]> git.pond.sub.org Git - empserver/blob - src/lib/commands/fuel.c
(fuel, load, shp_check_nav, retreat_ship1, 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-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 files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future 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 (shp_check_nav(&sect, &item.ship) == CN_LANDLOCKED) {
125                 pr("%s is landlocked and cannot be fueled.\n",
126                    prship(&item.ship));
127                 continue;
128             }
129
130             mp = &mchr[(int)item.ship.shp_type];
131
132             harbor = 0;
133             if (sect_has_dock(&sect)) {
134                 harbor = 1;
135                 oil_amt = sect.sct_item[I_OIL];
136                 pet_amt = sect.sct_item[I_PETROL];
137                 if ((oil_amt + pet_amt) == 0)
138                     harbor = 0;
139
140                 if (sect.sct_effic < 2) {
141                     pr("The harbor at %s is not 2%% efficient yet.\n",
142                        xyas(item.ship.shp_x,
143                             item.ship.shp_y, player->cnum));
144                     harbor = 0;
145                 }
146                 if ((sect.sct_own != player->cnum) && sect.sct_own)
147                     harbor = 0;
148             }
149
150             if ((mp->m_fuelu == 0) && (item.ship.shp_own == player->cnum)) {
151                 pr("%s does not use fuel!\n", prship(&item.ship));
152                 continue;
153             }
154
155             if (harbor) {
156                 ship_fuel = item.ship.shp_fuel;
157                 oil_amt = sect.sct_item[I_OIL];
158                 pet_amt = sect.sct_item[I_PETROL];
159                 max_amt = mp->m_fuelc - ship_fuel;
160
161                 if (max_amt == 0) {
162                     pr("%s already has a full fuel load.\n",
163                        prship(&item.ship));
164                     continue;
165                 }
166                 tot_fuel = (oil_amt * 50 + pet_amt * 5);
167                 if (tot_fuel == 0) {
168                     pr("No fuel in the harbor at %s!\n",
169                        xyas(sect.sct_x, sect.sct_y, player->cnum));
170                     continue;
171                 }
172                 move_amt = MIN(tot_fuel, fuel_amt);
173                 move_amt = MIN(move_amt, max_amt);
174
175                 if (move_amt == 0)
176                     continue;
177
178                 item.ship.shp_fuel += move_amt;
179
180                 fueled = 1;
181                 if ((pet_amt * 5) >= move_amt) {
182                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
183                     if (extra > 0.0)
184                         sect.sct_item[I_PETROL]
185                             = MAX((pet_amt - move_amt / 5) - 1, 0);
186                     else
187                         sect.sct_item[I_PETROL]
188                             = MAX((pet_amt - move_amt / 5), 0);
189                 } else {
190                     sect.sct_item[I_PETROL] = 0;
191                     move_amt -= pet_amt * 5;
192                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
193                     sect.sct_item[I_OIL] = MAX(oil_amt - move_amt / 50, 0);
194                     if (extra > 0.0)
195                         sect.sct_item[I_OIL]
196                             = MAX((oil_amt - move_amt / 50) - 1, 0);
197                     else
198                         sect.sct_item[I_OIL]
199                             = MAX((oil_amt - move_amt / 50), 0);
200                 }
201
202                 /* load plague */
203                 if (sect.sct_pstage == PLG_INFECT
204                     && item.ship.shp_pstage == PLG_HEALTHY)
205                     item.ship.shp_pstage = PLG_EXPOSED;
206
207                 putsect(&sect);
208                 putship(item.ship.shp_uid, &item.ship);
209             } else {            /* not in a harbor */
210                 if (!player->argp[4])
211                     pr("%s is not in a supplied, efficient harbor\n",
212                        prship(&item.ship));
213                 if (!snxtitem (&tender, EF_SHIP,
214                                getstarg(player->argp[4], "Oiler? ", buf)))
215                     continue;
216
217                 if (!check_ship_ok(&item.ship))
218                     continue;
219
220                 if (!nxtitem(&tender, &item2))
221                     continue;
222
223                 if (!(mchr[(int)item2.ship.shp_type].m_flags & M_OILER)) {
224                     pr("%s is not an oiler!\n", prship(&item2.ship));
225                     continue;
226                 }
227                 if (item2.ship.shp_own != player->cnum) {
228                     pr("You don't own that oiler!\n");
229                     continue;
230                 }
231
232                 if ((item2.ship.shp_x != item.ship.shp_x) ||
233                     (item2.ship.shp_y != item.ship.shp_y)) {
234                     pr("Not in the same sector!\n");
235                     continue;
236                 }
237                 ship_fuel = item.ship.shp_fuel;
238                 oil_amt = item2.ship.shp_item[I_OIL];
239                 pet_amt = item2.ship.shp_item[I_PETROL];
240                 max_amt = mp->m_fuelc - ship_fuel;
241
242                 if (max_amt == 0) {
243                     pr("%s already has a full fuel load.\n",
244                        prship(&item.ship));
245                     continue;
246                 }
247                 tot_fuel = oil_amt * 50 + pet_amt * 5;
248                 move_amt = MIN(tot_fuel, fuel_amt);
249                 move_amt = MIN(move_amt, max_amt);
250
251                 if (move_amt == 0)
252                     continue;
253
254                 item.ship.shp_fuel += move_amt;
255
256                 fueled = 1;
257                 if ((pet_amt * 5) >= move_amt) {
258                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
259                     if (extra > 0.0)
260                         item2.ship.shp_item[I_PETROL]
261                             = MAX((pet_amt - move_amt / 5) - 1, 0);
262                     else
263                         item2.ship.shp_item[I_PETROL]
264                             = MAX((pet_amt - move_amt / 5), 0);
265                 } else {
266                     item2.ship.shp_item[I_PETROL] = 0;
267                     move_amt -= pet_amt * 5;
268                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
269                     item2.ship.shp_item[I_OIL]
270                         = MAX(oil_amt - (move_amt / 50), 0);
271                     if (extra > 0.0)
272                         item2.ship.shp_item[I_OIL]
273                             = MAX((oil_amt - move_amt / 50) - 1, 0);
274                     else
275                         item2.ship.shp_item[I_OIL]
276                             = MAX((oil_amt - move_amt / 50), 0);
277                 }
278
279                 /* load plague */
280                 if (item2.ship.shp_pstage == PLG_INFECT
281                     && item.ship.shp_pstage == PLG_HEALTHY)
282                     item.ship.shp_pstage = PLG_EXPOSED;
283
284                 putship(item.ship.shp_uid, &item.ship);
285                 /* quick hack -KHS */
286                 if (item.ship.shp_uid == item2.ship.shp_uid)
287                     item2.ship.shp_fuel = item.ship.shp_fuel;
288                 putship(item2.ship.shp_uid, &item2.ship);
289             }
290             pr("%s", prship(&item.ship));
291         } else {
292             if (item.land.lnd_own != player->cnum)
293                 continue;
294
295             if (!getsect(item.land.lnd_x, item.land.lnd_y, &sect))
296                 continue;
297
298             if (!player->owner)
299                 continue;
300
301             lcp = &lchr[(int)item.land.lnd_type];
302
303             sector = 1;
304             oil_amt = sect.sct_item[I_OIL];
305             pet_amt = sect.sct_item[I_PETROL];
306
307             if ((oil_amt + pet_amt) == 0)
308                 sector = 0;
309
310             if ((item.land.lnd_fuelu == 0)
311                 && (item.land.lnd_own == player->cnum)) {
312                 pr("%s does not use fuel!\n", prland(&item.land));
313                 continue;
314             }
315
316             if (sector) {
317                 land_fuel = item.land.lnd_fuel;
318                 oil_amt = sect.sct_item[I_OIL];
319                 pet_amt = sect.sct_item[I_PETROL];
320                 max_amt = item.land.lnd_fuelc - land_fuel;
321
322                 if (max_amt == 0) {
323                     pr("%s already has a full fuel load.\n",
324                        prland(&item.land));
325                     continue;
326                 }
327                 tot_fuel = (oil_amt * 50 + pet_amt * 5);
328                 if (tot_fuel == 0) {
329                     pr("No fuel in the sector at %s!\n",
330                        xyas(sect.sct_x, sect.sct_y, player->cnum));
331                     continue;
332                 }
333                 move_amt = MIN(tot_fuel, fuel_amt);
334                 move_amt = MIN(move_amt, max_amt);
335
336                 if (move_amt == 0)
337                     continue;
338
339                 item.land.lnd_fuel += move_amt;
340
341                 fueled = 1;
342                 if ((pet_amt * 5) >= move_amt) {
343                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
344                     if (extra > 0.0)
345                         sect.sct_item[I_PETROL]
346                             = MAX((pet_amt - move_amt / 5) - 1, 0);
347                     else
348                         sect.sct_item[I_PETROL]
349                             = MAX((pet_amt - move_amt / 5), 0);
350                 } else {
351                     sect.sct_item[I_PETROL] = 0;
352                     move_amt -= pet_amt * 5;
353                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
354                     sect.sct_item[I_OIL] = MAX(oil_amt - move_amt / 50, 0);
355                     if (extra > 0.0)
356                         sect.sct_item[I_OIL]
357                             = MAX((oil_amt - move_amt / 50) - 1, 0);
358                     else
359                         sect.sct_item[I_OIL]
360                             = MAX((oil_amt - move_amt / 50), 0);
361                 }
362
363                 /* load plague */
364                 if (sect.sct_pstage == PLG_INFECT
365                     && item.land.lnd_pstage == PLG_HEALTHY)
366                     item.land.lnd_pstage = PLG_EXPOSED;
367
368                 putsect(&sect);
369                 putland(item.land.lnd_uid, &item.land);
370             } else {            /* not in a sector */
371                 if (!player->argp[4])
372                     pr("%s is not in a supplied sector\n",
373                        prland(&item.land));
374                 if (!snxtitem(&ltender, EF_LAND,
375                               getstarg(player->argp[4], "Supply unit? ",
376                                        buf)))
377                     continue;
378
379                 if (!check_land_ok(&item.land))
380                     continue;
381
382                 if (!nxtitem(&ltender, &item2))
383                     continue;
384
385                 if (!(lchr[(int)item2.land.lnd_type].l_flags & L_SUPPLY)) {
386                     pr("%s is not a supply unit!\n", prland(&item2.land));
387                     continue;
388                 }
389                 if (item2.land.lnd_own != player->cnum) {
390                     pr("You don't own that unit!\n");
391                     continue;
392                 }
393
394                 if ((item2.land.lnd_x != item.land.lnd_x) ||
395                     (item2.land.lnd_y != item.land.lnd_y)) {
396                     pr("Not in the same sector!\n");
397                     continue;
398                 }
399                 land_fuel = item.land.lnd_fuel;
400                 oil_amt = item2.land.lnd_item[I_OIL];
401                 pet_amt = item2.land.lnd_item[I_PETROL];
402                 max_amt = item.land.lnd_fuelc - land_fuel;
403
404                 if (max_amt == 0) {
405                     pr("%s already has a full fuel load.\n",
406                        prland(&item.land));
407                     continue;
408                 }
409                 tot_fuel = oil_amt * 50 + pet_amt * 5;
410                 move_amt = MIN(tot_fuel, fuel_amt);
411                 move_amt = MIN(move_amt, max_amt);
412
413                 if (move_amt == 0)
414                     continue;
415
416                 item.land.lnd_fuel += move_amt;
417
418                 fueled = 1;
419                 if ((pet_amt * 5) >= move_amt) {
420                     extra = ((float)move_amt / 5.0) - (move_amt / 5);
421                     if (extra > 0.0)
422                         item2.land.lnd_item[I_PETROL]
423                             = MAX((pet_amt - move_amt / 5) - 1, 0);
424                     else
425                         item2.land.lnd_item[I_PETROL]
426                             = MAX((pet_amt - move_amt / 5), 0);
427                 } else {
428                     item2.land.lnd_item[I_PETROL] = 0;
429                     move_amt -= pet_amt * 5;
430                     extra = ((float)move_amt / 50.0) - (move_amt / 50);
431                     item2.land.lnd_item[I_OIL]
432                         = MAX(oil_amt - move_amt / 50, 0);
433                     if (extra > 0.0)
434                         item2.land.lnd_item[I_OIL]
435                             = MAX((oil_amt - move_amt / 50) - 1, 0);
436                     else
437                         item2.land.lnd_item[I_OIL]
438                             = MAX((oil_amt - move_amt / 50), 0);
439                 }
440
441                 /* load plague */
442                 if (item2.land.lnd_pstage == PLG_INFECT
443                     && item.land.lnd_pstage == PLG_HEALTHY)
444                     item.land.lnd_pstage = PLG_EXPOSED;
445
446                 putland(item.land.lnd_uid, &item.land);
447                 /* quick hack -KHS */
448                 if (item2.land.lnd_uid == item.land.lnd_uid)
449                     item2.land.lnd_fuel = item.land.lnd_fuel;
450                 putland(item2.land.lnd_uid, &item2.land);
451             }
452             pr("%s", prland(&item.land));
453         }
454         if (fueled) {
455             pr(" takes on %d fuel in %s\n",
456                move_amt,
457                xyas(item.ship.shp_x, item.ship.shp_y, player->cnum));
458             if (player->cnum != item.ship.shp_own)
459                 wu(0, item.ship.shp_own,
460                    "%s takes on %d fuel in %s courtesy of %s\n",
461                    prship(&item.ship),
462                    move_amt,
463                    xyas(item.ship.shp_x, item.ship.shp_y,
464                         item.ship.shp_own), cname(player->cnum));
465         }
466     }
467     return RET_OK;
468 }