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