Galactic Bloodshed
build.cc
Go to the documentation of this file.
1 // Copyright 2014 The Galactic Bloodshed Authors. All rights reserved.
2 // Use of this source code is governed by a license that can be
3 // found in the COPYING file.
4 
5 /* build -- build a ship */
6 
7 #include "gb/build.h"
8 
9 #include <cmath>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <ctgmath>
14 #include <optional>
15 
16 #include "gb/GB_server.h"
17 #include "gb/buffers.h"
18 #include "gb/config.h"
19 #include "gb/files.h"
20 #include "gb/files_shl.h"
21 #include "gb/fire.h"
22 #include "gb/getplace.h"
23 #include "gb/land.h"
24 #include "gb/races.h"
25 #include "gb/shipdata.h"
26 #include "gb/ships.h"
27 #include "gb/shlmisc.h"
28 #include "gb/shootblast.h"
29 #include "gb/tele.h"
30 #include "gb/tweakables.h"
31 #include "gb/vars.h"
32 
33 static void autoload_at_planet(int, Ship *, Planet *, Sector &, int *,
34  double *);
35 static void autoload_at_ship(Ship *, Ship *, int *, double *);
36 static std::optional<ScopeLevel> build_at_ship(GameObj &, Ship *, int *, int *);
37 static int can_build_at_planet(GameObj &, startype *, const Planet &);
38 static bool can_build_this(const ShipType, const Race &, char *);
39 static int can_build_on_ship(int, Race *, Ship *, char *);
40 static void create_ship_by_planet(int, int, Race *, Ship *, Planet *, int, int,
41  int, int);
42 static void create_ship_by_ship(int, int, Race *, int, Planet *, Ship *,
43  Ship *);
44 static std::optional<ShipType> get_build_type(const char);
45 static int getcount(const command_t &, const size_t);
46 static void Getfactship(Ship *, Ship *);
47 static void Getship(Ship *, ShipType, Race *);
48 static void initialize_new_ship(GameObj &, Race *, Ship *, double, int);
49 
50 namespace {
51 bool can_build_on_sector(const int what, const racetype *Race,
52  const Planet &planet, const Sector &sector,
53  const int x, const int y, char *string) {
54  auto shipc = Shipltrs[what];
55  if (!sector.popn) {
56  sprintf(string, "You have no more civs in the sector!\n");
57  return false;
58  }
59  if (sector.condition == SectorType::SEC_WASTED) {
60  sprintf(string, "You can't build on wasted sectors.\n");
61  return false;
62  }
63  if (sector.owner != Race->Playernum && !Race->God) {
64  sprintf(string, "You don't own that sector.\n");
65  return false;
66  }
67  if ((!(Shipdata[what][ABIL_BUILD] & 1)) && !Race->God) {
68  sprintf(string, "This ship type cannot be built on a planet.\n");
69  sprintf(temp, "Use 'build ? %c' to find out where it can be built.\n",
70  shipc);
71  strcat(string, temp);
72  return false;
73  }
74  if (what == ShipType::OTYPE_QUARRY) {
75  Shiplist shiplist(planet.ships);
76  for (auto s : shiplist) {
77  if (s.alive && s.type == ShipType::OTYPE_QUARRY && s.land_x == x &&
78  s.land_y == y) {
79  sprintf(string, "There already is a quarry here.\n");
80  return false;
81  }
82  }
83  }
84  return true;
85 }
86 } // namespace
87 
88 /* upgrade ship characteristics */
89 void upgrade(const command_t &argv, GameObj &g) {
90  const player_t Playernum = g.player;
91  const governor_t Governor = g.governor;
92  // TODO(jeffbailey): Fix unused int APcount = 1;
93  int value;
94  int oldcost;
95  int newcost;
96  int netcost;
97  double complex;
98  racetype *Race;
99 
100  if (g.level != ScopeLevel::LEVEL_SHIP) {
101  g.out << "You have to change scope to the ship you wish to upgrade.\n";
102  return;
103  }
104  auto dirship = getship(g.shipno);
105  if (!dirship) {
106  g.out << "Illegal dir value.\n";
107  return;
108  }
109  if (testship(Playernum, Governor, *dirship)) {
110  return;
111  }
112  if (dirship->damage) {
113  g.out << "You cannot upgrade damaged ships.\n";
114  return;
115  }
116  if (dirship->type == ShipType::OTYPE_FACTORY) {
117  g.out << "You can't upgrade factories.\n";
118  return;
119  }
120 
121  Race = races[Playernum - 1];
122  auto ship = *dirship;
123 
124  if (argv.size() == 3)
125  value = std::stoi(argv[2]);
126  else
127  value = 0;
128 
129  if (value < 0) {
130  g.out << "That's a ridiculous setting.\n";
131  return;
132  }
133 
134  if (!Shipdata[dirship->build_type][ABIL_MOD]) {
135  g.out << "This ship cannot be upgraded.\n";
136  return;
137  }
138 
139  if (argv[1] == "armor") {
140  ship.armor = MAX(dirship->armor, MIN(value, 100));
141  } else if (argv[1] == "crew" && Shipdata[dirship->build_type][ABIL_MAXCREW]) {
142  ship.max_crew = MAX(dirship->max_crew, MIN(value, 10000));
143  } else if (argv[1] == "cargo" && Shipdata[dirship->build_type][ABIL_CARGO]) {
144  ship.max_resource = MAX(dirship->max_resource, MIN(value, 10000));
145  } else if (argv[1] == "hanger" &&
146  Shipdata[dirship->build_type][ABIL_HANGER]) {
147  ship.max_hanger = MAX(dirship->max_hanger, MIN(value, 10000));
148  } else if (argv[1] == "fuel" && Shipdata[dirship->build_type][ABIL_FUELCAP]) {
149  ship.max_fuel = MAX(dirship->max_fuel, MIN(value, 10000));
150  } else if (argv[1] == "mount" && Shipdata[dirship->build_type][ABIL_MOUNT] &&
151  !dirship->mount) {
152  if (!Crystal(Race)) {
153  g.out << "Your race does not now how to utilize crystal power yet.\n";
154  return;
155  }
156  ship.mount = !ship.mount;
157  } else if (argv[1] == "destruct" &&
158  Shipdata[dirship->build_type][ABIL_DESTCAP]) {
159  ship.max_destruct = MAX(dirship->max_destruct, MIN(value, 10000));
160  } else if (argv[1] == "speed" && Shipdata[dirship->build_type][ABIL_SPEED]) {
161  ship.max_speed = MAX(dirship->max_speed, MAX(1, MIN(value, 9)));
162  } else if (argv[1] == "hyperdrive" &&
163  Shipdata[dirship->build_type][ABIL_JUMP] &&
164  !dirship->hyper_drive.has && Hyper_drive(Race)) {
165  ship.hyper_drive.has = 1;
166  } else if (argv[1] == "primary" &&
167  Shipdata[dirship->build_type][ABIL_PRIMARY]) {
168  if (argv[2] == "strength") {
169  if (ship.primtype == GTYPE_NONE) {
170  g.out << "No caliber defined.\n";
171  return;
172  }
173  ship.primary = std::stoi(argv[3]);
174  ship.primary = MAX(ship.primary, dirship->primary);
175  } else if (argv[2] == "caliber") {
176  if (argv[3] == "light")
177  ship.primtype = MAX(GTYPE_LIGHT, dirship->primtype);
178  else if (argv[3] == "medium")
179  ship.primtype = MAX(GTYPE_MEDIUM, dirship->primtype);
180  else if (argv[3] == "heavy")
181  ship.primtype = MAX(GTYPE_HEAVY, dirship->primtype);
182  else {
183  g.out << "No such caliber.\n";
184  return;
185  }
186  ship.primtype =
187  MIN(Shipdata[dirship->build_type][ABIL_PRIMARY], ship.primtype);
188  } else {
189  g.out << "No such gun characteristic.\n";
190  return;
191  }
192  } else if (argv[1] == "secondary" &&
193  Shipdata[dirship->build_type][ABIL_SECONDARY]) {
194  if (argv[2] == "strength") {
195  if (ship.sectype == GTYPE_NONE) {
196  g.out << "No caliber defined.\n";
197  return;
198  }
199  ship.secondary = std::stoi(argv[3]);
200  ship.secondary = MAX(ship.secondary, dirship->secondary);
201  } else if (argv[2] == "caliber") {
202  if (argv[3] == "light")
203  ship.sectype = MAX(GTYPE_LIGHT, dirship->sectype);
204  else if (argv[3] == "medium")
205  ship.sectype = MAX(GTYPE_MEDIUM, dirship->sectype);
206  else if (argv[3] == "heavy")
207  ship.sectype = MAX(GTYPE_HEAVY, dirship->sectype);
208  else {
209  g.out << "No such caliber.\n";
210  return;
211  }
212  ship.sectype =
213  MIN(Shipdata[dirship->build_type][ABIL_SECONDARY], ship.sectype);
214  } else {
215  g.out << "No such gun characteristic.\n";
216  return;
217  }
218  } else if (argv[1] == "cew" && Shipdata[dirship->build_type][ABIL_CEW]) {
219  if (!Cew(Race)) {
220  g.out << "Your race cannot build confined energy weapons.\n";
221  return;
222  }
223  if (!Shipdata[dirship->build_type][ABIL_CEW]) {
224  g.out << "This kind of ship cannot mount confined energy weapons.\n";
225  return;
226  }
227  value = std::stoi(argv[3]);
228  if (argv[2] == "strength") {
229  ship.cew = value;
230  } else if (argv[2] == "range") {
231  ship.cew_range = value;
232  } else {
233  g.out << "No such option for CEWs.\n";
234  return;
235  }
236  } else if (argv[1] == "laser" && Shipdata[dirship->build_type][ABIL_LASER]) {
237  if (!Laser(Race)) {
238  g.out << "Your race cannot build lasers.\n";
239  return;
240  }
241  if (Shipdata[dirship->build_type][ABIL_LASER])
242  ship.laser = 1;
243  else {
244  g.out << "That ship cannot be fitted with combat lasers.\n";
245  return;
246  }
247  } else {
248  g.out << "That characteristic either doesn't exist or can't be modified.\n";
249  return;
250  }
251 
252  /* check to see whether this ship can actually be built by this player */
253  if ((complex = complexity(ship)) > Race->tech) {
254  sprintf(buf, "This upgrade requires an engineering technology of %.1f.\n",
255  complex);
256  notify(Playernum, Governor, buf);
257  return;
258  }
259 
260  /* check to see if the new ship will actually fit inside the hanger if it is
261  on another ship. Maarten */
262  std::optional<Ship> s2;
263  if (dirship->whatorbits == ScopeLevel::LEVEL_SHIP) {
264  s2 = getship(dirship->destshipno);
265  if (s2->max_hanger - (s2->hanger - dirship->size) < ship_size(ship)) {
266  sprintf(buf, "Not enough free hanger space on %c%ld.\n",
267  Shipltrs[s2->type], dirship->destshipno);
268  notify(Playernum, Governor, buf);
269  sprintf(
270  buf, "%d more needed.\n",
271  ship_size(ship) - (s2->max_hanger - (s2->hanger - dirship->size)));
272  notify(Playernum, Governor, buf);
273  return;
274  }
275  }
276 
277  /* compute new ship costs and see if the player can afford it */
278  newcost = Race->God ? 0 : (int)cost(ship);
279  oldcost = Race->God ? 0 : dirship->build_cost;
280  netcost = Race->God ? 0 : 2 * (newcost - oldcost); /* upgrade is expensive */
281  if (newcost < oldcost) {
282  g.out << "You cannot downgrade ships!\n";
283  return;
284  }
285  if (!Race->God) netcost += !netcost;
286 
287  if (netcost > dirship->resource) {
288  sprintf(buf, "Old value %dr New value %dr\n", oldcost, newcost);
289  notify(Playernum, Governor, buf);
290  sprintf(buf, "You need %d resources on board to make this modification.\n",
291  netcost);
292  notify(Playernum, Governor, buf);
293  } else if (netcost || Race->God) {
294  sprintf(buf, "Old value %dr New value %dr\n", oldcost, newcost);
295  notify(Playernum, Governor, buf);
296  sprintf(buf, "Characteristic modified at a cost of %d resources.\n",
297  netcost);
298  notify(Playernum, Governor, buf);
299  bcopy(&ship, &*dirship, sizeof(Ship));
300  dirship->resource -= netcost;
301  if (dirship->whatorbits == ScopeLevel::LEVEL_SHIP) {
302  s2->hanger -= dirship->size;
303  dirship->size = ship_size(*dirship);
304  s2->hanger += dirship->size;
305  putship(&*s2);
306  }
307  dirship->size = ship_size(*dirship);
308  dirship->base_mass = getmass(*dirship);
309  dirship->build_cost = Race->God ? 0 : cost(*dirship);
310  dirship->complexity = complexity(*dirship);
311 
312  putship(&*dirship);
313  } else
314  g.out << "You can not make this modification.\n";
315 }
316 
317 void make_mod(const command_t &argv, GameObj &g) {
318  const player_t Playernum = g.player;
319  const governor_t Governor = g.governor;
320  int mode;
321  if (argv[0] == "make")
322  mode = 0;
323  else
324  mode = 1 /* modify */;
325  int value;
326  unsigned short size;
327  char shipc;
328  racetype *Race;
329  double cost0;
330 
331  if (g.level != ScopeLevel::LEVEL_SHIP) {
332  g.out << "You have to change scope to an installation.\n";
333  return;
334  }
335 
336  auto dirship = getship(g.shipno);
337  if (!dirship) {
338  g.out << "Illegal dir value.\n";
339  return;
340  }
341  if (testship(Playernum, Governor, *dirship)) {
342  return;
343  }
344  if (dirship->type != ShipType::OTYPE_FACTORY) {
345  g.out << "That is not a factory.\n";
346  return;
347  }
348  if (dirship->on && argv.size() > 1) {
349  g.out << "This factory is already online.\n";
350  return;
351  }
352  Race = races[Playernum - 1];
353 
354  /* Save size of the factory, and set it to the
355  correct values for the design. Maarten */
356  size = dirship->size;
357  dirship->size = ship_size(*dirship);
358 
359  if (mode == 0) {
360  if (argv.size() < 2) { /* list the current settings for the factory */
361  if (!dirship->build_type) {
362  g.out << "No ship type specified.\n";
363  return;
364  }
365  notify(Playernum, Governor,
366  " --- Current Production Specifications ---\n");
367  sprintf(buf, "%s\t\t\tArmor: %4d\t\tGuns:",
368  (dirship->on ? "Online" : "Offline"), dirship->armor);
369  notify(Playernum, Governor, buf);
370  if (Shipdata[dirship->build_type][ABIL_PRIMARY] &&
371  dirship->primtype != GTYPE_NONE) {
372  sprintf(buf, "%3lu%c", dirship->primary,
373  (dirship->primtype == GTYPE_LIGHT
374  ? 'L'
375  : dirship->primtype == GTYPE_MEDIUM
376  ? 'M'
377  : dirship->primtype == GTYPE_HEAVY ? 'H' : 'N'));
378  notify(Playernum, Governor, buf);
379  }
380  if (Shipdata[dirship->build_type][ABIL_SECONDARY] &&
381  dirship->sectype != GTYPE_NONE) {
382  sprintf(buf, "/%lu%c", dirship->secondary,
383  (dirship->sectype == GTYPE_LIGHT
384  ? 'L'
385  : dirship->sectype == GTYPE_MEDIUM
386  ? 'M'
387  : dirship->sectype == GTYPE_HEAVY ? 'H' : 'N'));
388  notify(Playernum, Governor, buf);
389  }
390  g.out << "\n";
391  sprintf(buf, "Ship: %-16.16s\tCrew: %4d",
392  Shipnames[dirship->build_type], dirship->max_crew);
393  notify(Playernum, Governor, buf);
394  if (Shipdata[dirship->build_type][ABIL_MOUNT]) {
395  sprintf(buf, "\t\tXtal Mount: %s\n", (dirship->mount ? "yes" : "no"));
396  notify(Playernum, Governor, buf);
397  } else
398  g.out << "\n";
399  sprintf(buf, "Class: %s\t\tFuel: %4d", dirship->shipclass,
400  dirship->max_fuel);
401  notify(Playernum, Governor, buf);
402  if (Shipdata[dirship->build_type][ABIL_JUMP]) {
403  sprintf(buf, "\t\tHyperdrive: %s\n",
404  (dirship->hyper_drive.has ? "yes" : "no"));
405  notify(Playernum, Governor, buf);
406  } else
407  g.out << "\n";
408  sprintf(buf, "Cost: %d r\t\tCargo: %4lu", dirship->build_cost,
409  dirship->max_resource);
410  notify(Playernum, Governor, buf);
411  if (Shipdata[dirship->build_type][ABIL_LASER]) {
412  sprintf(buf, "\t\tCombat Lasers: %s\n",
413  (dirship->laser ? "yes" : "no"));
414  notify(Playernum, Governor, buf);
415  } else
416  g.out << "\n";
417  sprintf(buf, "Mass: %.1f\t\tHanger: %4u", dirship->base_mass,
418  dirship->max_hanger);
419  notify(Playernum, Governor, buf);
420  if (Shipdata[dirship->build_type][ABIL_CEW]) {
421  sprintf(buf, "\t\tCEW: %s\n", (dirship->cew ? "yes" : "no"));
422  notify(Playernum, Governor, buf);
423  } else
424  g.out << "\n";
425  sprintf(buf, "Size: %-6d\t\tDestruct: %4d", dirship->size,
426  dirship->max_destruct);
427  notify(Playernum, Governor, buf);
428  if (Shipdata[dirship->build_type][ABIL_CEW] && dirship->cew) {
429  sprintf(buf, "\t\t Opt Range: %4d\n", dirship->cew_range);
430  notify(Playernum, Governor, buf);
431  } else
432  g.out << "\n";
433  sprintf(buf, "Tech: %.1f (%.1f)\tSpeed: %4d", dirship->complexity,
434  Race->tech, dirship->max_speed);
435  notify(Playernum, Governor, buf);
436  if (Shipdata[dirship->build_type][ABIL_CEW] && dirship->cew) {
437  sprintf(buf, "\t\t Energy: %4d\n", dirship->cew);
438  notify(Playernum, Governor, buf);
439  } else
440  g.out << "\n";
441 
442  if (Race->tech < dirship->complexity)
443  notify(Playernum, Governor,
444  "Your engineering capability is not "
445  "advanced enough to produce this "
446  "design.\n");
447  return;
448  }
449 
450  shipc = argv[1][0];
451 
452  auto i = get_build_type(shipc);
453 
454  if ((!i) || ((*i == ShipType::STYPE_POD) && (!Race->pods))) {
455  g.out << "Illegal ship letter.\n";
456  return;
457  }
458  if (Shipdata[*i][ABIL_GOD] && !Race->God) {
459  g.out << "Nice try!\n";
460  return;
461  }
462  if (!(Shipdata[*i][ABIL_BUILD] &
463  Shipdata[ShipType::OTYPE_FACTORY][ABIL_CONSTRUCT])) {
464  g.out << "This kind of ship does not require a factory to construct.\n";
465  return;
466  }
467 
468  dirship->build_type = *i;
469  dirship->armor = Shipdata[*i][ABIL_ARMOR];
470  dirship->guns = GTYPE_NONE; /* this keeps track of the factory status! */
471  dirship->primary = Shipdata[*i][ABIL_GUNS];
472  dirship->primtype = Shipdata[*i][ABIL_PRIMARY];
473  dirship->secondary = Shipdata[*i][ABIL_GUNS];
474  dirship->sectype = Shipdata[*i][ABIL_SECONDARY];
475  dirship->max_crew = Shipdata[*i][ABIL_MAXCREW];
476  dirship->max_resource = Shipdata[*i][ABIL_CARGO];
477  dirship->max_hanger = Shipdata[*i][ABIL_HANGER];
478  dirship->max_fuel = Shipdata[*i][ABIL_FUELCAP];
479  dirship->max_destruct = Shipdata[*i][ABIL_DESTCAP];
480  dirship->max_speed = Shipdata[*i][ABIL_SPEED];
481 
482  dirship->mount = Shipdata[*i][ABIL_MOUNT] * Crystal(Race);
483  dirship->hyper_drive.has = Shipdata[*i][ABIL_JUMP] * Hyper_drive(Race);
484  dirship->cloak = Shipdata[*i][ABIL_CLOAK] * Cloak(Race);
485  dirship->laser = Shipdata[*i][ABIL_LASER] * Laser(Race);
486  dirship->cew = 0;
487  dirship->mode = 0;
488 
489  dirship->size = ship_size(*dirship);
490  dirship->complexity = complexity(*dirship);
491 
492  sprintf(dirship->shipclass, "mod %ld", g.shipno);
493 
494  sprintf(buf, "Factory designated to produce %ss.\n", Shipnames[*i]);
495  notify(Playernum, Governor, buf);
496  sprintf(buf, "Design complexity %.1f (%.1f).\n", dirship->complexity,
497  Race->tech);
498  notify(Playernum, Governor, buf);
499  if (dirship->complexity > Race->tech)
500  g.out << "You can't produce this design yet!\n";
501 
502  } else if (mode == 1) {
503  if (!dirship->build_type) {
504  g.out << "No ship design specified. Use 'make <ship type>' first.\n";
505  return;
506  }
507 
508  if (argv.size() < 2) {
509  g.out << "You have to specify the characteristic you wish to modify.\n";
510  return;
511  }
512 
513  if (argv.size() == 3)
514  value = std::stoi(argv[2]);
515  else
516  value = 0;
517 
518  if (value < 0) {
519  g.out << "That's a ridiculous setting.\n";
520  return;
521  }
522 
523  if (Shipdata[dirship->build_type][ABIL_MOD]) {
524  if (argv[1] == "armor") {
525  dirship->armor = MIN(value, 100);
526  } else if (argv[1] == "crew" &&
527  Shipdata[dirship->build_type][ABIL_MAXCREW]) {
528  dirship->max_crew = MIN(value, 10000);
529  } else if (argv[1] == "cargo" &&
530  Shipdata[dirship->build_type][ABIL_CARGO]) {
531  dirship->max_resource = MIN(value, 10000);
532  } else if (argv[1] == "hanger" &&
533  Shipdata[dirship->build_type][ABIL_HANGER]) {
534  dirship->max_hanger = MIN(value, 10000);
535  } else if (argv[1] == "fuel" &&
536  Shipdata[dirship->build_type][ABIL_FUELCAP]) {
537  dirship->max_fuel = MIN(value, 10000);
538  } else if (argv[1] == "destruct" &&
539  Shipdata[dirship->build_type][ABIL_DESTCAP]) {
540  dirship->max_destruct = MIN(value, 10000);
541  } else if (argv[1] == "speed" &&
542  Shipdata[dirship->build_type][ABIL_SPEED]) {
543  dirship->max_speed = MAX(1, MIN(value, 9));
544  } else if (argv[1] == "mount" &&
545  Shipdata[dirship->build_type][ABIL_MOUNT] && Crystal(Race)) {
546  dirship->mount = !dirship->mount;
547  } else if (argv[1] == "hyperdrive" &&
548  Shipdata[dirship->build_type][ABIL_JUMP] &&
549  Hyper_drive(Race)) {
550  dirship->hyper_drive.has = !dirship->hyper_drive.has;
551  } else if (argv[1] == "primary" &&
552  Shipdata[dirship->build_type][ABIL_PRIMARY]) {
553  if (argv[2] == "strength") {
554  dirship->primary = std::stoi(argv[3]);
555  } else if (argv[2] == "caliber") {
556  if (argv[3] == "light")
557  dirship->primtype = GTYPE_LIGHT;
558  else if (argv[3] == "medium")
559  dirship->primtype = GTYPE_MEDIUM;
560  else if (argv[3] == "heavy")
561  dirship->primtype = GTYPE_HEAVY;
562  else {
563  g.out << "No such caliber.\n";
564  return;
565  }
566  dirship->primtype = MIN(Shipdata[dirship->build_type][ABIL_PRIMARY],
567  dirship->primtype);
568  } else {
569  g.out << "No such gun characteristic.\n";
570  return;
571  }
572  } else if (argv[1] == "secondary" &&
573  Shipdata[dirship->build_type][ABIL_SECONDARY]) {
574  if (argv[2] == "strength") {
575  dirship->secondary = std::stoi(argv[3]);
576  } else if (argv[2] == "caliber") {
577  if (argv[3] == "light")
578  dirship->sectype = GTYPE_LIGHT;
579  else if (argv[3] == "medium")
580  dirship->sectype = GTYPE_MEDIUM;
581  else if (argv[3] == "heavy")
582  dirship->sectype = GTYPE_HEAVY;
583  else {
584  g.out << "No such caliber.\n";
585  return;
586  }
587  dirship->sectype = MIN(Shipdata[dirship->build_type][ABIL_SECONDARY],
588  dirship->sectype);
589  } else {
590  g.out << "No such gun characteristic.\n";
591  return;
592  }
593  } else if (argv[1] == "cew" && Shipdata[dirship->build_type][ABIL_CEW]) {
594  if (!Cew(Race)) {
595  g.out << "Your race does not understand confined energy weapons.\n";
596  return;
597  }
598  if (!Shipdata[dirship->build_type][ABIL_CEW]) {
599  g.out << "This kind of ship cannot mount confined energy weapons.\n";
600  return;
601  }
602  value = std::stoi(argv[3]);
603  if (argv[2] == "strength") {
604  dirship->cew = value;
605  } else if (argv[2] == "range") {
606  dirship->cew_range = value;
607  } else {
608  g.out << "No such option for CEWs.\n";
609  return;
610  }
611  } else if (argv[1] == "laser" &&
612  Shipdata[dirship->build_type][ABIL_LASER]) {
613  if (!Laser(Race)) {
614  g.out << "Your race does not understand lasers yet.\n";
615  return;
616  }
617  if (Shipdata[dirship->build_type][ABIL_LASER])
618  dirship->laser = !dirship->laser;
619  else {
620  g.out << "That ship cannot be fitted with combat lasers.\n";
621  return;
622  }
623  } else {
624  g.out << "That characteristic either doesn't exist or can't be "
625  "modified.\n";
626  return;
627  }
628  } else if (Hyper_drive(Race)) {
629  if (argv[1] == "hyperdrive") {
630  dirship->hyper_drive.has = !dirship->hyper_drive.has;
631  } else {
632  g.out << "You may only modify hyperdrive "
633  "installation on this kind of ship.\n";
634  return;
635  }
636  } else {
637  g.out << "Sorry, but you can't modify this ship right now.\n";
638  return;
639  }
640  } else {
641  g.out << "Weird error.\n";
642  return;
643  }
644  /* compute how much it's going to cost to build the ship */
645 
646  if ((cost0 = cost(*dirship)) > 65535.0) {
647  g.out << "Woah!! YOU CHEATER!!! The max cost allowed "
648  "is 65535!!! I'm Telllllllling!!!\n";
649  return;
650  }
651 
652  dirship->build_cost = Race->God ? 0 : (int)cost0;
653  sprintf(buf, "The current cost of the ship is %d resources.\n",
654  dirship->build_cost);
655  notify(Playernum, Governor, buf);
656  dirship->size = ship_size(*dirship);
657  dirship->base_mass = getmass(*dirship);
658  sprintf(buf, "The current base mass of the ship is %.1f - size is %d.\n",
659  dirship->base_mass, dirship->size);
660  notify(Playernum, Governor, buf);
661  dirship->complexity = complexity(*dirship);
662  sprintf(buf,
663  "Ship complexity is %.1f (you have %.1f engineering technology).\n",
664  dirship->complexity, Race->tech);
665  notify(Playernum, Governor, buf);
666 
667  /* Restore size to what it was before. Maarten */
668  dirship->size = size;
669 
670  putship(&*dirship);
671 }
672 
673 void build(const command_t &argv, GameObj &g) {
674  const player_t Playernum = g.player;
675  const governor_t Governor = g.governor;
676  // TODO(jeffbailey): Fix unused int APcount = 1;
677  racetype *Race;
678  Planet planet;
679  char c;
680  int j;
681  int m;
682  int n;
683  int x;
684  int y;
685  int count;
686  int outside;
687  ScopeLevel level;
688  ScopeLevel build_level;
689  int shipcost;
690  int load_crew;
691  int snum;
692  int pnum;
693  double load_fuel;
694  double tech;
695 
696  FILE *fd;
697  Sector sector;
698  std::optional<Ship> builder;
699  Ship newship;
700 
701  if (argv.size() > 1 && argv[1][0] == '?') {
702  /* information request */
703  if (argv.size() == 2) {
704  /* Ship parameter list */
705  g.out << " - Default ship parameters -\n";
706  sprintf(buf,
707  "%1s %-15s %5s %5s %3s %4s %3s %3s %3s %4s %4s %2s %4s %4s\n",
708  "?", "name", "cargo", "hang", "arm", "dest", "gun", "pri", "sec",
709  "fuel", "crew", "sp", "tech", "cost");
710  notify(Playernum, Governor, buf);
711  Race = races[Playernum - 1];
712  for (j = 0; j < NUMSTYPES; j++) {
713  ShipType i{ShipVector[j]};
714  if ((!Shipdata[i][ABIL_GOD]) || Race->God) {
715  if (Race->pods || (i != ShipType::STYPE_POD)) {
716  if (Shipdata[i][ABIL_PROGRAMMED]) {
717  sprintf(buf,
718  "%1c %-15.15s %5ld %5ld %3ld %4ld %3ld %3ld %3ld "
719  "%4ld %4ld %2ld %4.0f %4d\n",
720  Shipltrs[i], Shipnames[i], Shipdata[i][ABIL_CARGO],
721  Shipdata[i][ABIL_HANGER], Shipdata[i][ABIL_ARMOR],
722  Shipdata[i][ABIL_DESTCAP], Shipdata[i][ABIL_GUNS],
723  Shipdata[i][ABIL_PRIMARY], Shipdata[i][ABIL_SECONDARY],
724  Shipdata[i][ABIL_FUELCAP], Shipdata[i][ABIL_MAXCREW],
725  Shipdata[i][ABIL_SPEED], (double)Shipdata[i][ABIL_TECH],
726  Shipcost(i, Race));
727  notify(Playernum, Governor, buf);
728  }
729  }
730  }
731  }
732  return;
733  }
734  /* Description of specific ship type */
735  auto i = get_build_type(argv[2][0]);
736  if (!i)
737  g.out << "No such ship type.\n";
738  else if (!Shipdata[*i][ABIL_PROGRAMMED])
739  g.out << "This ship type has not been programmed.\n";
740  else {
741  if ((fd = fopen(EXAM_FL, "r")) == nullptr) {
742  perror(EXAM_FL);
743  return;
744  }
745  /* look through ship description file */
746  sprintf(buf, "\n");
747  for (j = 0; j <= i; j++)
748  while (fgetc(fd) != '~')
749  ;
750  /* Give description */
751  while ((c = fgetc(fd)) != '~') {
752  sprintf(temp, "%c", c);
753  strcat(buf, temp);
754  }
755  fclose(fd);
756  /* Built where? */
757  if (Shipdata[*i][ABIL_BUILD] & 1) {
758  sprintf(temp, "\nCan be constructed on planet.");
759  strcat(buf, temp);
760  }
761  n = 0;
762  sprintf(temp, "\nCan be built by ");
763  for (j = 0; j < NUMSTYPES; j++)
764  if (Shipdata[*i][ABIL_BUILD] & Shipdata[j][ABIL_CONSTRUCT]) n++;
765  if (n) {
766  m = 0;
767  strcat(buf, temp);
768  for (j = 0; j < NUMSTYPES; j++) {
769  if (Shipdata[*i][ABIL_BUILD] & Shipdata[j][ABIL_CONSTRUCT]) {
770  m++;
771  if (n - m > 1)
772  sprintf(temp, "%c, ", Shipltrs[j]);
773  else if (n - m > 0)
774  sprintf(temp, "%c and ", Shipltrs[j]);
775  else
776  sprintf(temp, "%c ", Shipltrs[j]);
777  strcat(buf, temp);
778  }
779  }
780  sprintf(temp, "type ships.\n");
781  strcat(buf, temp);
782  }
783  /* default parameters */
784  sprintf(temp,
785  "\n%1s %-15s %5s %5s %3s %4s %3s %3s %3s %4s %4s %2s %4s %4s\n",
786  "?", "name", "cargo", "hang", "arm", "dest", "gun", "pri", "sec",
787  "fuel", "crew", "sp", "tech", "cost");
788  strcat(buf, temp);
789  Race = races[Playernum - 1];
790  sprintf(temp,
791  "%1c %-15.15s %5ld %5ld %3ld %4ld %3ld %3ld %3ld %4ld "
792  "%4ld %2ld %4.0f %4d\n",
793  Shipltrs[*i], Shipnames[*i], Shipdata[*i][ABIL_CARGO],
794  Shipdata[*i][ABIL_HANGER], Shipdata[*i][ABIL_ARMOR],
795  Shipdata[*i][ABIL_DESTCAP], Shipdata[*i][ABIL_GUNS],
796  Shipdata[*i][ABIL_PRIMARY], Shipdata[*i][ABIL_SECONDARY],
797  Shipdata[*i][ABIL_FUELCAP], Shipdata[*i][ABIL_MAXCREW],
798  Shipdata[*i][ABIL_SPEED], (double)Shipdata[*i][ABIL_TECH],
799  Shipcost(*i, Race));
800  strcat(buf, temp);
801  notify(Playernum, Governor, buf);
802  }
803 
804  return;
805  }
806 
807  level = g.level;
808  if (level != ScopeLevel::LEVEL_SHIP && level != ScopeLevel::LEVEL_PLAN) {
809  g.out << "You must change scope to a ship or planet to build.\n";
810  return;
811  }
812  snum = g.snum;
813  pnum = g.pnum;
814  Race = races[Playernum - 1];
815  count = 0; /* this used used to reset count in the loop */
816  std::optional<ShipType> what;
817  do {
818  switch (level) {
819  case ScopeLevel::LEVEL_PLAN:
820  if (!count) { /* initialize loop variables */
821  if (argv.size() < 2) {
822  g.out << "Build what?\n";
823  return;
824  }
825  what = get_build_type(argv[1][0]);
826  if (!what) {
827  g.out << "No such ship type.\n";
828  return;
829  }
830  if (!can_build_this(*what, *Race, buf) && !Race->God) {
831  notify(Playernum, Governor, buf);
832  return;
833  }
834  if (!(Shipdata[*what][ABIL_BUILD] & 1) && !Race->God) {
835  g.out << "This ship cannot be built by a planet.\n";
836  return;
837  }
838  if (argv.size() < 3) {
839  g.out << "Build where?\n";
840  return;
841  }
842  planet = getplanet(snum, pnum);
843  if (!can_build_at_planet(g, Stars[snum], planet) && !Race->God) {
844  g.out << "You can't build that here.\n";
845  return;
846  }
847  sscanf(argv[2].c_str(), "%d,%d", &x, &y);
848  if (x < 0 || x >= planet.Maxx || y < 0 || y >= planet.Maxy) {
849  g.out << "Illegal sector.\n";
850  return;
851  }
852  sector = getsector(planet, x, y);
853  if (!can_build_on_sector(*what, Race, planet, sector, x, y, buf) &&
854  !Race->God) {
855  notify(Playernum, Governor, buf);
856  return;
857  }
858  if (!(count = getcount(argv, 4))) {
859  g.out << "Give a positive number of builds.\n";
860  return;
861  }
862  Getship(&newship, *what, Race);
863  }
864  if ((shipcost = newship.build_cost) >
865  planet.info[Playernum - 1].resource) {
866  sprintf(buf, "You need %dr to construct this ship.\n", shipcost);
867  notify(Playernum, Governor, buf);
868  goto finish;
869  }
870  create_ship_by_planet(Playernum, Governor, Race, &newship, &planet,
871  snum, pnum, x, y);
872  if (Race->governor[Governor].toggle.autoload &&
873  what != ShipType::OTYPE_TRANSDEV && !Race->God)
874  autoload_at_planet(Playernum, &newship, &planet, sector, &load_crew,
875  &load_fuel);
876  else {
877  load_crew = 0;
878  load_fuel = 0.0;
879  }
880  initialize_new_ship(g, Race, &newship, load_fuel, load_crew);
881  putship(&newship);
882  break;
883  case ScopeLevel::LEVEL_SHIP:
884  if (!count) { /* initialize loop variables */
885  builder = getship(g.shipno);
886  outside = 0;
887  auto test_build_level = build_at_ship(g, &*builder, &snum, &pnum);
888  if (!test_build_level) {
889  g.out << "You can't build here.\n";
890  return;
891  }
892  build_level = test_build_level.value();
893  switch (builder->type) {
894  case ShipType::OTYPE_FACTORY:
895  if (!(count = getcount(argv, 2))) {
896  g.out << "Give a positive number of builds.\n";
897  return;
898  }
899  if (!landed(*builder)) {
900  g.out << "Factories can only build when landed on a planet.\n";
901  return;
902  }
903  Getfactship(&newship, &*builder);
904  outside = 1;
905  break;
906  case ShipType::STYPE_SHUTTLE:
907  case ShipType::STYPE_CARGO:
908  if (landed(*builder)) {
909  g.out << "This ships cannot build when landed.\n";
910  return;
911  }
912  outside = 1;
913  [[clang::fallthrough]]; // TODO(jeffbailey): Added this to
914  // silence
915  // warning, check it.
916  default:
917  if (argv.size() < 2) {
918  g.out << "Build what?\n";
919  return;
920  }
921  if ((what = get_build_type(argv[1][0])) < 0) {
922  g.out << "No such ship type.\n";
923  return;
924  }
925  if (!can_build_on_ship(*what, Race, &*builder, buf)) {
926  notify(Playernum, Governor, buf);
927  return;
928  }
929  if (!(count = getcount(argv, 3))) {
930  g.out << "Give a positive number of builds.\n";
931  return;
932  }
933  Getship(&newship, *what, Race);
934  break;
935  }
936  if ((tech = builder->type == ShipType::OTYPE_FACTORY
937  ? complexity(*builder)
938  : Shipdata[*what][ABIL_TECH]) > Race->tech &&
939  !Race->God) {
940  sprintf(buf,
941  "You are not advanced enough to build this ship.\n%.1f "
942  "enginering technology needed. You have %.1f.\n",
943  tech, Race->tech);
944  notify(Playernum, Governor, buf);
945  return;
946  }
947  if (outside && build_level == ScopeLevel::LEVEL_PLAN) {
948  planet = getplanet(snum, pnum);
949  if (builder->type == ShipType::OTYPE_FACTORY) {
950  if (!can_build_at_planet(g, Stars[snum], planet)) {
951  g.out << "You can't build that here.\n";
952  return;
953  }
954  x = builder->land_x;
955  y = builder->land_y;
956  what = builder->build_type;
957  sector = getsector(planet, x, y);
958  if (!can_build_on_sector(*what, Race, planet, sector, x, y,
959  buf)) {
960  notify(Playernum, Governor, buf);
961  return;
962  }
963  }
964  }
965  }
966  /* build 'em */
967  switch (builder->type) {
968  case ShipType::OTYPE_FACTORY:
969  if ((shipcost = newship.build_cost) >
970  planet.info[Playernum - 1].resource) {
971  sprintf(buf, "You need %dr to construct this ship.\n", shipcost);
972  notify(Playernum, Governor, buf);
973  goto finish;
974  }
975  create_ship_by_planet(Playernum, Governor, Race, &newship, &planet,
976  snum, pnum, x, y);
977  if (Race->governor[Governor].toggle.autoload &&
978  what != ShipType::OTYPE_TRANSDEV && !Race->God) {
979  autoload_at_planet(Playernum, &newship, &planet, sector,
980  &load_crew, &load_fuel);
981  } else {
982  load_crew = 0;
983  load_fuel = 0.0;
984  }
985  break;
986  case ShipType::STYPE_SHUTTLE:
987  case ShipType::STYPE_CARGO:
988  if (builder->resource < (shipcost = newship.build_cost)) {
989  sprintf(buf, "You need %dr to construct the ship.\n", shipcost);
990  notify(Playernum, Governor, buf);
991  goto finish;
992  }
993  create_ship_by_ship(Playernum, Governor, Race, 1, &planet, &newship,
994  &*builder);
995  if (Race->governor[Governor].toggle.autoload &&
996  what != ShipType::OTYPE_TRANSDEV && !Race->God)
997  autoload_at_ship(&newship, &*builder, &load_crew, &load_fuel);
998  else {
999  load_crew = 0;
1000  load_fuel = 0.0;
1001  }
1002  break;
1003  default:
1004  if (builder->hanger + ship_size(newship) > builder->max_hanger) {
1005  g.out << "Not enough hanger space.\n";
1006  goto finish;
1007  }
1008  if (builder->resource < (shipcost = newship.build_cost)) {
1009  sprintf(buf, "You need %dr to construct the ship.\n", shipcost);
1010  notify(Playernum, Governor, buf);
1011  goto finish;
1012  }
1013  create_ship_by_ship(Playernum, Governor, Race, 0, nullptr, &newship,
1014  &*builder);
1015  if (Race->governor[Governor].toggle.autoload &&
1016  what != ShipType::OTYPE_TRANSDEV && !Race->God)
1017  autoload_at_ship(&newship, &*builder, &load_crew, &load_fuel);
1018  else {
1019  load_crew = 0;
1020  load_fuel = 0.0;
1021  }
1022  break;
1023  }
1024  initialize_new_ship(g, Race, &newship, load_fuel, load_crew);
1025  putship(&newship);
1026  break;
1027  default:
1028  // Shouldn't be possible.
1029  break;
1030  }
1031  count--;
1032  } while (count);
1033 /* free stuff */
1034 finish:
1035  switch (level) {
1036  case ScopeLevel::LEVEL_PLAN:
1037  putsector(sector, planet, x, y);
1038  putplanet(planet, Stars[snum], pnum);
1039  break;
1040  case ScopeLevel::LEVEL_SHIP:
1041  if (outside) switch (build_level) {
1042  case ScopeLevel::LEVEL_PLAN:
1043  putplanet(planet, Stars[snum], pnum);
1044  if (landed(*builder)) {
1045  putsector(sector, planet, x, y);
1046  }
1047  break;
1048  case ScopeLevel::LEVEL_STAR:
1049  putstar(Stars[snum], snum);
1050  break;
1051  case ScopeLevel::LEVEL_UNIV:
1052  putsdata(&Sdata);
1053  break;
1054  default:
1055  break;
1056  }
1057  putship(&*builder);
1058  break;
1059  default:
1060  // Shouldn't be possible.
1061  break;
1062  }
1063 }
1064 
1065 // Used for optional parameters. If the element requested exists, use
1066 // it. If the number is negative, return zero instead.
1067 static int getcount(const command_t &argv, const size_t elem) {
1068  int count = argv.size() > elem ? std::stoi(argv[elem]) : 1;
1069  if (count <= 0) count = 0;
1070  return (count);
1071 }
1072 
1073 static int can_build_at_planet(GameObj &g, startype *star,
1074  const Planet &planet) {
1075  player_t Playernum = g.player;
1076  governor_t Governor = g.governor;
1077  if (planet.slaved_to && planet.slaved_to != Playernum) {
1078  sprintf(buf, "This planet is enslaved by player %d.\n", planet.slaved_to);
1079  notify(Playernum, Governor, buf);
1080  return (0);
1081  }
1082  if (Governor && star->governor[Playernum - 1] != Governor) {
1083  g.out << "You are not authorized in this system.\n";
1084  return (0);
1085  }
1086  return (1);
1087 }
1088 
1089 static std::optional<ShipType> get_build_type(const char shipc) {
1090  for (int i = 0; i < std::extent<decltype(Shipltrs)>::value; ++i) {
1091  if (Shipltrs[i] == shipc) return ShipType{i};
1092  }
1093  return {};
1094 }
1095 
1096 static bool can_build_this(const ShipType what, const Race &race,
1097  char *string) {
1098  if (what == ShipType::STYPE_POD && !race.pods) {
1099  sprintf(string, "Only Metamorphic races can build Spore Pods.\n");
1100  return false;
1101  }
1102  if (!Shipdata[what][ABIL_PROGRAMMED]) {
1103  sprintf(string, "This ship type has not been programmed.\n");
1104  return false;
1105  }
1106  if (Shipdata[what][ABIL_GOD] && !race.God) {
1107  sprintf(string, "Only Gods can build this type of ship.\n");
1108  return false;
1109  }
1110  if (what == ShipType::OTYPE_VN && !Vn(&race)) {
1111  sprintf(string, "You have not discovered VN technology.\n");
1112  return false;
1113  }
1114  if (what == ShipType::OTYPE_TRANSDEV && !Avpm(&race)) {
1115  sprintf(string, "You have not discovered AVPM technology.\n");
1116  return false;
1117  }
1118  if (Shipdata[what][ABIL_TECH] > race.tech && !race.God) {
1119  sprintf(string,
1120  "You are not advanced enough to build this ship.\n%.1f "
1121  "enginering technology needed. You have %.1f.\n",
1122  (double)Shipdata[what][ABIL_TECH], race.tech);
1123  return false;
1124  }
1125  return true;
1126 }
1127 
1128 static int can_build_on_ship(int what, racetype *Race, Ship *builder,
1129  char *string) {
1130  if (!(Shipdata[what][ABIL_BUILD] & Shipdata[builder->type][ABIL_CONSTRUCT]) &&
1131  !Race->God) {
1132  sprintf(string, "This ship type cannot be built by a %s.\n",
1133  Shipnames[builder->type]);
1134  sprintf(temp, "Use 'build ? %c' to find out where it can be built.\n",
1135  Shipltrs[what]);
1136  strcat(string, temp);
1137  return (0);
1138  }
1139  return (1);
1140 }
1141 
1142 static std::optional<ScopeLevel> build_at_ship(GameObj &g, Ship *builder,
1143  int *snum, int *pnum) {
1144  player_t Playernum = g.player;
1145  governor_t Governor = g.governor;
1146  if (testship(Playernum, Governor, *builder)) return {};
1147  if (!Shipdata[builder->type][ABIL_CONSTRUCT]) {
1148  g.out << "This ship cannot construct other ships.\n";
1149  return {};
1150  }
1151  if (!builder->popn) {
1152  g.out << "This ship has no crew.\n";
1153  return {};
1154  }
1155  if (docked(builder)) {
1156  g.out << "Undock this ship first.\n";
1157  return {};
1158  }
1159  if (builder->damage) {
1160  g.out << "This ship is damaged and cannot build.\n";
1161  return {};
1162  }
1163  if (builder->type == ShipType::OTYPE_FACTORY && !builder->on) {
1164  g.out << "This factory is not online.\n";
1165  return {};
1166  }
1167  if (builder->type == ShipType::OTYPE_FACTORY && !landed(*builder)) {
1168  g.out << "Factories must be landed on a planet.\n";
1169  return {};
1170  }
1171  *snum = builder->storbits;
1172  *pnum = builder->pnumorbits;
1173  return (builder->whatorbits);
1174 }
1175 
1176 static void autoload_at_planet(int Playernum, Ship *s, Planet *planet,
1177  Sector &sector, int *crew, double *fuel) {
1178  *crew = MIN(s->max_crew, sector.popn);
1179  *fuel = MIN((double)s->max_fuel, (double)planet->info[Playernum - 1].fuel);
1180  sector.popn -= *crew;
1181  if (!sector.popn && !sector.troops) sector.owner = 0;
1182  planet->info[Playernum - 1].fuel -= (int)(*fuel);
1183 }
1184 
1185 static void autoload_at_ship(Ship *s, Ship *b, int *crew, double *fuel) {
1186  *crew = MIN(s->max_crew, b->popn);
1187  *fuel = MIN((double)s->max_fuel, (double)b->fuel);
1188  b->popn -= *crew;
1189  b->fuel -= *fuel;
1190 }
1191 
1192 static void initialize_new_ship(GameObj &g, racetype *Race, Ship *newship,
1193  double load_fuel, int load_crew) {
1194  player_t Playernum = g.player;
1195  governor_t Governor = g.governor;
1196  newship->speed = newship->max_speed;
1197  newship->owner = Playernum;
1198  newship->governor = Governor;
1199  newship->fuel = Race->God ? newship->max_fuel : load_fuel;
1200  newship->popn = Race->God ? newship->max_crew : load_crew;
1201  newship->troops = 0;
1202  newship->resource = Race->God ? newship->max_resource : 0;
1203  newship->destruct = Race->God ? newship->max_destruct : 0;
1204  newship->crystals = 0;
1205  newship->hanger = 0;
1206  newship->mass = newship->base_mass + (double)newship->popn * Race->mass +
1207  (double)newship->fuel * MASS_FUEL +
1208  (double)newship->resource * MASS_RESOURCE +
1209  (double)newship->destruct * MASS_DESTRUCT;
1210  newship->alive = 1;
1211  newship->active = 1;
1212  newship->protect.self = newship->guns ? 1 : 0;
1213  newship->hyper_drive.on = 0;
1214  newship->hyper_drive.ready = 0;
1215  newship->hyper_drive.charge = 0;
1216  newship->mounted = Race->God ? newship->mount : 0;
1217  newship->cloak = 0;
1218  newship->cloaked = 0;
1219  newship->fire_laser = 0;
1220  newship->mode = 0;
1221  newship->rad = 0;
1222  newship->damage = Race->God ? 0 : Shipdata[newship->type][ABIL_DAMAGE];
1223  newship->retaliate = newship->primary;
1224  newship->ships = 0;
1225  newship->on = 0;
1226  switch (newship->type) {
1227  case ShipType::OTYPE_VN:
1228  newship->special.mind.busy = 1;
1229  newship->special.mind.progenitor = Playernum;
1230  newship->special.mind.generation = 1;
1231  newship->special.mind.target = 0;
1232  newship->special.mind.tampered = 0;
1233  break;
1234  case ShipType::STYPE_MINE:
1235  newship->special.trigger.radius = 100; /* trigger radius */
1236  g.out << "Mine disarmed.\nTrigger radius set at 100.\n";
1237  break;
1238  case ShipType::OTYPE_TRANSDEV:
1239  newship->special.transport.target = 0;
1240  newship->on = 0;
1241  g.out << "Receive OFF. Change with order.\n";
1242  break;
1243  case ShipType::OTYPE_AP:
1244  g.out << "Processor OFF.\n";
1245  break;
1246  case ShipType::OTYPE_STELE:
1247  case ShipType::OTYPE_GTELE:
1248  sprintf(buf, "Telescope range is %.2f.\n",
1249  tele_range(newship->type, newship->tech));
1250  notify(Playernum, Governor, buf);
1251  break;
1252  default:
1253  break;
1254  }
1255  if (newship->damage) {
1256  sprintf(buf,
1257  "Warning: This ship is constructed with a %d%% damage level.\n",
1258  newship->damage);
1259  notify(Playernum, Governor, buf);
1260  if (!Shipdata[newship->type][ABIL_REPAIR] && newship->max_crew)
1261  notify(Playernum, Governor,
1262  "It will need resources to become fully operational.\n");
1263  }
1264  if (Shipdata[newship->type][ABIL_REPAIR] && newship->max_crew)
1265  g.out << "This ship does not need resources to repair.\n";
1266  if (newship->type == ShipType::OTYPE_FACTORY)
1267  g.out
1268  << "This factory may not begin repairs until it has been activated.\n";
1269  if (!newship->max_crew)
1270  g.out << "This ship is robotic, and may not repair itself.\n";
1271  sprintf(buf, "Loaded with %d crew and %.1f fuel.\n", load_crew, load_fuel);
1272  notify(Playernum, Governor, buf);
1273 }
1274 
1275 static void create_ship_by_planet(int Playernum, int Governor, racetype *Race,
1276  Ship *newship, Planet *planet, int snum,
1277  int pnum, int x, int y) {
1278  int shipno;
1279 
1280  newship->tech = Race->tech;
1281  newship->xpos = Stars[snum]->xpos + planet->xpos;
1282  newship->ypos = Stars[snum]->ypos + planet->ypos;
1283  newship->land_x = x;
1284  newship->land_y = y;
1285  sprintf(newship->shipclass, (((newship->type == ShipType::OTYPE_TERRA) ||
1286  (newship->type == ShipType::OTYPE_PLOW))
1287  ? "5"
1288  : "Standard"));
1289  newship->whatorbits = ScopeLevel::LEVEL_PLAN;
1290  newship->whatdest = ScopeLevel::LEVEL_PLAN;
1291  newship->deststar = snum;
1292  newship->destpnum = pnum;
1293  newship->storbits = snum;
1294  newship->pnumorbits = pnum;
1295  newship->docked = 1;
1296  planet->info[Playernum - 1].resource -= newship->build_cost;
1297  while ((shipno = getdeadship()) == 0)
1298  ;
1299  if (shipno == -1) shipno = Numships() + 1;
1300  newship->number = shipno;
1301  newship->owner = Playernum;
1302  newship->governor = Governor;
1303  newship->ships = 0;
1304  insert_sh_plan(planet, newship);
1305  if (newship->type == ShipType::OTYPE_TOXWC) {
1306  sprintf(buf, "Toxin concentration on planet was %d%%,",
1307  planet->conditions[TOXIC]);
1308  notify(Playernum, Governor, buf);
1309  if (planet->conditions[TOXIC] > TOXMAX)
1310  newship->special.waste.toxic = TOXMAX;
1311  else
1312  newship->special.waste.toxic = planet->conditions[TOXIC];
1313  planet->conditions[TOXIC] -= newship->special.waste.toxic;
1314  sprintf(buf, " now %d%%.\n", planet->conditions[TOXIC]);
1315  notify(Playernum, Governor, buf);
1316  }
1317  sprintf(buf, "%s built at a cost of %d resources.\n",
1318  ship_to_string(*newship).c_str(), newship->build_cost);
1319  notify(Playernum, Governor, buf);
1320  sprintf(buf, "Technology %.1f.\n", newship->tech);
1321  notify(Playernum, Governor, buf);
1322  sprintf(buf, "%s is on sector %d,%d.\n", ship_to_string(*newship).c_str(),
1323  newship->land_x, newship->land_y);
1324  notify(Playernum, Governor, buf);
1325 }
1326 
1327 static void create_ship_by_ship(int Playernum, int Governor, racetype *Race,
1328  int outside, Planet *planet, Ship *newship,
1329  Ship *builder) {
1330  int shipno;
1331 
1332  while ((shipno = getdeadship()) == 0)
1333  ;
1334  if (shipno == -1) shipno = Numships() + 1;
1335  newship->number = shipno;
1336  newship->owner = Playernum;
1337  newship->governor = Governor;
1338  if (outside) {
1339  newship->whatorbits = builder->whatorbits;
1340  newship->whatdest = ScopeLevel::LEVEL_UNIV;
1341  newship->deststar = builder->deststar;
1342  newship->destpnum = builder->destpnum;
1343  newship->storbits = builder->storbits;
1344  newship->pnumorbits = builder->pnumorbits;
1345  newship->docked = 0;
1346  switch (builder->whatorbits) {
1347  case ScopeLevel::LEVEL_PLAN:
1348  insert_sh_plan(planet, newship);
1349  break;
1350  case ScopeLevel::LEVEL_STAR:
1351  insert_sh_star(Stars[builder->storbits], newship);
1352  break;
1353  case ScopeLevel::LEVEL_UNIV:
1354  insert_sh_univ(&Sdata, newship);
1355  break;
1356  case ScopeLevel::LEVEL_SHIP:
1357  // TODO(jeffbailey): The compiler can't see that this is impossible.
1358  break;
1359  }
1360  } else {
1361  newship->whatorbits = ScopeLevel::LEVEL_SHIP;
1362  newship->whatdest = ScopeLevel::LEVEL_SHIP;
1363  newship->deststar = builder->deststar;
1364  newship->destpnum = builder->destpnum;
1365  newship->destshipno = builder->number;
1366  newship->storbits = builder->storbits;
1367  newship->pnumorbits = builder->pnumorbits;
1368  newship->docked = 1;
1369  insert_sh_ship(newship, builder);
1370  }
1371  newship->tech = Race->tech;
1372  newship->xpos = builder->xpos;
1373  newship->ypos = builder->ypos;
1374  newship->land_x = builder->land_x;
1375  newship->land_y = builder->land_y;
1376  sprintf(newship->shipclass, (((newship->type == ShipType::OTYPE_TERRA) ||
1377  (newship->type == ShipType::OTYPE_PLOW))
1378  ? "5"
1379  : "Standard"));
1380  builder->resource -= newship->build_cost;
1381 
1382  sprintf(buf, "%s built at a cost of %d resources.\n",
1383  ship_to_string(*newship).c_str(), newship->build_cost);
1384  notify(Playernum, Governor, buf);
1385  sprintf(buf, "Technology %.1f.\n", newship->tech);
1386  notify(Playernum, Governor, buf);
1387 }
1388 
1389 static void Getship(Ship *s, ShipType i, Race *r) {
1390  bzero((char *)s, sizeof(Ship));
1391  s->type = i;
1392  s->armor = Shipdata[i][ABIL_ARMOR];
1393  s->guns = Shipdata[i][ABIL_PRIMARY] ? PRIMARY : GTYPE_NONE;
1394  s->primary = Shipdata[i][ABIL_GUNS];
1395  s->primtype = Shipdata[i][ABIL_PRIMARY];
1396  s->secondary = Shipdata[i][ABIL_GUNS];
1397  s->sectype = Shipdata[i][ABIL_SECONDARY];
1398  s->max_crew = Shipdata[i][ABIL_MAXCREW];
1399  s->max_resource = Shipdata[i][ABIL_CARGO];
1400  s->max_hanger = Shipdata[i][ABIL_HANGER];
1401  s->max_destruct = Shipdata[i][ABIL_DESTCAP];
1402  s->max_fuel = Shipdata[i][ABIL_FUELCAP];
1403  s->max_speed = Shipdata[i][ABIL_SPEED];
1404  s->build_type = i;
1405  s->mount = r->God ? Shipdata[i][ABIL_MOUNT] : 0;
1406  s->hyper_drive.has = r->God ? Shipdata[i][ABIL_JUMP] : 0;
1407  s->cloak = 0;
1408  s->laser = r->God ? Shipdata[i][ABIL_LASER] : 0;
1409  s->cew = 0;
1410  s->cew_range = 0;
1411  s->size = ship_size(*s);
1412  s->base_mass = getmass(*s);
1413  s->mass = getmass(*s);
1414  s->build_cost = r->God ? 0 : (int)cost(*s);
1415  if (s->type == ShipType::OTYPE_VN || s->type == ShipType::OTYPE_BERS)
1416  s->special.mind.progenitor = r->Playernum;
1417 }
1418 
1419 static void Getfactship(Ship *s, Ship *b) {
1420  bzero((char *)s, sizeof(Ship));
1421  s->type = b->build_type;
1422  s->armor = b->armor;
1423  s->primary = b->primary;
1424  s->primtype = b->primtype;
1425  s->secondary = b->secondary;
1426  s->sectype = b->sectype;
1427  s->guns = s->primary ? PRIMARY : GTYPE_NONE;
1428  s->max_crew = b->max_crew;
1429  s->max_resource = b->max_resource;
1430  s->max_hanger = b->max_hanger;
1431  s->max_destruct = b->max_destruct;
1432  s->max_fuel = b->max_fuel;
1433  s->max_speed = b->max_speed;
1434  s->build_type = b->build_type;
1435  s->build_cost = b->build_cost;
1436  s->mount = b->mount;
1437  s->hyper_drive.has = b->hyper_drive.has;
1438  s->cloak = 0;
1439  s->laser = b->laser;
1440  s->cew = b->cew;
1441  s->cew_range = b->cew_range;
1442  s->size = ship_size(*s);
1443  s->base_mass = getmass(*s);
1444  s->mass = getmass(*s);
1445 }
1446 
1447 int Shipcost(ShipType i, Race *r) {
1448  Ship s;
1449 
1450  Getship(&s, i, r);
1451  return ((int)cost(s));
1452 }
1453 
1454 #ifdef MARKET
1455 void sell(const command_t &argv, GameObj &g) {
1456  const player_t Playernum = g.player;
1457  const governor_t Governor = g.governor;
1458  int APcount = 20;
1459  racetype *Race;
1460  commodtype c;
1461  int commodno;
1462  int amount;
1463  int item;
1464  char commod;
1465  int snum;
1466  int pnum;
1467 
1468  if (g.level != ScopeLevel::LEVEL_PLAN) {
1469  g.out << "You have to be in a planet scope to sell.\n";
1470  return;
1471  }
1472  snum = g.snum;
1473  pnum = g.pnum;
1474  if (argv.size() < 3) {
1475  g.out << "Syntax: sell <commodity> <amount>\n";
1476  return;
1477  }
1478  if (Governor && Stars[snum]->governor[Playernum - 1] != Governor) {
1479  g.out << "You are not authorized in this system.\n";
1480  return;
1481  }
1482  Race = races[Playernum - 1];
1483  if (Race->Guest) {
1484  g.out << "Guest races can't sell anything.\n";
1485  return;
1486  }
1487  /* get information on sale */
1488  commod = argv[1][0];
1489  amount = std::stoi(argv[2]);
1490  if (amount <= 0) {
1491  g.out << "Try using positive values.\n";
1492  return;
1493  }
1494  APcount = MIN(APcount, amount);
1495  if (!enufAP(Playernum, Governor, Stars[snum]->AP[Playernum - 1], APcount))
1496  return;
1497  auto p = getplanet(snum, pnum);
1498 
1499  if (p.slaved_to && p.slaved_to != Playernum) {
1500  sprintf(buf, "This planet is enslaved to player %d.\n", p.slaved_to);
1501  notify(Playernum, Governor, buf);
1502  return;
1503  }
1504  /* check to see if there is an undamage gov center or space port here */
1505  bool ok = false;
1506  Shiplist shiplist(p.ships);
1507  for (auto s : shiplist) {
1508  if (s.alive && (s.owner == Playernum) && !s.damage &&
1509  Shipdata[s.type][ABIL_PORT]) {
1510  ok = true;
1511  break;
1512  }
1513  }
1514  if (!ok) {
1515  g.out << "You don't have an undamaged space port or government center "
1516  "here.\n";
1517  return;
1518  }
1519  switch (commod) {
1520  case 'r':
1521  if (!p.info[Playernum - 1].resource) {
1522  g.out << "You don't have any resources here to sell!\n";
1523  return;
1524  }
1525  amount = MIN(amount, p.info[Playernum - 1].resource);
1526  p.info[Playernum - 1].resource -= amount;
1527  item = RESOURCE;
1528  break;
1529  case 'd':
1530  if (!p.info[Playernum - 1].destruct) {
1531  g.out << "You don't have any destruct here to sell!\n";
1532  return;
1533  }
1534  amount = MIN(amount, p.info[Playernum - 1].destruct);
1535  p.info[Playernum - 1].destruct -= amount;
1536  item = DESTRUCT;
1537  break;
1538  case 'f':
1539  if (!p.info[Playernum - 1].fuel) {
1540  g.out << "You don't have any fuel here to sell!\n";
1541  return;
1542  }
1543  amount = MIN(amount, p.info[Playernum - 1].fuel);
1544  p.info[Playernum - 1].fuel -= amount;
1545  item = FUEL;
1546  break;
1547  case 'x':
1548  if (!p.info[Playernum - 1].crystals) {
1549  g.out << "You don't have any crystals here to sell!\n";
1550  return;
1551  }
1552  amount = MIN(amount, p.info[Playernum - 1].crystals);
1553  p.info[Playernum - 1].crystals -= amount;
1554  item = CRYSTAL;
1555  break;
1556  default:
1557  g.out << "Permitted commodities are r, d, f, and x.\n";
1558  return;
1559  }
1560 
1561  c.owner = Playernum;
1562  c.governor = Governor;
1563  c.type = item;
1564  c.amount = amount;
1565  c.deliver = 0;
1566  c.bid = 0;
1567  c.bidder = 0;
1568  c.star_from = snum;
1569  c.planet_from = pnum;
1570 
1571  while ((commodno = getdeadcommod()) == 0)
1572  ;
1573 
1574  if (commodno == -1) commodno = Numcommods() + 1;
1575  sprintf(buf, "Lot #%d - %d units of %s.\n", commodno, amount, Commod[item]);
1576  notify(Playernum, Governor, buf);
1577  sprintf(buf, "Lot #%d - %d units of %s for sale by %s [%d].\n", commodno,
1578  amount, Commod[item], races[Playernum - 1]->name, Playernum);
1579  post(buf, TRANSFER);
1580  for (player_t i = 1; i <= Num_races; i++) notify_race(i, buf);
1581  putcommod(&c, commodno);
1582  putplanet(p, Stars[snum], pnum);
1583  deductAPs(Playernum, Governor, APcount, snum, 0);
1584 }
1585 
1586 void bid(const command_t &argv, GameObj &g) {
1587  const player_t Playernum = g.player;
1588  const governor_t Governor = g.governor;
1589  racetype *Race;
1590  Planet p;
1591  commodtype *c;
1592  char commod;
1593  int i;
1594  int item;
1595  int lot;
1596  int shipping;
1597  double dist;
1598  double rate;
1599  int snum;
1600  int pnum;
1601 
1602  if (argv.size() == 1) {
1603  /* list all market blocks for sale */
1604  notify(Playernum, Governor,
1605  "+++ Galactic Bloodshed Commodities Market +++\n\n");
1606  notify(Playernum, Governor,
1607  " Lot Stock Type Owner Bidder Amount "
1608  "Cost/Unit Ship Dest\n");
1609  for (i = 1; i <= Numcommods(); i++) {
1610  getcommod(&c, i);
1611  if (c->owner && c->amount) {
1612  rate = (double)c->bid / (double)c->amount;
1613  if (c->bidder == Playernum)
1614  sprintf(temp, "%4.4s/%-4.4s", Stars[c->star_to]->name,
1615  Stars[c->star_to]->pnames[c->planet_to]);
1616  else
1617  temp[0] = '\0';
1618  sprintf(
1619  buf, " %4d%c%5lu%10s%7d%8d%8ld%10.2f%8d %10s\n", i,
1620  c->deliver ? '*' : ' ', c->amount, Commod[c->type], c->owner,
1621  c->bidder, c->bid, rate,
1622  shipping_cost((int)c->star_from, (int)g.snum, &dist, (int)c->bid),
1623  temp);
1624  notify(Playernum, Governor, buf);
1625  }
1626  free(c);
1627  }
1628  } else if (argv.size() == 2) {
1629  /* list all market blocks for sale of the requested type */
1630  commod = argv[1][0];
1631  switch (commod) {
1632  case 'r':
1633  item = RESOURCE;
1634  break;
1635  case 'd':
1636  item = DESTRUCT;
1637  break;
1638  case 'f':
1639  item = FUEL;
1640  break;
1641  case 'x':
1642  item = CRYSTAL;
1643  break;
1644  default:
1645  g.out << "No such type of commodity.\n";
1646  return;
1647  }
1648  g.out << "+++ Galactic Bloodshed Commodities Market +++\n\n";
1649  g.out << " Lot Stock Type Owner Bidder Amount "
1650  "Cost/Unit Ship Dest\n";
1651  for (i = 1; i <= Numcommods(); i++) {
1652  getcommod(&c, i);
1653  if (c->owner && c->amount && (c->type == item)) {
1654  rate = (double)c->bid / (double)c->amount;
1655  if (c->bidder == Playernum)
1656  sprintf(temp, "%4.4s/%-4.4s", Stars[c->star_to]->name,
1657  Stars[c->star_to]->pnames[c->planet_to]);
1658  else
1659  temp[0] = '\0';
1660  sprintf(
1661  buf, " %4d%c%5lu%10s%7d%8d%8ld%10.2f%8d %10s\n", i,
1662  c->deliver ? '*' : ' ', c->amount, Commod[c->type], c->owner,
1663  c->bidder, c->bid, rate,
1664  shipping_cost((int)c->star_from, (int)g.snum, &dist, (int)c->bid),
1665  temp);
1666  notify(Playernum, Governor, buf);
1667  }
1668  free(c);
1669  }
1670  } else {
1671  if (g.level != ScopeLevel::LEVEL_PLAN) {
1672  g.out << "You have to be in a planet scope to buy.\n";
1673  return;
1674  }
1675  snum = g.snum;
1676  pnum = g.pnum;
1677  if (Governor && Stars[snum]->governor[Playernum - 1] != Governor) {
1678  g.out << "You are not authorized in this system.\n";
1679  return;
1680  }
1681  p = getplanet(snum, pnum);
1682 
1683  if (p.slaved_to && p.slaved_to != Playernum) {
1684  sprintf(buf, "This planet is enslaved to player %d.\n", p.slaved_to);
1685  notify(Playernum, Governor, buf);
1686  return;
1687  }
1688  /* check to see if there is an undamaged gov center or space port here */
1689  Shiplist shiplist(p.ships);
1690  bool ok = false;
1691  for (auto s : shiplist) {
1692  if (s.alive && (s.owner == Playernum) && !s.damage &&
1693  Shipdata[s.type][ABIL_PORT]) {
1694  ok = true;
1695  break;
1696  }
1697  }
1698  if (!ok) {
1699  g.out << "You don't have an undamaged space port or "
1700  "government center here.\n";
1701  return;
1702  }
1703 
1704  lot = std::stoi(argv[1]);
1705  money_t bid0 = std::stoi(argv[2]);
1706  if ((lot <= 0) || lot > Numcommods()) {
1707  g.out << "Illegal lot number.\n";
1708  return;
1709  }
1710  getcommod(&c, lot);
1711  if (!c->owner) {
1712  g.out << "No such lot for sale.\n";
1713  free(c);
1714  return;
1715  }
1716  if (c->owner == g.player &&
1717  (c->star_from != g.snum || c->planet_from != g.pnum)) {
1718  g.out << "You can only set a minimum price for your "
1719  "lot from the location it was sold.\n";
1720  free(c);
1721  return;
1722  }
1723  money_t minbid = (int)((double)c->bid * (1.0 + UP_BID));
1724  if (bid0 < minbid) {
1725  sprintf(buf, "You have to bid more than %ld.\n", minbid);
1726  notify(Playernum, Governor, buf);
1727  free(c);
1728  return;
1729  }
1730  Race = races[Playernum - 1];
1731  if (Race->Guest) {
1732  g.out << "Guest races cannot bid.\n";
1733  free(c);
1734  return;
1735  }
1736  if (bid0 > Race->governor[Governor].money) {
1737  g.out << "Sorry, no buying on credit allowed.\n";
1738  free(c);
1739  return;
1740  }
1741  /* notify the previous bidder that he was just outbidded */
1742  if (c->bidder) {
1743  sprintf(buf,
1744  "The bid on lot #%d (%lu %s) has been upped to %ld by %s [%d].\n",
1745  lot, c->amount, Commod[c->type], bid0, Race->name, Playernum);
1746  notify((int)c->bidder, (int)c->bidder_gov, buf);
1747  }
1748  c->bid = bid0;
1749  c->bidder = Playernum;
1750  c->bidder_gov = Governor;
1751  c->star_to = snum;
1752  c->planet_to = pnum;
1753  shipping =
1754  shipping_cost((int)c->star_to, (int)c->star_from, &dist, (int)c->bid);
1755 
1756  sprintf(
1757  buf,
1758  "There will be an additional %d charged to you for shipping costs.\n",
1759  shipping);
1760  notify(Playernum, Governor, buf);
1761  putcommod(c, lot);
1762  g.out << "Bid accepted.\n";
1763  free(c);
1764  }
1765 }
1766 
1767 int shipping_cost(int to, int from, double *dist, int value) {
1768  double factor;
1769  double fcost;
1770  int junk;
1771 
1772  *dist = sqrt(Distsq(Stars[to]->xpos, Stars[to]->ypos, Stars[from]->xpos,
1773  Stars[from]->ypos));
1774 
1775  junk = (int)(*dist / 10000.0);
1776  junk *= 10000;
1777 
1778  factor = 1.0 - exp(-(double)junk / MERCHANT_LENGTH);
1779 
1780  fcost = factor * (double)value;
1781  return (int)fcost;
1782 }
1783 #endif
#define MASS_FUEL
Definition: tweakables.h:98
#define Vn(r)
Definition: races.h:116
#define Distsq(x1, y1, x2, y2)
Definition: tweakables.h:218
void post(const char *origmsg, int type)
Definition: tele.cc:63
int getdeadcommod()
Definition: files_shl.cc:777
#define Cloak(r)
Definition: races.h:120
static int can_build_at_planet(GameObj &, startype *, const Planet &)
Definition: build.cc:1073
#define MASS_DESTRUCT
Definition: tweakables.h:100
#define RESOURCE
Definition: tweakables.h:268
static void Getfactship(Ship *, Ship *)
Definition: build.cc:1419
void bid(const command_t &argv, GameObj &g)
Definition: build.cc:1586
int Shipcost(ShipType i, Race *r)
Definition: build.cc:1447
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
static std::optional< ShipType > get_build_type(const char)
Definition: build.cc:1089
bool can_build_on_sector(const int what, const racetype *Race, const Planet &planet, const Sector &sector, const int x, const int y, char *string)
Definition: build.cc:51
#define EXAM_FL
Definition: files.h:24
#define Crystal(r)
Definition: races.h:122
int Numcommods()
Definition: files_shl.cc:1533
#define TRANSFER
Definition: files.h:18
void putsector(const Sector &s, const Planet &p, const int x, const int y)
Definition: files_shl.cc:1076
int docked(Ship *s)
Definition: land.cc:422
void sell(const command_t &argv, GameObj &g)
Definition: build.cc:1455
static void autoload_at_planet(int, Ship *, Planet *, Sector &, int *, double *)
Definition: build.cc:1176
void build(const command_t &argv, GameObj &g)
Definition: build.cc:673
shipnum_t Numships()
Definition: files_shl.cc:1516
#define Cew(r)
Definition: races.h:115
void make_mod(const command_t &argv, GameObj &g)
Definition: build.cc:317
#define PRIMARY
Definition: ships.h:15
#define MIN(x, y)
Definition: tweakables.h:213
#define TOXIC
Definition: tweakables.h:39
#define MERCHANT_LENGTH
Definition: tweakables.h:273
void upgrade(const command_t &argv, GameObj &g)
Definition: build.cc:89
static void initialize_new_ship(GameObj &g, racetype *Race, Ship *newship, double load_fuel, int load_crew)
Definition: build.cc:1192
#define UP_BID
Definition: tweakables.h:276
void putcommod(commodtype *c, int commodnum)
Definition: files_shl.cc:1504
#define MARKET
Definition: config.h:27
#define CRYSTAL
Definition: tweakables.h:271
#define Hyper_drive(r)
Definition: races.h:113
void deductAPs(const player_t Playernum, const governor_t Governor, unsigned int n, starnum_t snum, int sdata)
Definition: shlmisc.cc:214
int enufAP(int Playernum, int Governor, unsigned short AP, int x)
Definition: shlmisc.cc:131
static void create_ship_by_planet(int Playernum, int Governor, racetype *Race, Ship *newship, Planet *planet, int snum, int pnum, int x, int y)
Definition: build.cc:1275
static void Getship(Ship *, ShipType, Race *)
Definition: build.cc:1389
void putstar(startype *s, starnum_t snum)
Definition: files_shl.cc:813
static void create_ship_by_ship(int Playernum, int Governor, racetype *Race, int outside, Planet *planet, Ship *newship, Ship *builder)
Definition: build.cc:1327
int shipping_cost(int to, int from, double *dist, int value)
Definition: build.cc:1767
void putplanet(const Planet &p, startype *star, const int pnum)
Definition: files_shl.cc:934
#define Avpm(r)
Definition: races.h:119
#define TOXMAX
Definition: tweakables.h:266
void putship(Ship *s)
Definition: files_shl.cc:1317
static void autoload_at_ship(Ship *, Ship *, int *, double *)
Definition: build.cc:1185
static int getcount(const command_t &, const size_t)
Definition: build.cc:1067
int getcommod(commodtype **c, commodnum_t commodnum)
Definition: files_shl.cc:730
#define MAX(x, y)
Definition: tweakables.h:214
int getdeadship()
Definition: files_shl.cc:751
void putsdata(struct stardata *S)
Definition: files_shl.cc:804
#define Laser(r)
Definition: races.h:114
static int can_build_on_ship(int what, racetype *Race, Ship *builder, char *string)
Definition: build.cc:1128
static bool can_build_this(const ShipType, const Race &, char *)
Definition: build.cc:1096
#define NUMSTYPES
Definition: ships.h:99
#define FUEL
Definition: tweakables.h:270
#define DESTRUCT
Definition: tweakables.h:269
double tele_range(int, double)
Definition: shootblast.cc:539
static std::optional< ScopeLevel > build_at_ship(GameObj &, Ship *, int *, int *)
Definition: build.cc:1142
Sector getsector(const Planet &p, const int x, const int y)
Definition: files_shl.cc:480
#define MASS_RESOURCE
Definition: tweakables.h:99