]> git.pond.sub.org Git - empserver/blob - src/lib/commands/expl.c
Update copyright notice
[empserver] / src / lib / commands / expl.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  expl.c: Take over unoccupied sectors
28  *
29  *  Known contributors to this file:
30  *     Jeff Wallace, 1989
31  */
32
33 #include <config.h>
34
35 #include "commands.h"
36 #include "game.h"
37 #include "item.h"
38 #include "map.h"
39 #include "optlist.h"
40 #include "plague.h"
41
42 static int explore_map(coord, coord, char *, char *);
43
44 int
45 explore(void)
46 {
47     int amount;
48     struct sctstr sect;
49     struct sctstr endsect;
50     struct sctstr start;
51     struct sctstr chksect;
52     double weight;
53     int mcost, dam;
54     int infected;
55     i_type vtype;
56     int amt_src;
57     int amt_dst;
58     struct ichrstr *ip;
59     int work;
60     int loyal;
61     int own, mob;
62     int justtook;
63     coord x, y;
64     char *p;
65     int n;
66     int left;
67     char buf[1024];
68     char prompt[128];
69
70     if (!(ip = whatitem(player->argp[1], "explore with what? (civ/mil) ")))
71         return RET_SYN;
72     vtype = ip->i_uid;
73     if ((vtype != I_CIVIL) && (vtype != I_MILIT)) {
74         pr("You can only explore with civs and mil.\n");
75         return RET_FAIL;
76     }
77     if (!(p = getstarg(player->argp[2], "from sector : ", buf)))
78         return RET_SYN;
79     if (!sarg_xy(p, &x, &y))
80         return RET_SYN;
81     if (!getsect(x, y, &sect) || !player->owner) {
82         pr("Not yours\n");
83         return RET_FAIL;
84     }
85     infected = sect.sct_pstage == PLG_INFECT;
86     if ((amt_src = sect.sct_item[vtype]) <= 0) {
87         pr("No %s in %s\n", ip->i_name,
88            xyas(sect.sct_x, sect.sct_y, player->cnum));
89         return RET_SYN;
90     }
91     own = sect.sct_own;
92     mob = sect.sct_mobil;
93     if (vtype == I_CIVIL && sect.sct_oldown != own) {
94         pr("You can't explore with conquered populace!\n");
95         return RET_SYN;
96     }
97     if (mob <= 0) {
98         pr("No mobility in %s\n",
99            xyas(sect.sct_x, sect.sct_y, player->cnum));
100         return RET_SYN;
101     }
102
103     /* only used when moving civs; but prevent spurious compiler warnings */
104     work = sect.sct_work;
105     loyal = sect.sct_loyal;
106     if (vtype == I_CIVIL && work != 100)
107         pr("Warning: civil unrest\n");
108
109     sprintf(prompt, "Number of %s to explore with? (max %d) ",
110             ip->i_name, amt_src);
111     amount = onearg(player->argp[3], prompt);
112     if (amount <= 0)
113         return RET_SYN;
114     if (!check_sect_ok(&sect))
115         return RET_FAIL;
116     if (amount > amt_src) {
117         amount = amt_src;
118         pr("Only exploring with %d.\n", amount);
119     }
120
121     if (!abandon_askyn(&sect, vtype, amount, NULL)) {
122         pr("Explore cancelled.\n");
123         return RET_FAIL;
124     }
125
126     if (!check_sect_ok(&sect))
127         return RET_FAIL;
128
129     weight = (double)amount * ip->i_lbs;
130     /* remove commodities from source sector */
131     getsect(x, y, &start);
132     amt_src = start.sct_item[vtype];
133     amt_src -= amount;
134     if (amt_src < 0) {
135         pr("%s in %s are gone!\n", ip->i_name,
136            xyas(start.sct_x, start.sct_y, player->cnum));
137         return RET_OK;
138     }
139     start.sct_item[vtype] = amt_src;
140     start.sct_flags |= MOVE_IN_PROGRESS;
141     putsect(&start);
142     /*
143      * Now parse the path and return ending sector.
144      */
145     dam = 1;
146     mcost = move_ground(&sect, &endsect, weight, player->argp[4],
147                         explore_map, 1, &dam);
148
149     if (dam) {
150         left = effdamage(amount, dam);
151         if (left < amount) {
152             if (left) {
153                 pr("%d of the %s you were exploring with were destroyed!\n"
154                    "Only %d %s made it to %s\n",
155                    amount - left, ip->i_name, left, ip->i_name,
156                    xyas(endsect.sct_x, endsect.sct_y, player->cnum));
157             } else {
158                 pr("All of the %s you were exploring with were destroyed!\n",
159                    ip->i_name);
160             }
161             amount = left;
162         }
163     }
164     if (mcost > 0)
165         pr("Total movement cost = %d", mcost);
166     else
167         pr("No mobility used");
168
169     if (mcost < 0) {
170         pr("\nExplore aborted");
171         getsect(start.sct_x, start.sct_y, &sect);
172         sect.sct_mobil = mob;
173     } else {
174         /* Charge mobility */
175         getsect(sect.sct_x, sect.sct_y, &sect);
176         n = sect.sct_mobil - mcost;
177         if (n < 0)
178             n = 0;
179         sect.sct_mobil = n;
180         pr(", %d mob left in %s", sect.sct_mobil,
181            xyas(sect.sct_x, sect.sct_y, player->cnum));
182         putsect(&sect);
183         getsect(endsect.sct_x, endsect.sct_y, &sect);
184     }
185     pr("\n");
186     justtook = 0;
187
188     /*
189      *      Check for a multitude of problems
190      */
191     getsect(endsect.sct_x, endsect.sct_y, &chksect);
192     if (amount <= 0) {
193         getsect(start.sct_x, start.sct_y, &start);
194         sect.sct_flags &= ~MOVE_IN_PROGRESS;
195         putsect(&sect);
196         return RET_FAIL;
197     }
198     if (chksect.sct_type == SCT_WATER) {
199         pr("Bridge disappeared!\n");
200         getsect(start.sct_x, start.sct_y, &start);
201         start.sct_flags &= ~MOVE_IN_PROGRESS;
202         putsect(&start);
203         return RET_FAIL;
204     }
205     if (!player->god && chksect.sct_own && chksect.sct_own != player->cnum
206         && chksect.sct_type != SCT_SANCT) {
207         pr("Somebody beat you there!\n");
208         /* Send them back home */
209         getsect(start.sct_x, start.sct_y, &sect);
210         if (sect.sct_own != own) {
211             pr("Someone captured the sector you started from!\n");
212             pr("Your exploring people die of disappointment!\n");
213             sect.sct_flags &= ~MOVE_IN_PROGRESS;
214             putsect(&sect);
215             return RET_FAIL;
216         }
217     }
218
219     if (!player->god && !player->owner && sect.sct_type != SCT_SANCT) {
220         takeover(&sect, player->cnum);
221         justtook = 1;
222         sect.sct_oldown = own;
223         sect.sct_work = 100;
224         sect.sct_loyal = 0;
225     }
226     if (vtype == I_CIVIL && sect.sct_oldown != player->cnum) {
227         pr("Your civilians don't want to stay!\n");
228         getsect(start.sct_x, start.sct_y, &sect);
229         if (sect.sct_own != own) {
230             pr("Someone captured the sector you started from!\n");
231             pr("Your exploring people die of disappointment!\n");
232             sect.sct_flags &= ~MOVE_IN_PROGRESS;
233             putsect(&sect);
234             return RET_FAIL;
235         }
236     }
237     amt_dst = sect.sct_item[vtype];
238     if (amount > ITEM_MAX - amt_dst) {
239         amount = ITEM_MAX - amt_dst;
240         pr("Only %d can be left there.\n", amount);
241         if (amount <= 0)
242             getsect(start.sct_x, start.sct_y, &sect);
243     }
244     sect.sct_item[vtype] = amount + amt_dst;
245     /*
246      * Now add commodities to destination sector,
247      * along with plague that came along for the ride.
248      * Takeover unowned sectors if not deity.
249      */
250     if (!player->god && sect.sct_type != SCT_SANCT && justtook) {
251         pr("Sector %s is now yours.\n",
252            xyas(sect.sct_x, sect.sct_y, player->cnum));
253         if (opt_MOB_ACCESS) {
254             game_tick_to_now(&sect.sct_access);
255             sect.sct_mobil = -(etu_per_update / sect_mob_neg_factor);
256         } else {
257             sect.sct_mobil = 0;
258         }
259     }
260     if (infected && sect.sct_pstage == PLG_HEALTHY)
261         sect.sct_pstage = PLG_EXPOSED;
262     if (vtype == I_CIVIL) {
263         sect.sct_loyal
264             = (amt_dst * sect.sct_loyal + amount * loyal) / (amt_dst + amount);
265         sect.sct_work
266             = (amt_dst * sect.sct_work + amount * work) / (amt_dst + amount);
267     }
268     putsect(&sect);
269     getsect(start.sct_x, start.sct_y, &start);
270     start.sct_flags &= ~MOVE_IN_PROGRESS;
271     putsect(&start);
272     return RET_OK;
273 }
274
275 /*ARGSUSED*/
276 static int
277 explore_map(coord curx, coord cury, char *arg1, char *arg2)
278 {
279     struct nstr_sect ns;
280     struct sctstr sect;
281     char view[7];
282     int i;
283     int changed = 0;
284
285     snxtsct_dist(&ns, curx, cury, 1);
286     i = 0;
287     while (i < 7 && nxtsct(&ns, &sect)) {
288         /* Nasty: this relies on the iteration order */
289         view[i] = dchr[sect.sct_type].d_mnem;
290         switch (sect.sct_type) {
291         case SCT_WATER:
292         case SCT_RURAL:
293         case SCT_MOUNT:
294         case SCT_WASTE:
295         case SCT_PLAINS:
296             break;
297         default:
298             if (sect.sct_own != player->cnum && !player->god)
299                 view[i] = '?';
300             break;
301         }
302         changed += map_set(player->cnum, ns.x, ns.y, view[i], 0);
303         i++;
304     }
305     if (changed)
306         writemap(player->cnum);
307     if (!getsect(curx, cury, &sect))
308         return RET_FAIL;
309     pr("    %c %c         min gold fert  oil uran\n", view[0], view[1]);
310     pr("   %c %c %c        %3d %4d %4d %4d %4d\n",
311        view[2], view[3], view[4],
312        sect.sct_min, sect.sct_gmin, sect.sct_fertil, sect.sct_oil,
313        sect.sct_uran);
314     pr("    %c %c\n", view[5], view[6]);
315     return RET_OK;
316 }