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