]> git.pond.sub.org Git - empserver/blob - src/lib/commands/cons.c
Update copyright notice
[empserver] / src / lib / commands / cons.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2018, 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
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
40 struct ltcomstr {
41     int type;                   /* currently always EF_LOAN */
42     int num;                    /* number */
43     char *name;                 /* "loan" */
44     char *Name;                 /* "Loan" */
45     natid proposer;             /* country offering */
46     natid proposee;             /* country offered to */
47     natid mailee;               /* who gets mail about it */
48     char op;                    /* 'a', 'd', or 'p' */
49     union {
50         struct lonstr l;        /* the loan */
51     } u;
52 };
53
54 static int cons_choose(struct ltcomstr *ltcp);
55 static int cons_display(struct ltcomstr *ltcp);
56 static int cons_accept(struct ltcomstr *ltcp);
57 static int cons_decline(struct ltcomstr *ltcp);
58 static int cons_postpone(struct ltcomstr *ltcp);
59 static int loan_accept(struct ltcomstr *ltcp);
60 static int loan_decline(struct ltcomstr *ltcp);
61 static void accpt(struct ltcomstr *ltcp);
62 static void decline(struct ltcomstr *ltcp);
63 static void late(struct ltcomstr *ltcp);
64 static void prev_signed(struct ltcomstr *ltcp);
65
66 int
67 cons(void)
68 {
69     int rv;
70     struct ltcomstr ltc;
71
72     rv = cons_choose(&ltc);
73     if (rv != RET_OK)
74         return rv;
75
76     switch (ltc.op) {
77     case 'a':
78         return cons_accept(&ltc);
79     case 'd':
80         return cons_decline(&ltc);
81     case 'p':
82         return cons_postpone(&ltc);
83     default:
84         CANT_REACH();
85         return RET_SYN;
86     }
87 }
88
89 /*
90  * Choose whether we want to accept, decline, or postpone a
91  * loan.  Put all the goodies in ltcp, and return
92  * RET_OK if all goes well, and anything else on error.
93  */
94 static int
95 cons_choose(struct ltcomstr *ltcp)
96 {
97     static int lon_or_trt[] = { EF_LOAN, EF_BAD };
98     char *p;
99     struct lonstr *lp;
100     char prompt[128];
101     char buf[1024];
102
103     memset(ltcp, 0, sizeof(*ltcp));
104     p = player->argp[1] ? player->argp[1] : "loan";
105     ltcp->type = ef_byname_from(p, lon_or_trt);
106     switch (ltcp->type) {
107     case EF_LOAN:
108         if (!opt_LOANS) {
109             pr("Loans are not enabled.\n");
110             return RET_FAIL;
111         }
112         ltcp->name = "loan";
113         ltcp->Name = "Loan";
114         break;
115     default:
116         pr("You must specify \"loan\".\n");
117         return RET_SYN;
118     }
119     sprintf(prompt, "%s number? ", ltcp->Name);
120     if ((ltcp->num = onearg(player->argp[2], prompt)) < 0)
121         return RET_SYN;
122     if (!ef_read(ltcp->type, ltcp->num, &ltcp->u) || !cons_display(ltcp)) {
123         pr("%s #%d is not being offered to you!\n", ltcp->Name, ltcp->num);
124         return RET_SYN;
125     }
126     switch (ltcp->type) {
127     case EF_LOAN:
128         lp = &ltcp->u.l;
129         if (lp->l_status == LS_SIGNED) {
130             pr("That loan has already been accepted!\n");
131             return RET_FAIL;
132         }
133         ltcp->proposer = lp->l_loner;
134         ltcp->proposee = lp->l_lonee;
135         break;
136     }
137     ltcp->mailee = (ltcp->proposer == player->cnum)
138         ? ltcp->proposee : ltcp->proposer;
139     p = getstarg(player->argp[3], "Accept, decline or postpone? ", buf);
140     if (!p || (*p != 'a' && *p != 'd' && *p != 'p'))
141         return RET_SYN;
142     ltcp->op = *p;
143     return RET_OK;
144 }
145
146 static int
147 cons_display(struct ltcomstr *ltcp)
148 {
149     switch (ltcp->type) {
150     case EF_LOAN:
151         return disloan(ltcp->num, &ltcp->u.l);
152     default:
153         CANT_REACH();
154         return 0;
155     }
156 }
157
158 static int
159 cons_accept(struct ltcomstr *ltcp)
160 {
161     switch (ltcp->type) {
162     case EF_LOAN:
163         return loan_accept(ltcp);
164     default:
165         CANT_REACH();
166         return RET_FAIL;
167     }
168 }
169
170 static int
171 cons_decline(struct ltcomstr *ltcp)
172 {
173     switch (ltcp->type) {
174     case EF_LOAN:
175         return loan_decline(ltcp);
176     default:
177         CANT_REACH();
178         return RET_FAIL;
179     }
180 }
181
182 static int
183 cons_postpone(struct ltcomstr *ltcp)
184 {
185     pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
186     if (ltcp->proposee == player->cnum)
187         wu(0, ltcp->proposer, "%s %d considered by %s\n",
188            ltcp->name, ltcp->num, cname(player->cnum));
189     return RET_OK;
190 }
191
192 /*
193  * Accept a loan.  If the offering country has too little money,
194  * leave him $100 left and offer the rest.  Return RET_OK on
195  * success, anything else on error.
196  */
197 static int
198 loan_accept(struct ltcomstr *ltcp)
199 {
200     struct lonstr *lp;
201     struct natstr *lender;
202     struct nstr_item nstr;
203     struct lonstr loan;
204
205     lp = &ltcp->u.l;
206     if (ltcp->proposee != player->cnum) {
207         pr("%s %d is still pending.\n", ltcp->Name, ltcp->num);
208         return RET_OK;
209     }
210     if (!getloan(ltcp->num, lp)) {
211         logerror("loan_accept: can't read loan");
212         pr("can't read loan; get help!\n");
213         return RET_FAIL;
214     }
215     if (lp->l_status == LS_FREE) {      /* other guy retratcted already */
216         late(ltcp);
217         return RET_OK;
218     }
219     if (lp->l_status == LS_SIGNED) {    /* already signed somehow */
220         prev_signed(ltcp);
221         return RET_OK;
222     }
223     /* check to see if a loan already exists */
224     snxtitem_all(&nstr, EF_LOAN);
225     while (nxtitem(&nstr, &loan)) {
226         if (loan.l_status == LS_SIGNED && loan.l_lonee == lp->l_loner
227             && (loan.l_loner == lp->l_lonee)) {
228             pr("He already owes you money - make him repay his loan!\n");
229             return RET_OK;
230         }
231     }
232     lender = getnatp(ltcp->proposer);
233     if (lender->nat_money < lp->l_amtdue) {     /* other guy is poor */
234         lp->l_amtdue = lender->nat_money - 100;
235         pr("%s no longer has the funds.\n", cname(ltcp->proposer));
236         if (lp->l_amtdue <= 0)
237             return RET_FAIL;
238         pr("You may borrow $%d at the same terms.\n", lp->l_amtdue);
239     }
240     lender->nat_money -= lp->l_amtdue;
241     putnat(lender);
242     player->dolcost -= lp->l_amtdue;
243     lp->l_amtpaid = 0;
244     (void)time(&lp->l_lastpay);
245     lp->l_duedate = lp->l_ldur * SECS_PER_DAY + lp->l_lastpay;
246     lp->l_status = LS_SIGNED;
247     if (!putloan(ltcp->num, lp)) {
248         pr("Problem writing lp->to disk; get help!\n");
249         return RET_FAIL;
250     }
251     accpt(ltcp);
252     pr("You are now $%d richer (sort of).\n", lp->l_amtdue);
253     return RET_OK;
254 }
255
256 /*
257  * Decline a loan.  Return RET_OK on success, anything else on error.
258  */
259 static int
260 loan_decline(struct ltcomstr *ltcp)
261 {
262     struct lonstr *lp;
263
264     lp = &ltcp->u.l;
265     if (!getloan(ltcp->num, lp)) {
266         logerror("loan_decline: can't read loan");
267         pr("can't read loan; get help!\n");
268         return RET_FAIL;
269     }
270     /* loan got accepted somehow between now and last time we checked */
271     if (lp->l_status == LS_SIGNED) {
272         late(ltcp);
273         return RET_OK;
274     }
275     lp->l_status = LS_FREE;
276     if (!putloan(ltcp->num, lp)) {
277         logerror("loan_decline: can't write loan");
278         pr("can't write loan; get help!\n");
279         return RET_FAIL;
280     }
281     decline(ltcp);
282     return RET_OK;
283 }
284
285 /*
286  * Somebody tried to accept a loan that was retracted,
287  * or to decline a loan they already signed.
288  */
289 static void
290 late(struct ltcomstr *ltcp)
291 {
292     pr("Too late; that %s %s!\n", ltcp->name,
293        (ltcp->op == 'a') ? "is no longer being offered"
294        : "has already been accepted");
295 }
296
297 /*
298  * Loan was previously signed.
299  */
300 static void
301 prev_signed(struct ltcomstr *ltcp)
302 {
303     pr("%s #%d is already in effect.\n", ltcp->Name, ltcp->num);
304 }
305
306 /*
307  * Post-processing after successful declination of loan.
308  * Notify the folks involved.
309  */
310 static void
311 decline(struct ltcomstr *ltcp)
312 {
313     if (ltcp->proposee == player->cnum) {
314         wu(0, ltcp->proposer, "%s %d refused by %s\n",
315            ltcp->Name, ltcp->num, cname(player->cnum));
316         pr("%s %d refused.\n", ltcp->Name, ltcp->num);
317     } else {
318         wu(0, ltcp->proposee,
319            "%s offer %d retracted by %s\n",
320            ltcp->Name, ltcp->num, cname(player->cnum));
321         pr("%s offer %d retracted.\n", ltcp->Name, ltcp->num);
322     }
323 }
324
325 /*
326  * Post-processing after successful acceptance of loan.
327  * Notify the press, and the folks involved.
328  * (Weird spelling is to avoid accept(2)).
329  */
330 static void
331 accpt(struct ltcomstr *ltcp)
332 {
333     switch (ltcp->type) {
334     case EF_LOAN:
335         nreport(ltcp->proposer, N_MAKE_LOAN, player->cnum, 1);
336         break;
337     default:
338         CANT_REACH();
339     }
340     wu(0, ltcp->mailee, "%s #%d accepted by %s\n",
341        ltcp->Name, ltcp->num, cname(player->cnum));
342 }