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