]> git.pond.sub.org Git - empserver/blob - src/lib/commands/buil.c
fcd2b5e2e8670b6fafd321e9b048db58dae809ef
[empserver] / src / lib / commands / buil.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2013, 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  *  buil.c: Build ships, nukes, bridges, planes, land units, bridge towers
28  *
29  *  Known contributors to this file:
30  *     Steve McClure, 1998-2000
31  *     Markus Armbruster, 2004-2013
32  */
33
34 #include <config.h>
35
36 #include <limits.h>
37 #include "chance.h"
38 #include "commands.h"
39 #include "game.h"
40 #include "land.h"
41 #include "lost.h"
42 #include "map.h"
43 #include "nuke.h"
44 #include "optlist.h"
45 #include "path.h"
46 #include "plague.h"
47 #include "plane.h"
48 #include "ship.h"
49 #include "treaty.h"
50 #include "unit.h"
51
52 static int build_ship(struct sctstr *sp, int type, int tlev);
53 static int build_land(struct sctstr *sp, int type, int tlev);
54 static int build_nuke(struct sctstr *sp, int type, int tlev);
55 static int build_plane(struct sctstr *sp, int type, int tlev);
56 static int pick_unused_unit_uid(int);
57 static int build_bridge(char);
58 static int build_bspan(struct sctstr *sp);
59 static int build_btower(struct sctstr *sp);
60 static int build_can_afford(double, char *);
61
62 /*
63  * build <WHAT> <SECTS> <TYPE|DIR|MEG> [NUMBER]
64  */
65 int
66 buil(void)
67 {
68     struct natstr *natp = getnatp(player->cnum);
69     int tlev = (int)natp->nat_level[NAT_TLEV];
70     struct sctstr sect;
71     struct nstr_sect nstr;
72     int rqtech, type, number, val, gotsect;
73     char *p, *what, *prompt;
74     int (*build_it)(struct sctstr *, int, int);
75     char buf[1024];
76
77     p = getstarg(player->argp[1],
78                  "Build (ship, nuke, bridge, plane, land unit, tower)? ",
79                  buf);
80     if (!p)
81         return RET_SYN;
82     switch (*p) {
83     case 'b':
84     case 't':
85         return build_bridge(*p);
86     case 's':
87         what = "ship";
88         prompt = "Ship type? ";
89         build_it = build_ship;
90         break;
91     case 'p':
92         what = "plane";
93         prompt = "Plane type? ";
94         build_it = build_plane;
95         break;
96     case 'l':
97         what = "land";
98         prompt = "Land unit type? ";
99         build_it = build_land;
100         break;
101     case 'n':
102         if (!ef_nelem(EF_NUKE_CHR)) {
103             pr("There are no nukes in this game.\n");
104             return RET_FAIL;
105         }
106         if (drnuke_const > MIN_DRNUKE_CONST)
107             tlev = MIN(tlev,
108                        (int)(natp->nat_level[NAT_RLEV] / drnuke_const));
109         what = "nuke";
110         prompt = "Nuke type? ";
111         build_it = build_nuke;
112         break;
113     default:
114         pr("You can't build that!\n");
115         return RET_SYN;
116     }
117
118     if (!snxtsct(&nstr, player->argp[2]))
119         return RET_SYN;
120
121     p = getstarg(player->argp[3], prompt, buf);
122     if (!p || !*p)
123         return RET_SYN;
124
125     rqtech = 0;
126     switch (*what) {
127     case 'p':
128         type = ef_elt_byname(EF_PLANE_CHR, p);
129         if (type >= 0)
130             rqtech = plchr[type].pl_tech;
131         break;
132     case 's':
133         type = ef_elt_byname(EF_SHIP_CHR, p);
134         if (type >= 0)
135             rqtech = mchr[type].m_tech;
136         break;
137     case 'l':
138         type = ef_elt_byname(EF_LAND_CHR, p);
139         if (type >= 0)
140             rqtech = lchr[type].l_tech;
141         break;
142     case 'n':
143         type = ef_elt_byname(EF_NUKE_CHR, p);
144         if (type >= 0)
145             rqtech = nchr[type].n_tech;
146         break;
147     default:
148         CANT_REACH();
149         return RET_FAIL;
150     }
151
152     if (type < 0 || tlev < rqtech) {
153         pr("You can't build that!\n");
154         pr("Use `show %s build %d' to show types you can build.\n",
155            what, tlev);
156         return RET_FAIL;
157     }
158
159     number = 1;
160     if (player->argp[4]) {
161         number = atoi(player->argp[4]);
162         if (number > 20) {
163             char bstr[80];
164             sprintf(bstr,
165                     "Are you sure that you want to build %d of them? ",
166                     number);
167             p = getstarg(player->argp[6], bstr, buf);
168             if (!p || *p != 'y')
169                 return RET_SYN;
170         }
171     }
172
173     if (player->argp[5]) {
174         val = atoi(player->argp[5]);
175         if (val > tlev && !player->god) {
176             pr("Your%s tech level is only %d.\n",
177                *what == 'n' && drnuke_const > MIN_DRNUKE_CONST
178                ? " effective" : "", tlev);
179             return RET_FAIL;
180         }
181         if (rqtech > val) {
182             pr("Required tech is %d.\n", rqtech);
183             return RET_FAIL;
184         }
185         tlev = val;
186         pr("Building with tech level %d.\n", tlev);
187     }
188
189     gotsect = 0;
190     while (number-- > 0) {
191         while (nxtsct(&nstr, &sect)) {
192             if (!player->owner)
193                 continue;
194             gotsect = 1;
195             if (build_it(&sect, type, tlev))
196                 putsect(&sect);
197         }
198         snxtsct_rewind(&nstr);
199     }
200     if (!gotsect)
201         pr("No sectors.\n");
202     return RET_OK;
203 }
204
205 static int
206 build_ship(struct sctstr *sp, int type, int tlev)
207 {
208     short *vec = sp->sct_item;
209     struct mchrstr *mp = &mchr[type];
210     struct shpstr ship;
211     int avail;
212     double cost;
213     double eff = SHIP_MINEFF / 100.0;
214     int lcm, hcm;
215
216     hcm = roundavg(mp->m_hcm * eff);
217     lcm = roundavg(mp->m_lcm * eff);
218
219     if (sp->sct_type != SCT_HARBR) {
220         pr("Ships must be built in harbours.\n");
221         return 0;
222     }
223     if (sp->sct_effic < 60 && !player->god) {
224         pr("Sector %s is not 60%% efficient.\n",
225            xyas(sp->sct_x, sp->sct_y, player->cnum));
226         return 0;
227     }
228     if (vec[I_LCM] < lcm || vec[I_HCM] < hcm) {
229         pr("Not enough materials in %s\n",
230            xyas(sp->sct_x, sp->sct_y, player->cnum));
231         return 0;
232     }
233     avail = (SHP_BLD_WORK(mp->m_lcm, mp->m_hcm) * SHIP_MINEFF + 99) / 100;
234     if (sp->sct_avail < avail) {
235         pr("Not enough available work in %s to build a %s\n",
236            xyas(sp->sct_x, sp->sct_y, player->cnum), mp->m_name);
237         pr(" (%d available work required)\n", avail);
238         return 0;
239     }
240     cost = mp->m_cost * SHIP_MINEFF / 100.0;
241     if (!build_can_afford(cost, mp->m_name))
242         return 0;
243     if (!trechk(player->cnum, 0, NEWSHP))
244         return 0;
245     if (!check_sect_ok(sp))
246         return 0;
247     sp->sct_avail -= avail;
248     player->dolcost += cost;
249     ef_blank(EF_SHIP, pick_unused_unit_uid(EF_SHIP), &ship);
250     ship.shp_x = sp->sct_x;
251     ship.shp_y = sp->sct_y;
252     ship.shp_own = sp->sct_own;
253     ship.shp_type = mp - mchr;
254     ship.shp_effic = SHIP_MINEFF;
255     if (opt_MOB_ACCESS) {
256         game_tick_to_now(&ship.shp_access);
257         ship.shp_mobil = -(etu_per_update / sect_mob_neg_factor);
258     } else {
259         ship.shp_mobil = 0;
260     }
261     memset(ship.shp_item, 0, sizeof(ship.shp_item));
262     ship.shp_pstage = PLG_HEALTHY;
263     ship.shp_ptime = 0;
264     ship.shp_name[0] = 0;
265     ship.shp_orig_own = sp->sct_own;
266     ship.shp_orig_x = sp->sct_x;
267     ship.shp_orig_y = sp->sct_y;
268     shp_set_tech(&ship, tlev);
269     unit_wipe_orders((struct empobj *)&ship);
270
271     vec[I_LCM] -= lcm;
272     vec[I_HCM] -= hcm;
273
274     if (sp->sct_pstage == PLG_INFECT)
275         ship.shp_pstage = PLG_EXPOSED;
276     putship(ship.shp_uid, &ship);
277     pr("%s", prship(&ship));
278     pr(" built in sector %s\n", xyas(sp->sct_x, sp->sct_y, player->cnum));
279     return 1;
280 }
281
282 static int
283 build_land(struct sctstr *sp, int type, int tlev)
284 {
285     short *vec = sp->sct_item;
286     struct lchrstr *lp = &lchr[type];
287     struct lndstr land;
288     int avail;
289     double cost;
290     double eff = LAND_MINEFF / 100.0;
291     int mil, lcm, hcm, gun, shell;
292
293 #if 0
294     mil = roundavg(lp->l_mil * eff);
295     shell = roundavg(lp->l_shell * eff);
296     gun = roundavg(lp->l_gun * eff);
297 #else
298     mil = shell = gun = 0;
299 #endif
300     hcm = roundavg(lp->l_hcm * eff);
301     lcm = roundavg(lp->l_lcm * eff);
302
303     if (sp->sct_type != SCT_HEADQ) {
304         pr("Land units must be built in headquarters.\n");
305         return 0;
306     }
307     if (sp->sct_effic < 60 && !player->god) {
308         pr("Sector %s is not 60%% efficient.\n",
309            xyas(sp->sct_x, sp->sct_y, player->cnum));
310         return 0;
311     }
312     if (vec[I_LCM] < lcm || vec[I_HCM] < hcm) {
313         pr("Not enough materials in %s\n",
314            xyas(sp->sct_x, sp->sct_y, player->cnum));
315         return 0;
316     }
317 #if 0
318     if (vec[I_GUN] < gun || vec[I_GUN] == 0) {
319         pr("Not enough guns in %s\n",
320            xyas(sp->sct_x, sp->sct_y, player->cnum));
321         return 0;
322     }
323     if (vec[I_SHELL] < shell) {
324         pr("Not enough shells in %s\n",
325            xyas(sp->sct_x, sp->sct_y, player->cnum));
326         return 0;
327     }
328     if (vec[I_MILIT] < mil) {
329         pr("Not enough military in %s\n",
330            xyas(sp->sct_x, sp->sct_y, player->cnum));
331         return 0;
332     }
333 #endif
334     if (!trechk(player->cnum, 0, NEWLND))
335         return 0;
336     if (!check_sect_ok(sp))
337         return 0;
338     avail = (LND_BLD_WORK(lp->l_lcm, lp->l_hcm) * LAND_MINEFF + 99) / 100;
339     if (sp->sct_avail < avail) {
340         pr("Not enough available work in %s to build a %s\n",
341            xyas(sp->sct_x, sp->sct_y, player->cnum), lp->l_name);
342         pr(" (%d available work required)\n", avail);
343         return 0;
344     }
345     cost = lp->l_cost * LAND_MINEFF / 100.0;
346     if (!build_can_afford(cost, lp->l_name))
347         return 0;
348     sp->sct_avail -= avail;
349     player->dolcost += cost;
350     ef_blank(EF_LAND, pick_unused_unit_uid(EF_LAND), &land);
351     land.lnd_x = sp->sct_x;
352     land.lnd_y = sp->sct_y;
353     land.lnd_own = sp->sct_own;
354     land.lnd_type = lp - lchr;
355     land.lnd_effic = LAND_MINEFF;
356     if (opt_MOB_ACCESS) {
357         game_tick_to_now(&land.lnd_access);
358         land.lnd_mobil = -(etu_per_update / sect_mob_neg_factor);
359     } else {
360         land.lnd_mobil = 0;
361     }
362     land.lnd_ship = -1;
363     land.lnd_land = -1;
364     land.lnd_harden = 0;
365     memset(land.lnd_item, 0, sizeof(land.lnd_item));
366     land.lnd_pstage = PLG_HEALTHY;
367     land.lnd_ptime = 0;
368     lnd_set_tech(&land, tlev);
369     unit_wipe_orders((struct empobj *)&land);
370
371     vec[I_LCM] -= lcm;
372     vec[I_HCM] -= hcm;
373     vec[I_MILIT] -= mil;
374     vec[I_GUN] -= gun;
375     vec[I_SHELL] -= shell;
376
377     if (sp->sct_pstage == PLG_INFECT)
378         land.lnd_pstage = PLG_EXPOSED;
379     putland(land.lnd_uid, &land);
380     pr("%s", prland(&land));
381     pr(" built in sector %s\n", xyas(sp->sct_x, sp->sct_y, player->cnum));
382     return 1;
383 }
384
385 static int
386 build_nuke(struct sctstr *sp, int type, int tlev)
387 {
388     short *vec = sp->sct_item;
389     struct nchrstr *np = &nchr[type];
390     struct nukstr nuke;
391     int avail;
392
393     if (sp->sct_type != SCT_NUKE && !player->god) {
394         pr("Nuclear weapons must be built in nuclear plants.\n");
395         return 0;
396     }
397     if (sp->sct_effic < 60 && !player->god) {
398         pr("Sector %s is not 60%% efficient.\n",
399            xyas(sp->sct_x, sp->sct_y, player->cnum));
400         return 0;
401     }
402     if (vec[I_HCM] < np->n_hcm || vec[I_LCM] < np->n_lcm ||
403         vec[I_OIL] < np->n_oil || vec[I_RAD] < np->n_rad) {
404         pr("Not enough materials for a %s bomb in %s\n",
405            np->n_name, xyas(sp->sct_x, sp->sct_y, player->cnum));
406         pr("(%d hcm, %d lcm, %d oil, & %d rads).\n",
407            np->n_hcm, np->n_lcm, np->n_oil, np->n_rad);
408         return 0;
409     }
410     if (!build_can_afford(np->n_cost, np->n_name))
411         return 0;
412     avail = NUK_BLD_WORK(np->n_lcm, np->n_hcm, np->n_oil, np->n_rad);
413     /*
414      * XXX when nukes turn into units (or whatever), then
415      * make them start at 20%.  Since they don't have efficiency
416      * now, we charge all the work right away.
417      */
418     if (sp->sct_avail < avail) {
419         pr("Not enough available work in %s to build a %s;\n",
420            xyas(sp->sct_x, sp->sct_y, player->cnum), np->n_name);
421         pr(" (%d available work required)\n", avail);
422         return 0;
423     }
424     if (!trechk(player->cnum, 0, NEWNUK))
425         return 0;
426     if (!check_sect_ok(sp))
427         return 0;
428     sp->sct_avail -= avail;
429     player->dolcost += np->n_cost;
430     ef_blank(EF_NUKE, pick_unused_unit_uid(EF_NUKE), &nuke);
431     nuke.nuk_x = sp->sct_x;
432     nuke.nuk_y = sp->sct_y;
433     nuke.nuk_own = sp->sct_own;
434     nuke.nuk_type = np - nchr;
435     nuke.nuk_effic = 100;
436     nuke.nuk_plane = -1;
437     nuke.nuk_tech = tlev;
438     unit_wipe_orders((struct empobj *)&nuke);
439
440     vec[I_HCM] -= np->n_hcm;
441     vec[I_LCM] -= np->n_lcm;
442     vec[I_OIL] -= np->n_oil;
443     vec[I_RAD] -= np->n_rad;
444
445     putnuke(nuke.nuk_uid, &nuke);
446     pr("%s created in %s\n", prnuke(&nuke),
447        xyas(sp->sct_x, sp->sct_y, player->cnum));
448     return 1;
449 }
450
451 static int
452 build_plane(struct sctstr *sp, int type, int tlev)
453 {
454     short *vec = sp->sct_item;
455     struct plchrstr *pp = &plchr[type];
456     struct plnstr plane;
457     int avail;
458     double cost;
459     double eff = PLANE_MINEFF / 100.0;
460     int hcm, lcm, mil;
461
462     mil = roundavg(pp->pl_crew * eff);
463     /* Always use at least 1 mil to build a plane */
464     if (mil == 0 && pp->pl_crew > 0)
465         mil = 1;
466     hcm = roundavg(pp->pl_hcm * eff);
467     lcm = roundavg(pp->pl_lcm * eff);
468     if (sp->sct_type != SCT_AIRPT && !player->god) {
469         pr("Planes must be built in airports.\n");
470         return 0;
471     }
472     if (sp->sct_effic < 60 && !player->god) {
473         pr("Sector %s is not 60%% efficient.\n",
474            xyas(sp->sct_x, sp->sct_y, player->cnum));
475         return 0;
476     }
477     if (vec[I_LCM] < lcm || vec[I_HCM] < hcm) {
478         pr("Not enough materials in %s\n",
479            xyas(sp->sct_x, sp->sct_y, player->cnum));
480         return 0;
481     }
482     avail = (PLN_BLD_WORK(pp->pl_lcm, pp->pl_hcm) * PLANE_MINEFF + 99) / 100;
483     if (sp->sct_avail < avail) {
484         pr("Not enough available work in %s to build a %s\n",
485            xyas(sp->sct_x, sp->sct_y, player->cnum), pp->pl_name);
486         pr(" (%d available work required)\n", avail);
487         return 0;
488     }
489     cost = pp->pl_cost * PLANE_MINEFF / 100.0;
490     if (!build_can_afford(cost, pp->pl_name))
491         return 0;
492     if (vec[I_MILIT] < mil || (vec[I_MILIT] == 0 && pp->pl_crew > 0)) {
493         pr("Not enough military for crew in %s\n",
494            xyas(sp->sct_x, sp->sct_y, player->cnum));
495         return 0;
496     }
497     if (!trechk(player->cnum, 0, NEWPLN))
498         return 0;
499     if (!check_sect_ok(sp))
500         return 0;
501     sp->sct_avail -= avail;
502     player->dolcost += cost;
503     ef_blank(EF_PLANE, pick_unused_unit_uid(EF_PLANE), &plane);
504     plane.pln_x = sp->sct_x;
505     plane.pln_y = sp->sct_y;
506     plane.pln_own = sp->sct_own;
507     plane.pln_type = pp - plchr;
508     plane.pln_effic = PLANE_MINEFF;
509     if (opt_MOB_ACCESS) {
510         game_tick_to_now(&plane.pln_access);
511         plane.pln_mobil = -(etu_per_update / sect_mob_neg_factor);
512     } else {
513         plane.pln_mobil = 0;
514     }
515     plane.pln_range = UCHAR_MAX; /* will be adjusted by pln_set_tech() */
516     plane.pln_ship = -1;
517     plane.pln_land = -1;
518     plane.pln_harden = 0;
519     plane.pln_flags = 0;
520     pln_set_tech(&plane, tlev);
521     unit_wipe_orders((struct empobj *)&plane);
522
523     vec[I_LCM] -= lcm;
524     vec[I_HCM] -= hcm;
525     vec[I_MILIT] -= mil;
526
527     putplane(plane.pln_uid, &plane);
528     pr("%s built in sector %s\n", prplane(&plane),
529        xyas(sp->sct_x, sp->sct_y, player->cnum));
530     return 1;
531 }
532
533 static int
534 pick_unused_unit_uid(int type)
535 {
536     struct nstr_item nstr;
537     union empobj_storage unit;
538
539     snxtitem_all(&nstr, type);
540     while (nxtitem(&nstr, &unit)) {
541         if (!unit.gen.own)
542             return nstr.cur;
543     }
544     ef_extend(type, 50);
545     return nstr.cur;
546 }
547
548 static int
549 build_bridge(char what)
550 {
551     struct natstr *natp = getnatp(player->cnum);
552     struct nstr_sect nstr;
553     int (*build_it)(struct sctstr *);
554     int gotsect;
555     struct sctstr sect;
556
557     switch (what) {
558     case 'b':
559         if (natp->nat_level[NAT_TLEV] < buil_bt) {
560             pr("Building a span requires a tech of %.0f\n", buil_bt);
561             return RET_FAIL;
562         }
563         build_it = build_bspan;
564         break;
565     case 't':
566         if (!opt_BRIDGETOWERS) {
567             pr("Bridge tower building is disabled.\n");
568             return RET_FAIL;
569         }
570         if (natp->nat_level[NAT_TLEV] < buil_tower_bt) {
571             pr("Building a tower requires a tech of %.0f\n",
572                buil_tower_bt);
573             return RET_FAIL;
574         }
575         build_it = build_btower;
576         break;
577     default:
578         CANT_REACH();
579         return RET_FAIL;
580     }
581
582     if (!snxtsct(&nstr, player->argp[2]))
583         return RET_SYN;
584     gotsect = 0;
585     while (nxtsct(&nstr, &sect)) {
586         if (!player->owner)
587             continue;
588         gotsect = 1;
589         if (build_it(&sect))
590             putsect(&sect);
591     }
592     if (!gotsect)
593         pr("No sectors.\n");
594     return RET_OK;
595 }
596
597 static int
598 build_bspan(struct sctstr *sp)
599 {
600     short *vec = sp->sct_item;
601     struct sctstr sect;
602     int val;
603     int newx, newy;
604     int avail;
605     int nx, ny, i, good = 0;
606     char *p;
607     char buf[1024];
608
609     if (opt_EASY_BRIDGES == 0) {        /* must have a bridge head or tower */
610         if (sp->sct_type != SCT_BTOWER) {
611             if (sp->sct_type != SCT_BHEAD)
612                 return 0;
613             if (sp->sct_newtype != SCT_BHEAD)
614                 return 0;
615         }
616     }
617
618     if (sp->sct_effic < 60 && !player->god) {
619         pr("Sector %s is not 60%% efficient.\n",
620            xyas(sp->sct_x, sp->sct_y, player->cnum));
621         return 0;
622     }
623
624     if (vec[I_HCM] < buil_bh) {
625         pr("%s only has %d unit%s of hcm,\n",
626            xyas(sp->sct_x, sp->sct_y, player->cnum),
627            vec[I_HCM], vec[I_HCM] > 1 ? "s" : "");
628         pr("(a bridge span requires %d)\n", buil_bh);
629         return 0;
630     }
631
632     if (!build_can_afford(buil_bc, dchr[SCT_BSPAN].d_name))
633         return 0;
634     avail = (SCT_BLD_WORK(0, buil_bh) * SCT_MINEFF + 99) / 100;
635     if (sp->sct_avail < avail) {
636         pr("Not enough available work in %s to build a bridge\n",
637            xyas(sp->sct_x, sp->sct_y, player->cnum));
638         pr(" (%d available work required)\n", avail);
639         return 0;
640     }
641     if (!player->argp[3]) {
642         pr("Bridge head at %s\n",
643            xyas(sp->sct_x, sp->sct_y, player->cnum));
644         nav_map(sp->sct_x, sp->sct_y, 1);
645     }
646     p = getstarg(player->argp[3], "build span in what direction? ", buf);
647     if (!p || !*p) {
648         return 0;
649     }
650     /* Sanity check time */
651     if (!check_sect_ok(sp))
652         return 0;
653
654     if ((val = chkdir(*p, DIR_FIRST, DIR_LAST)) < 0) {
655         pr("'%c' is not a valid direction...\n", *p);
656         direrr(NULL, NULL, NULL);
657         return 0;
658     }
659     newx = sp->sct_x + diroff[val][0];
660     newy = sp->sct_y + diroff[val][1];
661     if (getsect(newx, newy, &sect) == 0 || sect.sct_type != SCT_WATER) {
662         pr("%s is not a water sector\n", xyas(newx, newy, player->cnum));
663         return 0;
664     }
665     if (opt_EASY_BRIDGES) {
666         good = 0;
667
668         for (i = 1; i <= 6; i++) {
669             struct sctstr s2;
670             nx = sect.sct_x + diroff[i][0];
671             ny = sect.sct_y + diroff[i][1];
672             getsect(nx, ny, &s2);
673             if ((s2.sct_type != SCT_WATER) && (s2.sct_type != SCT_BSPAN))
674                 good = 1;
675         }
676         if (!good) {
677             pr("Bridges must be built adjacent to land or bridge towers.\n");
678             pr("That sector is not adjacent to land or a bridge tower.\n");
679             return 0;
680         }
681     }                           /* end EASY_BRIDGES */
682     sp->sct_avail -= avail;
683     player->dolcost += buil_bc;
684     sect.sct_type = SCT_BSPAN;
685     sect.sct_newtype = SCT_BSPAN;
686     sect.sct_effic = SCT_MINEFF;
687     sect.sct_road = 0;
688     sect.sct_rail = 0;
689     sect.sct_defense = 0;
690     if (opt_MOB_ACCESS) {
691         game_tick_to_now(&sect.sct_access);
692         sect.sct_mobil = -(etu_per_update / sect_mob_neg_factor);
693     } else {
694         sect.sct_mobil = 0;
695     }
696     sect.sct_mines = 0;
697     map_set(player->cnum, sect.sct_x, sect.sct_y, dchr[SCT_BSPAN].d_mnem, 2);
698     writemap(player->cnum);
699     putsect(&sect);
700     pr("Bridge span built over %s\n",
701        xyas(sect.sct_x, sect.sct_y, player->cnum));
702     vec[I_HCM] -= buil_bh;
703     return 1;
704 }
705
706 static int
707 build_btower(struct sctstr *sp)
708 {
709     short *vec = sp->sct_item;
710     struct sctstr sect;
711     int val;
712     int newx, newy;
713     int avail;
714     char *p;
715     char buf[1024];
716     int i;
717     int nx;
718     int ny;
719
720     if (sp->sct_type != SCT_BSPAN) {
721         pr("Bridge towers can only be built from bridge spans.\n");
722         return 0;
723     }
724
725     if (sp->sct_effic < 60 && !player->god) {
726         pr("Sector %s is not 60%% efficient.\n",
727            xyas(sp->sct_x, sp->sct_y, player->cnum));
728         return 0;
729     }
730
731     if (vec[I_HCM] < buil_tower_bh) {
732         pr("%s only has %d unit%s of hcm,\n",
733            xyas(sp->sct_x, sp->sct_y, player->cnum),
734            vec[I_HCM], vec[I_HCM] > 1 ? "s" : "");
735         pr("(a bridge tower requires %d)\n", buil_tower_bh);
736         return 0;
737     }
738
739     if (!build_can_afford(buil_tower_bc, dchr[SCT_BTOWER].d_name))
740         return 0;
741     avail = (SCT_BLD_WORK(0, buil_tower_bh) * SCT_MINEFF + 99) / 100;
742     if (sp->sct_avail < avail) {
743         pr("Not enough available work in %s to build a bridge tower\n",
744            xyas(sp->sct_x, sp->sct_y, player->cnum));
745         pr(" (%d available work required)\n", avail);
746         return 0;
747     }
748     if (!player->argp[3]) {
749         pr("Building from %s\n", xyas(sp->sct_x, sp->sct_y, player->cnum));
750         nav_map(sp->sct_x, sp->sct_y, 1);
751     }
752     p = getstarg(player->argp[3], "build tower in what direction? ", buf);
753     if (!p || !*p) {
754         return 0;
755     }
756     /* Sanity check time */
757     if (!check_sect_ok(sp))
758         return 0;
759
760     if ((val = chkdir(*p, DIR_FIRST, DIR_LAST)) < 0) {
761         pr("'%c' is not a valid direction...\n", *p);
762         direrr(NULL, NULL, NULL);
763         return 0;
764     }
765     newx = sp->sct_x + diroff[val][0];
766     newy = sp->sct_y + diroff[val][1];
767     if (getsect(newx, newy, &sect) == 0 || sect.sct_type != SCT_WATER) {
768         pr("%s is not a water sector\n", xyas(newx, newy, player->cnum));
769         return 0;
770     }
771
772     /* Now, check.  You aren't allowed to build bridge towers
773        next to land. */
774     for (i = 1; i <= 6; i++) {
775         struct sctstr s2;
776         nx = sect.sct_x + diroff[i][0];
777         ny = sect.sct_y + diroff[i][1];
778         getsect(nx, ny, &s2);
779         if ((s2.sct_type != SCT_WATER) &&
780             (s2.sct_type != SCT_BTOWER) && (s2.sct_type != SCT_BSPAN)) {
781             pr("Bridge towers cannot be built adjacent to land.\n");
782             pr("That sector is adjacent to land.\n");
783             return 0;
784         }
785     }
786
787     sp->sct_avail -= avail;
788     player->dolcost += buil_tower_bc;
789     sect.sct_type = SCT_BTOWER;
790     sect.sct_newtype = SCT_BTOWER;
791     sect.sct_effic = SCT_MINEFF;
792     sect.sct_road = 0;
793     sect.sct_rail = 0;
794     sect.sct_defense = 0;
795     if (opt_MOB_ACCESS) {
796         game_tick_to_now(&sect.sct_access);
797         sect.sct_mobil = -(etu_per_update / sect_mob_neg_factor);
798     } else {
799         sect.sct_mobil = 0;
800     }
801     sect.sct_mines = 0;
802     map_set(player->cnum, sect.sct_x, sect.sct_y, dchr[SCT_BTOWER].d_mnem, 2);
803     writemap(player->cnum);
804     putsect(&sect);
805     pr("Bridge tower built in %s\n",
806        xyas(sect.sct_x, sect.sct_y, player->cnum));
807     vec[I_HCM] -= buil_tower_bh;
808     return 1;
809 }
810
811 static int
812 build_can_afford(double cost, char *what)
813 {
814     struct natstr *natp = getnatp(player->cnum);
815     if (natp->nat_money < player->dolcost + cost) {
816         pr("Not enough money left to build a %s\n", what);
817         return 0;
818     }
819     return 1;
820 }