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