]> git.pond.sub.org Git - empserver/blob - src/lib/commands/buy.c
Import of Empire 4.2.12
[empserver] / src / lib / commands / buy.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  buy.c: Buy commodities from other nations
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Pat Loney, 1992
33  *     Steve McClure, 1996-2000
34  */
35
36 #include "misc.h"
37 #include "xy.h"
38 #include "file.h"
39 #include "var.h"
40 #include "sect.h"
41 #include "nat.h"
42 #include "news.h"
43 #include "nsc.h"
44 #include "item.h"
45 #include "deity.h"
46 #include "land.h"
47 #include "commodity.h"
48 #include "plane.h"
49 #include "nuke.h"
50 #include "ship.h"
51 #include "trade.h"
52 #include "player.h"
53 #include "loan.h"
54 #include "commands.h"
55 #include "optlist.h"
56
57 extern  int MARK_DELAY;
58
59 /*
60  * format: buy <COMMODITY>
61  *
62  */
63 int
64 buy(void)
65 {
66     struct sctstr sect;
67     struct natstr *natp;
68     struct comstr comm;
69     struct comstr ncomm;
70     struct comstr comt;
71     struct trdstr tmpt;
72     struct ichrstr *ip;
73     int qty;
74     int o, n, q;
75     coord       x, y;
76     char        *p;
77     float       bid;
78     time_t      now;
79     double      tally;
80     double      canspend;
81     extern      double  buytax;
82     extern      double  tradetax;
83     s_char  buf[1024];
84     
85     if (!opt_MARKET) {
86         pr("The market is disabled.\n");
87         return RET_FAIL;
88     }
89     natp = getnatp(player->cnum);
90     display_mark(player->argp[1]);
91     pr("\n");
92     p = getstarg(player->argp[2], "Which lot are you bidding on: ", buf);
93     if (p == 0)
94         return RET_SYN;
95     if (*p == 0)
96         return RET_SYN;
97     o = atoi(p);
98     if (o < 0)
99         return RET_SYN;
100     if(!getcomm(o, &comm) || comm.com_owner == 0){
101         pr("Invalid lot number.\n");
102         return RET_OK;
103     }
104     if (player->argp[1] && *(player->argp[1]) &&
105         comm.com_type != player->argp[1][0]) {
106         pr("That lot is not of the type you specified.\n");
107         return RET_OK;
108     }
109     if (comm.com_owner == player->cnum){
110         pr("You can't bid on your own lot.\n");
111         return RET_OK;
112     }
113     pr("WARNING!  This market issues credit.  If you make more\n");
114     pr("  bids than your treasury can cover at the time of sale,\n");
115     pr("  you can potentially go into financial ruin, and see no\n");
116     pr("  gains.  You have been warned.\n\n");
117     if ((p = getstarg(player->argp[3], "How much per unit: ",buf)) == 0)
118         return RET_SYN;
119     bid = atof(p);
120     if (bid <= 0)
121         return RET_FAIL;
122     if (natp->nat_money < (bid * comm.com_amount * buytax)) {
123         pr("This purchase would cost %.2f, %.2f more than you have.\n",
124            bid * comm.com_amount * buytax,
125            bid * comm.com_amount * buytax - natp->nat_money);
126         return RET_FAIL;
127     }
128 /*  check to see if all of the bids that this player has out plus this new bid
129     would make him go broke.  Ken, I ought to skin you alive for making me code
130     this part up.*/
131     tally = 0.0;
132     for (q = 0; gettrade(q, &tmpt); q++) {
133         if (tmpt.trd_maxbidder == player->cnum &&
134             tmpt.trd_unitid >= 0 &&
135             tmpt.trd_owner != player->cnum) {
136             tally += tmpt.trd_maxprice * tradetax;
137         }
138     }
139     for (q = 0; getcomm(q, &comt); q++) {
140         if (comt.com_maxbidder == player->cnum &&
141             comt.com_owner != 0 &&
142             comt.com_owner != player->cnum) {
143             tally += (comt.com_maxprice * comt.com_amount) * buytax;
144         }
145     }
146     canspend = natp->nat_money - tally;
147     getcomm(o, &comm);
148     if ((bid * comm.com_amount * buytax) > canspend) {
149         pr("You have overextended yourself in the market\n");
150         pr("You can not bid on the current items at that price.\n");
151         return RET_OK;
152     }
153     if (!(p = getstarg(player->argp[4], "destination sector : ", buf)))
154         return RET_SYN;
155     if (!sarg_xy(p, &x, &y))
156         return RET_SYN;
157     if (!getsect(x, y, &sect)) {
158         pr("Could not access sector");
159         return RET_FAIL;
160     }
161     if ((sect.sct_type != SCT_WAREH && sect.sct_type != SCT_HARBR) ||
162         sect.sct_own != player->cnum) {
163         pr("The destination sector is not one of your warehouses.\n");
164         return RET_FAIL;
165     }
166     if (sect.sct_effic < 60) {
167         pr("That sector is under construction.\n");
168         return RET_FAIL;
169     }
170     ip = whichitem(comm.com_type);
171     n = getvar(ip->i_vtype, (char *)&sect, EF_SECTOR);
172     qty = comm.com_amount;
173     if (qty + n > 9990) {
174         pr("That sector cannot hold %d more %s. It currently holds %d.\n",
175            qty, ip->i_name, n);
176         return RET_FAIL;
177     }
178     /* First we check for room, then we yank back.  Probably not necessary. */
179     if (putvar(ip->i_vtype, n + qty, (char *)&sect, EF_SECTOR) <= 0) {
180         pr("No room to store %s in %s\n",
181            ip->i_name, xyas(sect.sct_x, sect.sct_y, player->cnum));
182         return RET_FAIL;
183     }
184     if (putvar(ip->i_vtype, n, (char *)&sect, EF_SECTOR) <= 0) {
185         pr("Something weird just happened, tell the deity.\n");
186         logerror("buy.c: putvar failed.\n");
187         return RET_FAIL;
188     }
189     if ((bid * comm.com_amount) > natp->nat_money) {
190         pr("You don't have that much to spend!\n");
191         return RET_FAIL;
192     }
193     getcomm(o, &ncomm);
194     if (!ncomm.com_owner) {
195         pr("That lot has been taken off the market.\n");
196         return RET_FAIL;
197     }
198     if (bid > 0.04 + comm.com_maxprice){
199         comm.com_maxprice = bid;
200  /* Add five minutes to the time if less than 5 minutes */
201         time(&now);
202         if (((MARK_DELAY - (now - comm.com_markettime)) < 300) &&
203             comm.com_maxbidder != player->cnum) {
204           comm.com_markettime += 300;
205           /* Special case - what if so much time has gone by?  Well,
206              Just reset the markettime  so that only 5 minutes are left */
207           if ((MARK_DELAY - (now - comm.com_markettime)) < 0)
208             comm.com_markettime = (now - (MARK_DELAY - 300));
209         }
210         comm.com_maxbidder = player->cnum;
211         comm.com_x = x;
212         comm.com_y = y;
213         putcomm(o, &comm);
214         pr("Your bid is being considered.\n");
215     } else {
216         pr("Your bid wasn't high enough (you need to bid at least $0.05 higher\n");
217         pr("than the last bid.\n");
218         return RET_OK;
219     }
220     
221     check_market();
222
223     return RET_OK;
224 }
225
226 int
227 check_market(void)
228 {
229     extern      double  buytax;
230     struct comstr comm;
231     struct sctstr *sect;
232     struct ichrstr *ip;
233     struct natstr *natp;
234     int m;
235     int n;
236     time_t now;
237     double tmoney;
238     double tleft;
239     double subleft;
240     double monleft;
241     double gain;
242     double price;
243     struct lonstr loan;
244     long outstanding;  /* Outstanding debt */
245     long couval;  /* Value of country's goods */
246     int foundloan;
247     int j;
248
249 /*    logerror("Checking the market.\n");*/
250     for (n = 0; getcomm(n, &comm); n++) {
251         if (comm.com_maxbidder == comm.com_owner ||
252             comm.com_owner == 0)
253             continue;
254         (void)time(&now);
255         tleft = MARK_DELAY / 3600.0 - (now - comm.com_markettime) / 3600.0;
256         if (tleft < 0)
257             tleft = 0;
258         if (tleft > 0.0)
259             continue;
260         ip = whichitem(comm.com_type);
261         sect = getsectp(comm.com_x, comm.com_y);
262         m = getvar(ip->i_vtype, (char *)sect, EF_SECTOR);
263
264         monleft = 0;
265
266         price = comm.com_maxprice * comm.com_amount * buytax;
267         gain = comm.com_maxprice * comm.com_amount;
268
269         natp = getnatp(comm.com_maxbidder);
270         tmoney = natp->nat_money;
271         if (tmoney <= 0)
272           monleft = price;
273         if (tmoney < price && tmoney > 0) {
274             monleft = price - (tmoney - 1);
275             tmoney = 1;
276             price = price - monleft;
277         } else if (tmoney > 0) {
278             monleft = 0;
279             tmoney = tmoney - price;
280         }
281
282         /* Subtract the amount of money that needs to come out in a loan. */
283         subleft = monleft;
284
285         if (opt_LOANS) {
286             /* Try to make a loan for the rest from the owner. */
287             if (monleft > 0 && tmoney > 0) {
288                 if ((float)((float)price / (float)(price + monleft)) < 0.1) {
289                     wu(0, comm.com_maxbidder, "You need at least 10 percent down to purchase something on credit.\n");
290                 } else {
291                     couval = get_couval(comm.com_maxbidder);
292                     outstanding = get_outstand(comm.com_maxbidder);
293                     couval = couval - outstanding;
294                     if (couval > monleft) {
295                         /*  Make the loan */
296                         foundloan = 0;
297                         for (j = 0; getloan(j, &loan); j++) {
298                             if (loan.l_status != LS_FREE)
299                                 continue;
300                             foundloan = 1;
301                             break;
302                         }
303                         if (!foundloan)
304                             ef_extend(EF_LOAN, 1);
305                         loan.l_status = LS_SIGNED;
306                         loan.l_loner = comm.com_owner;
307                         loan.l_lonee = comm.com_maxbidder;
308                         loan.l_irate = 25;
309                         loan.l_ldur = 4;
310                         loan.l_amtpaid = 0;
311                         loan.l_amtdue = monleft;
312                         time(&loan.l_lastpay);
313                         loan.l_duedate = (loan.l_ldur * SECS_PER_DAY) + loan.l_lastpay;
314                         loan.l_uid = j;
315                         if (!putloan(j, &loan))
316                             logerror("Error writing to the loan file.\n");
317                         else
318                             monleft = 0;
319                         nreport(comm.com_maxbidder,N_FIN_TROUBLE, comm.com_owner, 1);
320                         wu(0, comm.com_maxbidder, "You just took loan #%d for $%.2f to cover the cost of your purchase.\n", j, loan.l_amtdue);
321                         wu(0, comm.com_owner, "You just extended loan #%d to %s to help with the purchase cose.\n", j, cname(comm.com_maxbidder));
322                     } else {
323                         nreport(comm.com_maxbidder,N_CREDIT_JUNK, comm.com_owner, 1);
324                         wu(0, comm.com_maxbidder, "You don't have enough credit to get a loan.\n");
325                         wu(0, comm.com_owner, "You just turned down a loan to %s.\n", cname(comm.com_maxbidder));
326                     }
327                 }
328             }
329         }
330         
331         if (monleft > 0) {
332             nreport(comm.com_maxbidder, N_WELCH_DEAL, comm.com_owner, 1);
333             wu(0, comm.com_maxbidder,
334                "You didn't have enough cash/credit to cover the cost.\n");
335             wu(0, comm.com_owner, 
336                "Sale #%d fell through.  Goods remain on the market.\n", n);
337             comm.com_maxbidder = comm.com_owner;
338         } else if (sect->sct_type != SCT_WAREH && sect->sct_type != SCT_HARBR) {
339             wu(0, comm.com_maxbidder, 
340                "Sector not a warehouse now, sale #%d fell though.\n", n);
341             wu(0, comm.com_owner, 
342                "Sale #%d fell through.  Goods remain on the market.\n", n);
343             comm.com_maxbidder = comm.com_owner;
344         } else if (putvar(ip->i_vtype, m + comm.com_amount,
345                           (char *)sect, EF_SECTOR) <= 0) {
346             wu(0, comm.com_maxbidder, 
347                "Warehouse full,  sale #%d fell though.\n", n);
348             wu(0, comm.com_owner, 
349                "Sale #%d fell through.  Goods remain on the market.\n", n);
350             comm.com_maxbidder = comm.com_owner;
351         } else {
352             putsect(sect);
353             nreport(comm.com_owner, N_MAKE_SALE, comm.com_maxbidder, 1);
354             wu(0, comm.com_owner, "%s bought %d %c's from you for $%.2f\n",
355                cname(comm.com_maxbidder), comm.com_amount, 
356                comm.com_type, gain);
357             wu(0, comm.com_maxbidder, "You just bought %d %c's from %s for $%.2f\n",
358                comm.com_amount, comm.com_type, cname(comm.com_owner),
359                gain * buytax);
360             natp=getnatp(comm.com_owner);
361             /* Make sure we subtract the amount that came out in a loan */
362             natp->nat_money += (gain - subleft);
363             natp=getnatp(comm.com_maxbidder);
364             natp->nat_money = tmoney;
365             comm.com_owner = 0;
366         }
367         comm.com_owner = 0;
368         putcomm(n, &comm);
369     }
370 /*    logerror("Done checking the market.\n");*/
371     return RET_OK;
372 }
373
374