]> git.pond.sub.org Git - empserver/blob - src/lib/player/player.c
4666d179ed7465ad20cc960623c775cb66471ac3
[empserver] / src / lib / player / player.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  player.c: Main command loop for a player
29  *
30  *  Known contributors to this file:
31  *     Steve McClure, 2000
32  *     Markus Armbruster, 2004-2008
33  *     Ron Koenderink, 2004-2007
34  */
35
36 #include <config.h>
37
38 #include "com.h"
39 #include "empio.h"
40 #include "empthread.h"
41 #include "file.h"
42 #include "journal.h"
43 #include "misc.h"
44 #include "nat.h"
45 #include "optlist.h"
46 #include "player.h"
47 #include "proto.h"
48 #include "prototypes.h"
49 #include "tel.h"
50
51
52 static int command(void);
53 static int status(void);
54
55 struct player *player;
56
57 void
58 player_main(struct player *p)
59 {
60     struct natstr *natp;
61     char buf[128];
62
63     p->state = PS_PLAYING;
64     player = p;
65     time(&player->curup);
66     update_timeused_login(player->curup);
67     show_motd();
68     if (init_nats() < 0) {
69         pr("Server confused, try again later\n");
70         return;
71     }
72     natp = getnatp(player->cnum);
73     if (!may_play_now(natp, player->curup, 0))
74         return;
75     if (natp->nat_stat != STAT_VIS
76         && natp->nat_last_login
77         && (strcmp(natp->nat_hostaddr, player->hostaddr)
78             || strcmp(natp->nat_userid, player->userid))) {
79         pr("Last connection from: %s", ctime(&natp->nat_last_login));
80         pr("                  to: %s",
81            natp->nat_last_login <= natp->nat_last_logout
82            ? ctime(&natp->nat_last_logout) : "?");
83         pr("                  by: %s@%s\n",
84            natp->nat_userid,
85            *natp->nat_hostname ? natp->nat_hostname : natp->nat_hostaddr);
86     }
87     strcpy(natp->nat_userid, player->userid);
88     strcpy(natp->nat_hostname, player->hostname);
89     strcpy(natp->nat_hostaddr, player->hostaddr);
90     natp->nat_last_login = player->curup;
91     putnat(natp);
92     journal_login();
93     if (natp->nat_flags & NF_INFORM && natp->nat_tgms > 0) {
94         if (natp->nat_tgms == 1)
95             pr("You have a new telegram waiting ...\n");
96         else
97             pr("You have %s new telegrams waiting ...\n",
98                numstr(buf, natp->nat_tgms));
99         natp->nat_tgms = 0;
100     }
101
102     while (status() && command()) {
103         player->aborted = player->eof;
104         empth_yield();
105     }
106     /* #*# I put the following line in to prevent server crash -KHS */
107     natp = getnatp(player->cnum);
108     time(&natp->nat_last_logout);
109     putnat(natp);
110     update_timeused(natp->nat_last_logout);
111     enforce_minimum_session_time();
112     pr("Bye-bye\n");
113     journal_logout();
114 }
115
116 static int
117 command(void)
118 {
119     char *redir;                /* UTF-8 */
120     char scanspace[1024];
121     time_t now;
122
123     if (getcommand(player->combuf) < 0)
124         return 0;
125
126     now = time(NULL);
127     update_timeused(now);
128     if (!may_play_now(getnatp(player->cnum), now, 1))
129         return 0;
130
131     if (parse(player->combuf, scanspace, player->argp, player->comtail,
132               &player->condarg, &redir) < 0) {
133         pr("See \"info Syntax\"?\n");
134     } else {
135         if (dispatch(player->combuf, redir) < 0)
136             pr("Try \"list of commands\" or \"info\"\n");
137     }
138     return 1;
139 }
140
141 static int
142 status(void)
143 {
144     struct natstr *natp;
145     int old_nstat;
146     char buf[128];
147
148     if (player->eof || player->state == PS_SHUTDOWN)
149         return 0;
150     natp = getnatp(player->cnum);
151     if (player->dolcost > 100.0)
152         pr("That just cost you $%.2f\n", player->dolcost);
153     else if (player->dolcost < -100.0)
154         pr("You just made $%.2f\n", -player->dolcost);
155     if (player->dolcost != 0.0) {
156         /*
157          * Hackish work around for a race condition in the nightly
158          * build's regression tests: sometimes the update starts right
159          * after the force command yields, sometimes a bit later.  If
160          * it is late, we use one random number here, for the bye,
161          * and throwing off the random sequence.
162          */
163         natp->nat_money -= roundavg(player->dolcost);
164         player->dolcost = 0.0;
165     }
166
167     old_nstat = player->nstat;
168     player_set_nstat(player, natp);
169     if ((old_nstat & MONEY) && !(player->nstat & MONEY))
170         pr("You are now broke; industries are on strike.\n");
171     if (!(old_nstat & MONEY) && (player->nstat & MONEY))
172         pr("You are no longer broke!\n");
173
174     time(&player->curup);
175     update_timeused(player->curup);
176     if (!may_play_now(natp, player->curup, 0))
177         return 0;
178     if (player->btused) {
179         natp->nat_btu -= player->btused;
180         player->btused = 0;
181     }
182     if (natp->nat_tgms > 0) {
183         if (!(natp->nat_flags & NF_INFORM)) {
184             if (natp->nat_tgms == 1)
185                 pr("You have a new telegram waiting ...\n");
186             else
187                 pr("You have %s new telegrams waiting ...\n",
188                    numstr(buf, natp->nat_tgms));
189             natp->nat_tgms = 0;
190         }
191     }
192     if (natp->nat_ann > 0) {
193         if (natp->nat_ann == 1)
194             pr("You have a new announcement waiting ...\n");
195         else
196             pr("You have %s new announcements waiting ...\n",
197                numstr(buf, natp->nat_ann));
198         natp->nat_ann = 0;
199     }
200     if (natp->nat_stat == STAT_ACTIVE && (player->nstat & CAP) == 0)
201         pr("You lost your capital... better designate one (see info capital)\n");
202     putnat(natp);
203     return 1;
204 }
205
206 /*
207  * XXX This whole mess should be redone; execute block should
208  * start with "exec start", and should end with "exec end".
209  * We'll wait until 1.2 I guess.
210  */
211 int
212 execute(void)
213 {
214     char buf[1024];
215     int failed;
216     char *p;
217     char *redir;                /* UTF-8 */
218     char scanspace[1024];
219
220     failed = 0;
221
222     if (player->comtail[1])
223         p = player->comtail[1];
224     else
225         p = getstring("File? ", buf);
226     if (p == NULL || *p == '\0')
227         return RET_SYN;
228     prexec(p);
229
230     while (!failed && status()) {
231         player->nstat &= ~EXEC;
232         if (recvclient(buf, sizeof(buf)) < 0)
233             break;
234         if (parse(buf, scanspace, player->argp, player->comtail,
235                   &player->condarg, &redir) < 0) {
236             failed = 1;
237             continue;
238         }
239         pr("\nExecute : %s\n", buf);
240         if (redir) {
241             pr("Execute : redirection not supported\n");
242             failed = 1;
243         } else if (dispatch(buf, NULL) < 0)
244             failed = 1;
245     }
246     if (failed) {
247         while (recvclient(buf, sizeof(buf)) >= 0) ;
248     }
249
250     pr("Execute : %s\n", failed ? "aborted" : "terminated");
251     player->eof = 0;
252     return RET_OK;
253 }
254
255 int
256 show_motd(void)
257 {
258     show_first_tel(motdfil);
259     return RET_OK;
260 }
261
262 int
263 quit(void)
264 {
265     player->state = PS_SHUTDOWN;
266     return RET_OK;
267 }
268
269 char *
270 praddr(struct player *p)
271 {
272     return prbuf("%s@%s", p->userid,
273                  *p->hostname ? p->hostname : p->hostaddr);
274 }