]> git.pond.sub.org Git - empserver/blob - src/lib/player/player.c
5f2719ed13628ccc9401f60c2758eb92997ff714
[empserver] / src / lib / player / player.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2013, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  player.c: Main command loop for a player
28  *
29  *  Known contributors to this file:
30  *     Steve McClure, 2000
31  *     Markus Armbruster, 2004-2012
32  *     Ron Koenderink, 2004-2009
33  */
34
35 #include <config.h>
36
37 #include "chance.h"
38 #include "empio.h"
39 #include "empthread.h"
40 #include "file.h"
41 #include "misc.h"
42 #include "nat.h"
43 #include "optlist.h"
44 #include "player.h"
45 #include "prototypes.h"
46
47
48 static int command(void);
49 static int status(void);
50
51 struct player *player;
52
53 void
54 player_main(struct player *p)
55 {
56     struct natstr *natp;
57     char buf[128];
58
59     player = p;
60     time(&player->curup);
61     update_timeused_login(player->curup);
62     show_motd();
63     if (init_nats() < 0) {
64         pr("Server confused, try again later\n");
65         return;
66     }
67     natp = getnatp(player->cnum);
68     if (!may_play_now(natp, player->curup))
69         return;
70     if (natp->nat_stat != STAT_VIS
71         && natp->nat_last_login
72         && (strcmp(natp->nat_hostaddr, player->hostaddr)
73             || strcmp(natp->nat_userid, player->userid))) {
74         pr("Last connection from: %s", ctime(&natp->nat_last_login));
75         pr("                  to: %s",
76            natp->nat_last_login <= natp->nat_last_logout
77            ? ctime(&natp->nat_last_logout) : "?");
78         pr("                  by: %s@%s\n",
79            natp->nat_userid,
80            *natp->nat_hostname ? natp->nat_hostname : natp->nat_hostaddr);
81     }
82     strcpy(natp->nat_userid, player->userid);
83     strcpy(natp->nat_hostname, player->hostname);
84     strcpy(natp->nat_hostaddr, player->hostaddr);
85     natp->nat_last_login = player->curup;
86     putnat(natp);
87     if (natp->nat_flags & NF_INFORM && natp->nat_tgms > 0) {
88         if (natp->nat_tgms == 1)
89             pr("You have a new telegram waiting ...\n");
90         else
91             pr("You have %s new telegrams waiting ...\n",
92                numstr(buf, natp->nat_tgms));
93         natp->nat_tgms = 0;
94     }
95
96     while (status() && command()) {
97         if (player->got_ctld)
98             io_set_eof(player->iop);
99         player->aborted = 0;
100         empth_yield();
101     }
102     /* #*# I put the following line in to prevent server crash -KHS */
103     natp = getnatp(player->cnum);
104     time(&natp->nat_last_logout);
105     putnat(natp);
106     update_timeused(natp->nat_last_logout);
107     enforce_minimum_session_time();
108     pr("Bye-bye\n");
109 }
110
111 static int
112 command(void)
113 {
114     struct natstr *natp = getnatp(player->cnum);
115     char *redir;                /* UTF-8 */
116     time_t now;
117
118     prprompt(natp->nat_timeused / 60, natp->nat_btu);
119     if (getcommand(player->combuf) < 0)
120         return player->aborted;
121
122     now = time(NULL);
123     update_timeused(now);
124     if (!player->god && !may_play_now(natp, now))
125         return 0;
126
127     if (parse(player->combuf, player->argbuf, player->argp,
128               player->comtail, &player->condarg, &redir) < 0) {
129         pr("See \"info Syntax\"?\n");
130     } else {
131         if (dispatch(player->combuf, redir) < 0)
132             pr("Try \"list of commands\" or \"info\"\n");
133     }
134     return 1;
135 }
136
137 static int
138 status(void)
139 {
140     struct natstr *natp;
141     int old_nstat;
142     char buf[128];
143
144     natp = getnatp(player->cnum);
145     if (player->dolcost > 100.0)
146         pr("That just cost you $%.2f\n", player->dolcost);
147     else if (player->dolcost < -100.0)
148         pr("You just made $%.2f\n", -player->dolcost);
149     if (player->dolcost != 0.0) {
150         /*
151          * Hackish work around for a race condition in the nightly
152          * build's regression tests: sometimes the update starts right
153          * after the force command yields, sometimes a bit later.  If
154          * it is late, we use one random number here, for the bye,
155          * and throwing off the random sequence.
156          */
157         natp->nat_money -= roundavg(player->dolcost);
158         player->dolcost = 0.0;
159     }
160
161     old_nstat = player->nstat;
162     player_set_nstat(player, natp);
163     if ((old_nstat & MONEY) && !(player->nstat & MONEY))
164         pr("You are now broke; industries are on strike.\n");
165     if (!(old_nstat & MONEY) && (player->nstat & MONEY))
166         pr("You are no longer broke!\n");
167
168     time(&player->curup);
169     update_timeused(player->curup);
170     if (io_error(player->iop) || io_eof(player->iop)
171         || !may_play_now(natp, player->curup))
172         return 0;
173
174     if (player->btused) {
175         natp->nat_btu -= player->btused;
176         player->btused = 0;
177     }
178     if (natp->nat_tgms > 0) {
179         if (!(natp->nat_flags & NF_INFORM)) {
180             if (natp->nat_tgms == 1)
181                 pr("You have a new telegram waiting ...\n");
182             else
183                 pr("You have %s new telegrams waiting ...\n",
184                    numstr(buf, natp->nat_tgms));
185             natp->nat_tgms = 0;
186         }
187     }
188     if (natp->nat_ann > 0) {
189         if (natp->nat_ann == 1)
190             pr("You have a new announcement waiting ...\n");
191         else
192             pr("You have %s new announcements waiting ...\n",
193                numstr(buf, natp->nat_ann));
194         natp->nat_ann = 0;
195     }
196     if (natp->nat_stat == STAT_ACTIVE && (player->nstat & CAP) == 0)
197         pr("You lost your capital... better designate one (see info capital)\n");
198     putnat(natp);
199     return 1;
200 }
201
202 /*
203  * Make all objects stale if ARG is one of the player's command arguments.
204  * See ef_make_stale() for what "making stale" means.
205  * Useful for functions that prompt for missing arguments.
206  * These can yield the processor, so we'd like to call ef_make_stale()
207  * there.  Except that leads to false positives when the caller passes
208  * an argument that is never null, and relies on the fact that the
209  * function doesn't yield then.  We can't know that in general.  But
210  * we do know in the common special case of command arguments.
211  */
212 void
213 make_stale_if_command_arg(char *arg)
214 {
215     if (player->argbuf <= arg
216         && arg <= player->argbuf + sizeof(player->argbuf))
217         ef_make_stale();
218 }
219
220 /*
221  * XXX This whole mess should be redone; execute block should
222  * start with "exec start", and should end with "exec end".
223  * We'll wait until 1.2 I guess.
224  */
225 int
226 execute(void)
227 {
228     char buf[1024];             /* UTF-8 */
229     int failed;
230     char *p;                    /* UTF-8 */
231     char *redir;                /* UTF-8 */
232
233     failed = 0;
234
235     p = player->comtail[1];
236     if (!p)
237         p = ugetstring("File? ", buf);
238     if (p == NULL || *p == '\0')
239         return RET_SYN;
240     prexec(p);
241
242     while (!failed && status() && !player->got_ctld) {
243         player->nstat &= ~EXEC;
244         if (getcommand(player->combuf) < 0)
245             break;
246         if (parse(player->combuf, player->argbuf, player->argp,
247                   player->comtail, &player->condarg, &redir) < 0) {
248             failed = 1;
249             continue;
250         }
251         pr("\nExecute : ");
252         uprnf(player->combuf);
253         pr("\n");
254         if (redir) {
255             pr("Execute : redirection not supported\n");
256             failed = 1;
257         } else if (dispatch(player->combuf, NULL) < 0)
258             failed = 1;
259         /* player->aborted not reset; makes next getcommand() fail */
260         empth_yield();
261     }
262     if (failed) {
263         while (recvclient(buf, sizeof(buf)) >= 0) ;
264     }
265
266     pr("Execute : %s\n", failed ? "aborted" : "terminated");
267     player->got_ctld = 0;
268     return RET_OK;
269 }
270
271 int
272 show_motd(void)
273 {
274     show_first_tel(motdfil);
275     return RET_OK;
276 }
277
278 int
279 quit(void)
280 {
281     io_set_eof(player->iop);
282     return RET_OK;
283 }
284
285 char *
286 praddr(struct player *p)
287 {
288     return prbuf("%s@%s", p->userid,
289                  *p->hostname ? p->hostname : p->hostaddr);
290 }