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