]> git.pond.sub.org Git - empserver/blob - src/lib/commands/cons.c
04cd21ca50c3fb65570f777f55b555adc204713b
[empserver] / src / lib / commands / cons.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  *  cons.c: Consider a loan or treaty
29  *
30  *  Known contributors to this file:
31  *
32  */
33
34 #include <config.h>
35
36 #include "commands.h"
37 #include "loan.h"
38 #include "news.h"
39 #include "optlist.h"
40 #include "treaty.h"
41
42 /*
43  * Things common to a loan or treaty.
44  */
45 struct ltcomstr {
46     int type;                   /* EF_LOAN or EF_TREATY */
47     int num;                    /* number */
48     char *name;                 /* "loan" or "treaty" */
49     char *Name;                 /* "Loan" or "Treaty" */
50     natid proposer;             /* country offering */
51     natid proposee;             /* country offered to */
52     natid mailee;               /* who gets mail about it */
53     char op;                    /* 'a', 'd', or 'p' */
54     union {
55         struct lonstr l;        /* the loan */
56         struct trtstr t;        /* the treaty */
57     } u;
58 };
59
60 static int cons_choose(struct ltcomstr *ltcp);
61 static int treaty_accept(struct ltcomstr *ltcp);
62 static int treaty_decline(struct ltcomstr *ltcp);
63 static int loan_accept(struct ltcomstr *ltcp);
64 static int loan_decline(struct ltcomstr *ltcp);
65 static int postpone(struct ltcomstr *ltcp);
66 static void accpt(struct ltcomstr *ltcp);
67 static void decline(struct ltcomstr *ltcp);
68 static void late(struct ltcomstr *ltcp);
69 static void prev_signed(struct ltcomstr *ltcp);
70
71 int
72 cons(void)
73 {
74     int rv;
75     struct ltcomstr ltc;
76
77     rv = cons_choose(&ltc);
78     if (rv != RET_OK)
79         return rv;
80
81     switch (ltc.op) {
82     case 'a':
83         rv = (ltc.type == EF_TREATY) ? treaty_accept(&ltc)
84             : loan_accept(&ltc);
85         break;
86     case 'd':
87         rv = (ltc.type == EF_TREATY) ? treaty_decline(&ltc)
88             : loan_decline(&ltc);
89         break;
90     case 'p':
91         rv = postpone(&ltc);
92         break;
93     default:
94         pr("Bad operation %c from cons_choose; get help!\n", ltc.op);
95         break;
96     };
97
98     return rv;
99 }
100
101 /*
102  * Choose whether we want to accept, decline, or postpone a
103  * loan or treaty.  Put all the goodies in ltcp, and return
104  * RET_OK if all goes well, and anything else on error.
105  */
106 static int
107 cons_choose(struct ltcomstr *ltcp)
108 {
109     static int lon_or_trt[] = { EF_LOAN, EF_TREATY, EF_BAD };
110     char *p;
111     struct lonstr *lp;
112     struct trtstr *tp;
113     char prompt[128];
114     char buf[1024];
115
116     memset(ltcp, 0, sizeof(*ltcp));
117     if (!getstarg(player->argp[1], "loan or treaty? ", buf))
118         return RET_SYN;
119     ltcp->type = ef_byname_from(buf, lon_or_trt);
120     switch (ltcp->type) {
121     case EF_TREATY:
122         if (!opt_TREATIES) {
123             pr("Treaties are not enabled.\n");
124             return RET_FAIL;
125         }
126         ltcp->name = "treaty";
127         ltcp->Name = "Treaty";
128         break;
129     case EF_LOAN:
130         if (!opt_LOANS) {
131             pr("Loans are not enabled.\n");
132             return RET_FAIL;
133         }
134         ltcp->name = "loan";
135         ltcp->Name = "Loan";
136         break;
137     default:
138         pr("You must specify \"loan\" or \"treaty\".\n");
139         return RET_SYN;
140     }
141     sprintf(prompt, "%s number? ", ltcp->Name);
142     if ((ltcp->num = onearg(player->argp[2], prompt)) < 0)
143         return RET_SYN;
144     if (!ef_read(ltcp->type, ltcp->num, &ltcp->u) ||
145         !(ltcp->type == EF_TREATY
146           ? distrea(ltcp->num, &ltcp->u.t)
147           : disloan(ltcp->num, &ltcp->u.l))) {
148         pr("%s #%d is not being offered to you!\n", ltcp->Name, ltcp->num);
149         return RET_SYN;
150     }
151     switch (ltcp->type) {
152     case EF_LOAN:
153         lp = &ltcp->u.l;
154         if (lp->l_status == LS_SIGNED) {
155             pr("That loan has already been accepted!\n");
156             return RET_FAIL;
157         }
158         ltcp->proposer = lp->l_loner;
159         ltcp->proposee = lp->l_lonee;
160         break;
161     case EF_TREATY:
162         tp = &ltcp->u.t;
163         if (tp->trt_status == TS_SIGNED) {
164             pr("That treaty has already been accepted!\n");
165             return RET_FAIL;
166         }
167         ltcp->proposer = tp->trt_cna;
168         ltcp->proposee = tp->trt_cnb;
169         break;
170     }
171     ltcp->mailee = (ltcp->proposer == player->cnum)
172         ? ltcp->proposee : ltcp->proposer;
173     p = getstarg(player->argp[3], "Accept, decline or postpone? ", buf);
174     if (!p || (*p != 'a' && *p != 'd' && *p != 'p'))
175         return RET_SYN;
176     ltcp->op = *p;
177     return RET_OK;
178 }
179
180 /*
181  * Accept a loan.  If the offering country has too little money,
182  * leave him $100 left and offer the rest.  Return RET_OK on
183  * success, anything else on error.
184  */
185 static int
186 loan_accept(struct ltcomstr *ltcp)
187 {
188     struct lonstr *lp;
189     struct natstr *lender;
190     struct nstr_item nstr;
191     struct lonstr loan;
192
193     lp = &ltcp->u.l;
194     if (ltcp->proposee != player->cnum) {
195         pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
196         return RET_OK;
197     }
198     if (!getloan(ltcp->num, lp)) {
199         logerror("loan_accept: can't read loan");
200         pr("can't read loan; get help!\n");
201         return RET_FAIL;
202     }
203     if (lp->l_status == LS_FREE) {      /* other guy retratcted already */
204         late(ltcp);
205         return RET_OK;
206     }
207     if (lp->l_status == LS_SIGNED) {    /* already signed somehow */
208         prev_signed(ltcp);
209         return RET_OK;
210     }
211     /* check to see if a loan already exists */
212     snxtitem_all(&nstr, EF_LOAN);
213     while (nxtitem(&nstr, &loan)) {
214         if (loan.l_status == LS_SIGNED && loan.l_lonee == lp->l_loner
215             && (loan.l_loner == lp->l_lonee)) {
216             pr("He already owes you money - make him repay his loan!\n");
217             return RET_OK;
218         }
219     }
220     lender = getnatp(ltcp->proposer);
221     if (lender->nat_money < lp->l_amtdue) {     /* other guy is poor */
222         lp->l_amtdue = lender->nat_money - 100;
223         pr("%s no longer has the funds.\n", cname(ltcp->proposer));
224         if (lp->l_amtdue <= 0)
225             return RET_FAIL;
226         pr("You may borrow $%ld at the same terms.\n", lp->l_amtdue);
227     }
228     lender->nat_money -= lp->l_amtdue;
229     putnat(lender);
230     player->dolcost -= lp->l_amtdue;
231     lp->l_amtpaid = 0;
232     (void)time(&lp->l_lastpay);
233     lp->l_duedate = lp->l_ldur * 86400 + lp->l_lastpay;
234     lp->l_status = LS_SIGNED;
235     if (!putloan(ltcp->num, lp)) {
236         pr("Problem writing lp->to disk; get help!\n");
237         return RET_FAIL;
238     }
239     accpt(ltcp);
240     pr("You are now $%ld richer (sort of).\n", lp->l_amtdue);
241     return RET_OK;
242 }
243
244 /*
245  * Declne a loan.  Return RET_OK on success, anything else on error.
246  */
247 static int
248 loan_decline(struct ltcomstr *ltcp)
249 {
250     struct lonstr *lp;
251
252     lp = &ltcp->u.l;
253     if (!getloan(ltcp->num, lp)) {
254         logerror("loan_decline: can't read loan");
255         pr("can't read loan; get help!\n");
256         return RET_FAIL;
257     }
258     /* loan got accepted somehow between now and last time we checked */
259     if (lp->l_status == LS_SIGNED) {
260         late(ltcp);
261         return RET_OK;
262     }
263     lp->l_status = LS_FREE;
264     if (!putloan(ltcp->num, lp)) {
265         logerror("loan_decline: can't write loan");
266         pr("can't write loan; get help!\n");
267         return RET_FAIL;
268     }
269     decline(ltcp);
270     return RET_OK;
271 }
272
273 /*
274  * Accept a treaty.  Return RET_OK on success, anything else on error.
275  */
276 static int
277 treaty_accept(struct ltcomstr *ltcp)
278 {
279     struct trtstr *tp;
280
281     tp = &ltcp->u.t;
282     if (ltcp->proposee != player->cnum) {
283         pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
284         return RET_OK;
285     }
286     if (!gettre(ltcp->num, tp)) {
287         pr("treaty_accept: can't read treaty");
288         pr("can't read treaty; get help!\n");
289         return RET_FAIL;
290     }
291     if (tp->trt_status == TS_FREE) {    /* treaty offer withdrawn */
292         late(ltcp);
293         return RET_OK;
294     }
295     if (tp->trt_status == TS_SIGNED) {  /* somehow got accepted */
296         prev_signed(ltcp);
297         return RET_OK;
298     }
299     tp->trt_status = TS_SIGNED;
300     if (!puttre(ltcp->num, tp)) {
301         pr("treaty_accept: can't write treaty");
302         pr("Problem saving treaty; get help!\n");
303         return RET_FAIL;
304     }
305     accpt(ltcp);
306     pr("Treaty in effect until %s", ctime(&tp->trt_exp));
307     return RET_OK;
308 }
309
310 /*
311  * Decline a treaty.  Return RET_OK on success, anything else on error.
312  */
313 static int
314 treaty_decline(struct ltcomstr *ltcp)
315 {
316     struct trtstr *tp;
317
318     tp = &ltcp->u.t;
319     if (!gettre(ltcp->num, tp)) {
320         logerror("treaty_decline: can't read treaty");
321         pr("can't read treaty; get help!\n");
322         return RET_FAIL;
323     }
324     /* treaty got signed somehow between now and last time we read it */
325     if (tp->trt_status == TS_SIGNED) {
326         late(ltcp);
327         return RET_OK;
328     }
329     tp->trt_status = TS_FREE;
330     if (!puttre(ltcp->num, tp)) {
331         logerror("treaty_decline: can't write treaty");
332         pr("Problem saving treaty; get help!\n");
333         return RET_FAIL;
334     }
335     decline(ltcp);
336     return RET_OK;
337 }
338
339 /*
340  * Postpone a treaty; always succeeds.
341  */
342 static int
343 postpone(struct ltcomstr *ltcp)
344 {
345     pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
346     if (ltcp->proposee == player->cnum)
347         wu(0, ltcp->proposer, "%s %d considered by %s\n",
348            ltcp->name, ltcp->num, cname(player->cnum));
349     return RET_OK;
350 }
351
352 /*
353  * Somebody tried to accept a loan/treaty that was retracted,
354  * or to decline a loan/treaty they already signed.
355  */
356 static void
357 late(struct ltcomstr *ltcp)
358 {
359     pr("Too late; that %s %s!\n", ltcp->name,
360        (ltcp->op == 'a') ? "is no longer being offered"
361        : "has already been accepted");
362 }
363
364 /*
365  * Loan or treaty was previously signed.
366  */
367 static void
368 prev_signed(struct ltcomstr *ltcp)
369 {
370     pr("%s #%d is already in effect.\n", ltcp->Name, ltcp->num);
371 }
372
373 /*
374  * Post-processing after successful declination of loan or treaty.
375  * Notify the folks involved.
376  */
377 static void
378 decline(struct ltcomstr *ltcp)
379 {
380     if (ltcp->proposee == player->cnum) {
381         wu(0, ltcp->proposer, "%s %d refused by %s\n",
382            ltcp->Name, ltcp->num, cname(player->cnum));
383         pr("%s %d refused.\n", ltcp->Name, ltcp->num);
384     } else {
385         wu(0, ltcp->proposee,
386            "%s offer %d retracted by %s\n",
387            ltcp->Name, ltcp->num, cname(player->cnum));
388         pr("%s offer %d retracted.\n", ltcp->Name, ltcp->num);
389     }
390 }
391
392 /*
393  * Post-processing after successful acceptance of loan or treaty.
394  * Notify the press, and the folks involved.
395  * (Weird spelling is to avoid accept(2)).
396  */
397 static void
398 accpt(struct ltcomstr *ltcp)
399 {
400     if (ltcp->type == EF_LOAN)
401         nreport(ltcp->proposer, N_MAKE_LOAN, player->cnum, 1);
402     else
403         nreport(player->cnum, N_SIGN_TRE, ltcp->mailee, 1);
404     wu(0, ltcp->mailee, "%s #%d accepted by %s\n",
405        ltcp->Name, ltcp->num, cname(player->cnum));
406 }