]> git.pond.sub.org Git - empserver/blob - src/lib/commands/fuel.c
Update copyright notice.
[empserver] / src / lib / commands / fuel.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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  *  fuel.c: fuel ships/land units
29  * 
30  *  Known contributors to this file:
31  *     
32  */
33
34 #include "misc.h"
35 #include "player.h"
36 #include "var.h"
37 #include "xy.h"
38 #include "ship.h"
39 #include "plane.h"
40 #include "land.h"
41 #include "nat.h"
42 #include "nsc.h"
43 #include "file.h"
44 #include "sect.h"
45 #include "optlist.h"
46 #include "commands.h"
47
48
49 union item_u {
50     struct shpstr ship;
51     struct lndstr land;
52 };
53
54 int
55 fuel(void)
56 {
57     struct nstr_item ni;
58     union item_u item, item2;
59     int type;
60     struct mchrstr *mp;
61     struct lchrstr *lcp;
62     s_char *p;
63     int fueled;
64     int land_fuel, ship_fuel;
65     int oil_amt, pet_amt, fuel_amt, tot_fuel, max_amt;
66     int move_amt;
67     float extra;
68     struct sctstr sect;
69     struct natstr *natp;
70     int harbor, sector;
71     int fuelled_ship = -1;
72     struct nstr_item tender, ltender;
73     s_char prompt[128];
74     s_char buf[1024];
75
76     if (opt_FUEL == 0) {
77         pr("Option 'FUEL' not enabled\n");
78         return RET_SYN;
79     }
80     if ((p =
81          getstarg(player->argp[1], "Ship or land unit (s,l)? ", buf)) == 0)
82         return RET_SYN;
83     type = ef_byname(p);
84     if (type == EF_SECTOR)
85         type = EF_SHIP;
86     if (type != EF_SHIP && type != EF_LAND) {
87         pr("Ships or land units only! (s, l)\n");
88         return RET_SYN;
89     }
90     sprintf(prompt, "%s(s)? ", ef_nameof(type));
91     p = getstarg(player->argp[2], prompt, buf);
92     if (!snxtitem(&ni, type, p))
93         return RET_SYN;
94     if (isdigit(*p))
95         fuelled_ship = atoi(p);
96     p = getstarg(player->argp[3], "Amount: ", buf);
97     if (p == 0 || *p == 0)
98         return RET_SYN;
99     fuel_amt = atoi(p);
100     if (fuel_amt <= 0) {
101         pr("Fuel amount must be positive!\n");
102         return RET_FAIL;
103     }
104
105     ni.flags &= ~(EFF_OWNER);
106
107     while (nxtitem(&ni, (s_char *)&item)) {
108         fueled = 0;
109         if (type == EF_SHIP) {
110             if (item.ship.shp_own != player->cnum) {
111                 int rel;
112
113                 if (item.ship.shp_uid != fuelled_ship)
114                     continue;
115                 natp = getnatp(player->cnum);
116                 rel = getrel(natp, item.ship.shp_own);
117                 if (rel < FRIENDLY)
118                     continue;
119             }
120             if (!getsect(item.ship.shp_x, item.ship.shp_y, &sect))
121                 continue;
122             if (!item.ship.shp_own)
123                 continue;
124
125             if ((sect.sct_type != SCT_HARBR)
126                 && (sect.sct_type != SCT_WATER)
127                 && (sect.sct_type != SCT_BSPAN) && (!opt_BIG_CITY
128                                                     || sect.sct_type !=
129                                                     SCT_CAPIT)) {
130                 pr("Sector %s is not a harbor, bridge span, or sea.\n",
131                    xyas(item.ship.shp_x, item.ship.shp_y,
132                         item.ship.shp_own));
133                 continue;
134             }
135
136             mp = &mchr[(int)item.ship.shp_type];
137
138             harbor = 0;
139             if (sect.sct_type == SCT_HARBR
140                 || (opt_BIG_CITY && sect.sct_type == SCT_CAPIT)) {
141                 harbor = 1;
142                 oil_amt = sect.sct_item[I_OIL];
143                 pet_amt = sect.sct_item[I_PETROL];
144                 if ((oil_amt + pet_amt) == 0)
145                     harbor = 0;
146
147                 if (sect.sct_effic < 2) {
148                     pr("The harbor at %s is not 2%% efficient yet.\n",
149                        xyas(item.ship.shp_x,
150                             item.ship.shp_y, player->cnum));
151                     harbor = 0;
152                 }
153                 if ((sect.sct_own != player->cnum) && sect.sct_own)
154                     harbor = 0;
155             }
156
157             if ((mp->m_fuelu == 0) && (item.ship.shp_own == player->cnum)) {
158                 pr("%s does not use fuel!\n", prship(&item.ship));
159                 continue;
160             }
161
162             if (harbor) {
163                 ship_fuel = item.ship.shp_fuel;
164                 oil_amt = sect.sct_item[I_OIL];
165                 pet_amt = sect.sct_item[I_PETROL];
166                 max_amt = mp->m_fuelc - ship_fuel;
167
168                 if (max_amt == 0) {
169                     pr("%s already has a full fuel load.\n",
170                        prship(&item.ship));
171                     continue;
172                 }
173                 tot_fuel = (oil_amt * 50 + pet_amt * 5);
174                 if (tot_fuel == 0) {
175                     pr("No fuel in the harbor at %s!\n",
176                        xyas(sect.sct_x, sect.sct_y, player->cnum));
177                     continue;
178                 }
179                 move_amt = min(tot_fuel, fuel_amt);
180                 move_amt = min(move_amt, max_amt);
181
182                 if (move_amt == 0)
183                     continue;
184
185                 item.ship.shp_fuel += move_amt;
186
187                 fueled = 1;
188                 if ((pet_amt * 5) >= move_amt) {
189                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
190                     if (extra > 0.0)
191                         sect.sct_item[I_PETROL]
192                             = max((pet_amt - move_amt / 5) - 1, 0);
193                     else
194                         sect.sct_item[I_PETROL]
195                             = max((pet_amt - move_amt / 5), 0);
196                 } else {
197                     sect.sct_item[I_PETROL] = 0;
198                     move_amt -= pet_amt * 5;
199                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
200                     sect.sct_item[I_OIL] = max(oil_amt - move_amt / 50, 0);
201                     if (extra > 0.0)
202                         sect.sct_item[I_OIL]
203                             = max((oil_amt - move_amt / 50) - 1, 0);
204                     else
205                         sect.sct_item[I_OIL]
206                             = max((oil_amt - move_amt / 50), 0);
207                 }
208
209                 /* load plague */
210                 if (sect.sct_pstage == PLG_INFECT
211                     && item.ship.shp_pstage == PLG_HEALTHY)
212                     item.ship.shp_pstage = PLG_EXPOSED;
213
214                 putsect(&sect);
215                 putship(item.ship.shp_uid, &item.ship);
216             } else {            /* not in a harbor */
217                 if (!player->argp[4])
218                     pr("%s is not in a supplied, efficient harbor\n",
219                        prship(&item.ship));
220                 if (!snxtitem (&tender, EF_SHIP,
221                                getstarg(player->argp[4], "Oiler? ", buf)))
222                     continue;
223
224                 if (!check_ship_ok(&item.ship))
225                     continue;
226
227                 if (!nxtitem(&tender, (s_char *)&item2))
228                     continue;
229
230                 if (!(mchr[(int)item2.ship.shp_type].m_flags & M_OILER)) {
231                     pr("%s is not an oiler!\n", prship(&item2.ship));
232                     continue;
233                 }
234                 if (item2.ship.shp_own != player->cnum) {
235                     pr("You don't own that oiler!\n");
236                     continue;
237                 }
238
239                 if ((item2.ship.shp_x != item.ship.shp_x) ||
240                     (item2.ship.shp_y != item.ship.shp_y)) {
241                     pr("Not in the same sector!\n");
242                     continue;
243                 }
244                 ship_fuel = item.ship.shp_fuel;
245                 oil_amt = item2.ship.shp_item[I_OIL];
246                 pet_amt = item2.ship.shp_item[I_PETROL];
247                 max_amt = mp->m_fuelc - ship_fuel;
248
249                 if (max_amt == 0) {
250                     pr("%s already has a full fuel load.\n",
251                        prship(&item.ship));
252                     continue;
253                 }
254                 tot_fuel = oil_amt * 50 + pet_amt * 5;
255                 move_amt = min(tot_fuel, fuel_amt);
256                 move_amt = min(move_amt, max_amt);
257
258                 if (move_amt == 0)
259                     continue;
260
261                 item.ship.shp_fuel += move_amt;
262
263                 fueled = 1;
264                 if ((pet_amt * 5) >= move_amt) {
265                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
266                     if (extra > 0.0)
267                         item2.ship.shp_item[I_PETROL]
268                             = max((pet_amt - move_amt / 5) - 1, 0);
269                     else
270                         item2.ship.shp_item[I_PETROL]
271                             = max((pet_amt - move_amt / 5), 0);
272                 } else {
273                     item2.ship.shp_item[I_PETROL] = 0;
274                     move_amt -= pet_amt * 5;
275                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
276                     item2.ship.shp_item[I_OIL]
277                         = max(oil_amt - (move_amt / 50), 0);
278                     if (extra > 0.0)
279                         item2.ship.shp_item[I_OIL]
280                             = max((oil_amt - move_amt / 50) - 1, 0);
281                     else
282                         item2.ship.shp_item[I_OIL]
283                             = max((oil_amt - move_amt / 50), 0);
284                 }
285
286                 /* load plague */
287                 if (item2.ship.shp_pstage == PLG_INFECT
288                     && item.ship.shp_pstage == PLG_HEALTHY)
289                     item.ship.shp_pstage = PLG_EXPOSED;
290
291                 putship(item.ship.shp_uid, &item.ship);
292                 /* quick hack -KHS */
293                 if (item.ship.shp_uid == item2.ship.shp_uid)
294                     item2.ship.shp_fuel = item.ship.shp_fuel;
295                 putship(item2.ship.shp_uid, &item2.ship);
296             }
297             pr("%s", prship(&item.ship));
298         } else {
299             if (item.land.lnd_own != player->cnum)
300                 continue;
301
302             if (!getsect(item.land.lnd_x, item.land.lnd_y, &sect))
303                 continue;
304
305             if (!player->owner)
306                 continue;
307
308             lcp = &lchr[(int)item.land.lnd_type];
309
310             sector = 1;
311             oil_amt = sect.sct_item[I_OIL];
312             pet_amt = sect.sct_item[I_PETROL];
313
314             if ((oil_amt + pet_amt) == 0)
315                 sector = 0;
316
317             if ((item.land.lnd_fuelu == 0)
318                 && (item.land.lnd_own == player->cnum)) {
319                 pr("%s does not use fuel!\n", prland(&item.land));
320                 continue;
321             }
322
323             if (sector) {
324                 land_fuel = item.land.lnd_fuel;
325                 oil_amt = sect.sct_item[I_OIL];
326                 pet_amt = sect.sct_item[I_PETROL];
327                 max_amt = item.land.lnd_fuelc - land_fuel;
328
329                 if (max_amt == 0) {
330                     pr("%s already has a full fuel load.\n",
331                        prland(&item.land));
332                     continue;
333                 }
334                 tot_fuel = (oil_amt * 50 + pet_amt * 5);
335                 if (tot_fuel == 0) {
336                     pr("No fuel in the sector at %s!\n",
337                        xyas(sect.sct_x, sect.sct_y, player->cnum));
338                     continue;
339                 }
340                 move_amt = min(tot_fuel, fuel_amt);
341                 move_amt = min(move_amt, max_amt);
342
343                 if (move_amt == 0)
344                     continue;
345
346                 item.land.lnd_fuel += move_amt;
347
348                 fueled = 1;
349                 if ((pet_amt * 5) >= move_amt) {
350                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
351                     if (extra > 0.0)
352                         sect.sct_item[I_PETROL]
353                             = max((pet_amt - move_amt / 5) - 1, 0);
354                     else
355                         sect.sct_item[I_PETROL]
356                             = max((pet_amt - move_amt / 5), 0);
357                 } else {
358                     sect.sct_item[I_PETROL] = 0;
359                     move_amt -= pet_amt * 5;
360                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
361                     sect.sct_item[I_OIL] = max(oil_amt - move_amt / 50, 0);
362                     if (extra > 0.0)
363                         sect.sct_item[I_OIL]
364                             = max((oil_amt - move_amt / 50) - 1, 0);
365                     else
366                         sect.sct_item[I_OIL]
367                             = max((oil_amt - move_amt / 50), 0);
368                 }
369
370                 /* load plague */
371                 if (sect.sct_pstage == PLG_INFECT
372                     && item.land.lnd_pstage == PLG_HEALTHY)
373                     item.land.lnd_pstage = PLG_EXPOSED;
374
375                 putsect(&sect);
376                 putland(item.land.lnd_uid, &item.land);
377             } else {            /* not in a sector */
378                 if (!player->argp[4])
379                     pr("%s is not in a supplied sector\n",
380                        prland(&item.land));
381                 if (!snxtitem(&ltender, EF_LAND,
382                               getstarg(player->argp[4], "Supply unit? ",
383                                        buf)))
384                     continue;
385
386                 if (!check_land_ok(&item.land))
387                     continue;
388
389                 if (!nxtitem(&ltender, (s_char *)&item2))
390                     continue;
391
392                 if (!(lchr[(int)item2.land.lnd_type].l_flags & L_SUPPLY)) {
393                     pr("%s is not a supply unit!\n", prland(&item2.land));
394                     continue;
395                 }
396                 if (item2.land.lnd_own != player->cnum) {
397                     pr("You don't own that unit!\n");
398                     continue;
399                 }
400
401                 if ((item2.land.lnd_x != item.land.lnd_x) ||
402                     (item2.land.lnd_y != item.land.lnd_y)) {
403                     pr("Not in the same sector!\n");
404                     continue;
405                 }
406                 land_fuel = item.land.lnd_fuel;
407                 oil_amt = item2.land.lnd_item[I_OIL];
408                 pet_amt = item2.land.lnd_item[I_PETROL];
409                 max_amt = item.land.lnd_fuelc - land_fuel;
410
411                 if (max_amt == 0) {
412                     pr("%s already has a full fuel load.\n",
413                        prland(&item.land));
414                     continue;
415                 }
416                 tot_fuel = oil_amt * 50 + pet_amt * 5;
417                 move_amt = min(tot_fuel, fuel_amt);
418                 move_amt = min(move_amt, max_amt);
419
420                 if (move_amt == 0)
421                     continue;
422
423                 item.land.lnd_fuel += move_amt;
424
425                 fueled = 1;
426                 if ((pet_amt * 5) >= move_amt) {
427                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
428                     if (extra > 0.0)
429                         item2.land.lnd_item[I_PETROL]
430                             = max((pet_amt - move_amt / 5) - 1, 0);
431                     else
432                         item2.land.lnd_item[I_PETROL]
433                             = max((pet_amt - move_amt / 5), 0);
434                 } else {
435                     item2.land.lnd_item[I_PETROL] = 0;
436                     move_amt -= pet_amt * 5;
437                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
438                     item2.land.lnd_item[I_OIL]
439                         = max(oil_amt - move_amt / 50, 0);
440                     if (extra > 0.0)
441                         item2.land.lnd_item[I_OIL]
442                             = max((oil_amt - move_amt / 50) - 1, 0);
443                     else
444                         item2.land.lnd_item[I_OIL]
445                             = max((oil_amt - move_amt / 50), 0);
446                 }
447
448                 /* load plague */
449                 if (item2.land.lnd_pstage == PLG_INFECT
450                     && item.land.lnd_pstage == PLG_HEALTHY)
451                     item.land.lnd_pstage = PLG_EXPOSED;
452
453                 putland(item.land.lnd_uid, &item.land);
454                 /* quick hack -KHS */
455                 if (item2.land.lnd_uid == item.land.lnd_uid)
456                     item2.land.lnd_fuel = item.land.lnd_fuel;
457                 putland(item2.land.lnd_uid, &item2.land);
458             }
459             pr("%s", prland(&item.land));
460         }
461         if (fueled) {
462             pr(" takes on %d fuel in %s\n",
463                move_amt,
464                xyas(item.ship.shp_x, item.ship.shp_y, player->cnum));
465             if (player->cnum != item.ship.shp_own)
466                 wu(0, item.ship.shp_own,
467                    "%s takes on %d fuel in %s courtesy of %s\n",
468                    prship(&item.ship),
469                    move_amt,
470                    xyas(item.ship.shp_x, item.ship.shp_y,
471                         item.ship.shp_own), cname(player->cnum));
472         }
473     }
474     return RET_OK;
475 }