Galactic Bloodshed
load.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 /* load.c -- load/unload stuff */
6 
7 #include "gb/load.h"
8 
9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 
13 #include "gb/GB_server.h"
14 #include "gb/buffers.h"
15 #include "gb/defense.h"
16 #include "gb/files_shl.h"
17 #include "gb/fire.h"
18 #include "gb/getplace.h"
19 #include "gb/land.h"
20 #include "gb/move.h"
21 #include "gb/races.h"
22 #include "gb/ships.h"
23 #include "gb/shlmisc.h"
24 #include "gb/tweakables.h"
25 #include "gb/utils/rand.h"
26 #include "gb/vars.h"
27 
28 static char buff[128], bufr[128], bufd[128], bufc[128], bufx[128], bufm[128];
29 
30 static int jettison_check(GameObj &, int, int);
31 static int landed_on(Ship *, shipnum_t);
32 
33 static void do_transporter(Race *, GameObj &, Ship *);
34 static void unload_onto_alien_sector(GameObj &, Planet *, Ship *, Sector &, int,
35  int);
36 
37 void load(const command_t &argv, GameObj &g) {
38  player_t Playernum = g.player;
39  governor_t Governor = g.governor;
40  int APcount = 0;
41  int mode = argv[0] == "load" ? 0 : 1; // load or unload
42  char commod;
43  unsigned char sh = 0;
44  unsigned char diff = 0;
45  int lolim;
46  int uplim;
47  int amt;
48  int transfercrew;
49  Ship *s;
50  Ship *s2;
51  Planet p;
52  Sector sect;
53  racetype *Race;
54  shipnum_t shipno;
55  shipnum_t nextshipno;
56 
57  if (argv.size() < 2) {
58  if (mode == 0) {
59  g.out << "Load what?\n";
60  } else {
61  g.out << "Unload what?\n";
62  }
63  return;
64  }
65 
66  nextshipno = start_shiplist(g, argv[1]);
67 
68  while ((shipno = do_shiplist(&s, &nextshipno)))
69  if (in_list(Playernum, argv[1], *s, &nextshipno) &&
70  authorized(Governor, *s)) {
71  if (s->owner != Playernum || !s->alive) {
72  free(s);
73  continue;
74  }
75  if (!s->active) {
76  sprintf(buf, "%s is irradiated and inactive.\n",
77  ship_to_string(*s).c_str());
78  notify(Playernum, Governor, buf);
79  free(s);
80  continue;
81  }
82  if (s->whatorbits == ScopeLevel::LEVEL_UNIV) {
83  if (!enufAP(Playernum, Governor, Sdata.AP[Playernum - 1], APcount)) {
84  free(s);
85  continue;
86  }
87  } else if (!enufAP(Playernum, Governor,
88  Stars[s->storbits]->AP[Playernum - 1], APcount))
89  continue;
90  if (!s->docked) {
91  sprintf(buf, "%s is not landed or docked.\n",
92  ship_to_string(*s).c_str());
93  notify(Playernum, Governor, buf);
94  free(s);
95  continue;
96  } /* ship has a recipient */
97  if (s->whatdest == ScopeLevel::LEVEL_PLAN) {
98  sprintf(buf, "%s at %d,%d\n", ship_to_string(*s).c_str(), s->land_x,
99  s->land_y);
100  notify(Playernum, Governor, buf);
101  if (s->storbits != g.snum || s->pnumorbits != g.pnum) {
102  notify(Playernum, Governor,
103  "Change scope to the planet this ship is landed on.\n");
104  free(s);
105  continue;
106  }
107  } else { /* ship is docked */
108  if (!s->destshipno) {
109  sprintf(buf, "%s is not docked.\n", ship_to_string(*s).c_str());
110  free(s);
111  continue;
112  }
113  if (!getship(&s2, (int)s->destshipno)) {
114  g.out << "Destination ship is bogus.\n";
115  free(s);
116  continue;
117  }
118  if (!s2->alive || !(s->whatorbits == ScopeLevel::LEVEL_SHIP ||
119  s2->destshipno == shipno)) {
120  /* the ship it was docked with died or
121  undocked with it or something. */
122  s->docked = 0;
123  s->whatdest = ScopeLevel::LEVEL_UNIV;
124  putship(s);
125  sprintf(buf, "%s is not docked.\n", ship_to_string(*s2).c_str());
126  notify(Playernum, Governor, buf);
127  free(s);
128  free(s2);
129  continue;
130  }
131  if (overloaded(s2) && s2->whatorbits == ScopeLevel::LEVEL_SHIP) {
132  sprintf(buf, "%s is overloaded!\n", ship_to_string(*s2).c_str());
133  notify(Playernum, Governor, buf);
134  free(s);
135  free(s2);
136  continue;
137  }
138  sprintf(buf, "%s docked with %s\n", ship_to_string(*s).c_str(),
139  ship_to_string(*s2).c_str());
140  notify(Playernum, Governor, buf);
141  sh = 1;
142  if (s2->owner != Playernum) {
143  sprintf(buf, "Player %d owns that ship.\n", s2->owner);
144  notify(Playernum, Governor, buf);
145  diff = 1;
146  }
147  }
148 
149  commod = argv[2][0];
150  if (argv.size() > 3)
151  amt = std::stoi(argv[3]);
152  else
153  amt = 0;
154 
155  if (mode) amt = -amt; /* unload */
156 
157  if (amt < 0 && s->type == ShipType::OTYPE_VN) {
158  g.out << "You can't unload VNs.\n";
159  free(s);
160  if (sh) free(s2);
161  continue;
162  }
163 
164  if (!sh) p = getplanet(g.snum, g.pnum);
165 
166  if (!sh && (commod == 'c' || commod == 'm'))
167  sect = getsector(p, s->land_x, s->land_y);
168 
169  switch (commod) {
170  case 'x':
171  case '&':
172  if (sh) {
173  uplim =
174  diff ? 0 : MIN(s2->crystals, max_crystals(*s) - s->crystals);
175  lolim =
176  diff ? 0 : -MIN(s->crystals, max_crystals(*s2) - s2->crystals);
177  } else {
178  uplim = MIN(p.info[Playernum - 1].crystals,
179  max_crystals(*s) - s->crystals);
180  lolim = -s->crystals;
181  }
182  break;
183  case 'c':
184  if (sh) {
185  uplim = diff ? 0 : MIN(s2->popn, max_crew(*s) - s->popn);
186  lolim = diff ? 0 : -MIN(s->popn, max_crew(*s2) - s2->popn);
187  } else {
188  uplim = MIN(sect.popn, max_crew(*s) - s->popn);
189  lolim = -s->popn;
190  }
191  break;
192  case 'm':
193  if (sh) {
194  uplim = diff ? 0 : MIN(s2->troops, max_mil(*s) - s->troops);
195  lolim = diff ? 0 : -MIN(s->troops, max_mil(*s2) - s2->troops);
196  } else {
197  uplim = MIN(sect.troops, max_mil(*s) - s->troops);
198  lolim = -s->troops;
199  }
200  break;
201  case 'd':
202  if (sh) {
203  uplim =
204  diff ? 0 : MIN(s2->destruct, max_destruct(*s) - s->destruct);
205  lolim = -MIN(s->destruct, max_destruct(*s2) - s2->destruct);
206  } else {
207  uplim = MIN(p.info[Playernum - 1].destruct,
208  max_destruct(*s) - s->destruct);
209  lolim = -s->destruct;
210  }
211  break;
212  case 'f':
213  if (sh) {
214  uplim =
215  diff ? 0 : MIN((int)s2->fuel, (int)max_fuel(*s) - (int)s->fuel);
216  lolim = -MIN((int)s->fuel, (int)max_fuel(*s2) - (int)s2->fuel);
217  } else {
218  uplim = MIN((int)p.info[Playernum - 1].fuel,
219  (int)max_fuel(*s) - (int)s->fuel);
220  lolim = -(int)s->fuel;
221  }
222  break;
223  case 'r':
224  if (sh) {
225  if (s->type == ShipType::STYPE_SHUTTLE &&
226  s->whatorbits != ScopeLevel::LEVEL_SHIP)
227  uplim = diff ? 0 : s2->resource;
228  else
229  uplim =
230  diff ? 0 : MIN(s2->resource, max_resource(*s) - s->resource);
231  if (s2->type == ShipType::STYPE_SHUTTLE &&
232  s->whatorbits != ScopeLevel::LEVEL_SHIP)
233  lolim = -s->resource;
234  else
235  lolim = -MIN(s->resource, max_resource(*s2) - s2->resource);
236  } else {
237  uplim = MIN(p.info[Playernum - 1].resource,
238  max_resource(*s) - s->resource);
239  lolim = -s->resource;
240  }
241  break;
242  default:
243  g.out << "No such commodity valid.\n";
244  if (sh) free(s2);
245  free(s);
246  continue;
247  }
248 
249  if (amt < lolim || amt > uplim) {
250  sprintf(buf, "you can only transfer between %d and %d.\n", lolim,
251  uplim);
252  notify(Playernum, Governor, buf);
253 
254  if (sh) free(s2);
255  free(s);
256  continue;
257  }
258 
259  Race = races[Playernum - 1];
260 
261  if (amt == 0) amt = (mode ? lolim : uplim);
262 
263  switch (commod) {
264  case 'c':
265  if (sh) {
266  s2->popn -= amt;
267  if (!landed_on(s, sh)) s2->mass -= amt * Race->mass;
268  transfercrew = 1;
269  } else if (sect.owner && sect.owner != Playernum) {
270  sprintf(buf,
271  "That sector is already occupied by another player!\n");
272  notify(Playernum, Governor, buf);
273  /* fight a land battle */
274  unload_onto_alien_sector(g, &p, s, sect, CIV, -amt);
275  putship(s);
276  putsector(sect, p, s->land_x, s->land_y);
277  putplanet(p, Stars[g.snum], g.pnum);
278  free(s);
279  return;
280  } else {
281  transfercrew = 1;
282  if (!sect.popn && !sect.troops && amt < 0) {
283  p.info[Playernum - 1].numsectsowned++;
284  p.info[Playernum - 1].mob_points += sect.mobilization;
285  sect.owner = Playernum;
286  sprintf(buf, "sector %d,%d COLONIZED.\n", s->land_x, s->land_y);
287  notify(Playernum, Governor, buf);
288  }
289  sect.popn -= amt;
290  p.popn -= amt;
291  p.info[Playernum - 1].popn -= amt;
292  if (!sect.popn && !sect.troops) {
293  p.info[Playernum - 1].numsectsowned--;
294  p.info[Playernum - 1].mob_points -= sect.mobilization;
295  sect.owner = 0;
296  sprintf(buf, "sector %d,%d evacuated.\n", s->land_x, s->land_y);
297  notify(Playernum, Governor, buf);
298  }
299  }
300  if (transfercrew) {
301  s->popn += amt;
302  s->mass += amt * Race->mass;
303  sprintf(buf, "crew complement of %s is now %lu.\n",
304  ship_to_string(*s).c_str(), s->popn);
305  notify(Playernum, Governor, buf);
306  }
307  break;
308  case 'm':
309  if (sh) {
310  s2->troops -= amt;
311  if (!landed_on(s, sh)) s2->mass -= amt * Race->mass;
312  transfercrew = 1;
313  } else if (sect.owner && sect.owner != Playernum) {
314  sprintf(buf,
315  "That sector is already occupied by another player!\n");
316  notify(Playernum, Governor, buf);
317  unload_onto_alien_sector(g, &p, s, sect, MIL, -amt);
318  putship(s);
319  putsector(sect, p, s->land_x, s->land_y);
320  putplanet(p, Stars[g.snum], g.pnum);
321  free(s);
322  return;
323  } else {
324  transfercrew = 1;
325  if (!(sect.popn + sect.troops) && amt < 0) {
326  p.info[Playernum - 1].numsectsowned++;
327  p.info[Playernum - 1].mob_points += sect.mobilization;
328  sect.owner = Playernum;
329  sprintf(buf, "sector %d,%d OCCUPIED.\n", s->land_x, s->land_y);
330  notify(Playernum, Governor, buf);
331  }
332  sect.troops -= amt;
333  p.troops -= amt;
334  p.info[Playernum - 1].troops -= amt;
335  if (!(sect.troops + sect.popn)) {
336  p.info[Playernum - 1].numsectsowned--;
337  p.info[Playernum - 1].mob_points -= sect.mobilization;
338  sect.owner = 0;
339  sprintf(buf, "sector %d,%d evacuated.\n", s->land_x, s->land_y);
340  notify(Playernum, Governor, buf);
341  }
342  }
343  if (transfercrew) {
344  s->troops += amt;
345  s->mass += amt * Race->mass;
346  sprintf(buf, "troop complement of %s is now %lu.\n",
347  ship_to_string(*s).c_str(), s->troops);
348  notify(Playernum, Governor, buf);
349  }
350  break;
351  case 'd':
352  if (sh) {
353  s2->destruct -= amt;
354  if (!landed_on(s, sh)) s2->mass -= amt * MASS_DESTRUCT;
355  } else
356  p.info[Playernum - 1].destruct -= amt;
357 
358  s->destruct += amt;
359  s->mass += amt * MASS_DESTRUCT;
360  sprintf(buf, "%d destruct transferred.\n", amt);
361  notify(Playernum, Governor, buf);
362  if (!max_crew(*s)) {
363  sprintf(buf, "\n%s ", ship_to_string(*s).c_str());
364  notify(Playernum, Governor, buf);
365  if (s->destruct) {
366  sprintf(buf, "now boobytrapped.\n");
367  } else {
368  sprintf(buf, "no longer boobytrapped.\n");
369  }
370  notify(Playernum, Governor, buf);
371  }
372  break;
373  case 'x':
374  if (sh) {
375  s2->crystals -= amt;
376  } else
377  p.info[Playernum - 1].crystals -= amt;
378  s->crystals += amt;
379  sprintf(buf, "%d crystal(s) transferred.\n", amt);
380  notify(Playernum, Governor, buf);
381  break;
382  case 'f':
383  if (sh) {
384  s2->fuel -= (double)amt;
385  if (!landed_on(s, sh)) s2->mass -= (double)amt * MASS_FUEL;
386  } else
387  p.info[Playernum - 1].fuel -= amt;
388  rcv_fuel(s, (double)amt);
389  sprintf(buf, "%d fuel transferred.\n", amt);
390  notify(Playernum, Governor, buf);
391  break;
392  case 'r':
393  if (sh) {
394  s2->resource -= amt;
395  if (!landed_on(s, sh)) s2->mass -= amt * MASS_RESOURCE;
396  } else
397  p.info[Playernum - 1].resource -= amt;
398  rcv_resource(s, amt);
399  sprintf(buf, "%d resources transferred.\n", amt);
400  notify(Playernum, Governor, buf);
401  break;
402  default:
403  g.out << "No such commodity.\n";
404 
405  if (sh) free(s2);
406  free(s);
407  continue;
408  }
409 
410  if (sh) {
411  /* ship to ship transfer */
412  buff[0] = bufr[0] = bufd[0] = bufc[0] = '\0';
413  switch (commod) {
414  case 'r':
415  sprintf(buf, "%d resources transferred.\n", amt);
416  notify(Playernum, Governor, buf);
417  sprintf(bufr, "%d Resources\n", amt);
418  break;
419  case 'f':
420  sprintf(buf, "%d fuel transferred.\n", amt);
421  notify(Playernum, Governor, buf);
422  sprintf(buff, "%d Fuel\n", amt);
423  break;
424  case 'd':
425  sprintf(buf, "%d destruct transferred.\n", amt);
426  notify(Playernum, Governor, buf);
427  sprintf(bufd, "%d Destruct\n", amt);
428  break;
429  case 'x':
430  case '&':
431  sprintf(buf, "%d crystals transferred.\n", amt);
432  notify(Playernum, Governor, buf);
433  sprintf(bufd, "%d Crystal(s)\n", amt);
434  break;
435  case 'c':
436  sprintf(buf, "%d popn transferred.\n", amt);
437  notify(Playernum, Governor, buf);
438  sprintf(bufc, "%d %s\n", amt,
439  Race->Metamorph ? "tons of biomass" : "population");
440  break;
441  case 'm':
442  sprintf(buf, "%d military transferred.\n", amt);
443  notify(Playernum, Governor, buf);
444  sprintf(bufm, "%d %s\n", amt,
445  Race->Metamorph ? "tons of biomass" : "population");
446  break;
447  default:
448  break;
449  }
450  putship(s2);
451  free(s2);
452  } else {
453  if (commod == 'c' || commod == 'm') {
454  putsector(sect, p, s->land_x, s->land_y);
455  }
456  putplanet(p, Stars[g.snum], g.pnum);
457  }
458 
459  /* do transporting here */
460  if (s->type == ShipType::OTYPE_TRANSDEV && s->special.transport.target &&
461  s->on)
462  do_transporter(Race, g, s);
463 
464  putship(s);
465  free(s);
466  } else
467  free(s); /* make sure you do this! */
468 }
469 
470 void jettison(const command_t &argv, GameObj &g) {
471  player_t Playernum = g.player;
472  governor_t Governor = g.governor;
473  int APcount = 0;
474  int Mod = 0;
475  shipnum_t shipno;
476  shipnum_t nextshipno;
477  int amt;
478  char commod;
479  Ship *s;
480  racetype *Race;
481 
482  if (argv.size() < 2) {
483  g.out << "Jettison what?\n";
484  return;
485  }
486 
487  nextshipno = start_shiplist(g, argv[1]);
488 
489  while ((shipno = do_shiplist(&s, &nextshipno)))
490  if (in_list(Playernum, argv[1], *s, &nextshipno) &&
491  authorized(Governor, *s)) {
492  if (s->owner != Playernum || !s->alive) {
493  free(s);
494  continue;
495  }
496  if (landed(*s)) {
497  g.out << "Ship is landed, cannot jettison.\n";
498  free(s);
499  continue;
500  }
501  if (!s->active) {
502  sprintf(buf, "%s is irradiated and inactive.\n",
503  ship_to_string(*s).c_str());
504  notify(Playernum, Governor, buf);
505  free(s);
506  continue;
507  }
508  if (s->whatorbits == ScopeLevel::LEVEL_UNIV) {
509  if (!enufAP(Playernum, Governor, Sdata.AP[Playernum - 1], APcount)) {
510  free(s);
511  continue;
512  }
513  } else if (!enufAP(Playernum, Governor,
514  Stars[s->storbits]->AP[Playernum - 1], APcount)) {
515  free(s);
516  continue;
517  }
518 
519  if (argv.size() > 3)
520  amt = std::stoi(argv[3]);
521  else
522  amt = 0;
523 
524  Race = races[Playernum - 1];
525 
526  commod = argv[2][0];
527  switch (commod) {
528  case 'x':
529  if ((amt = jettison_check(g, amt, (int)(s->crystals))) > 0) {
530  s->crystals -= amt;
531  sprintf(buf, "%d crystal%s jettisoned.\n", amt,
532  (amt == 1) ? "" : "s");
533  notify(Playernum, Governor, buf);
534  Mod = 1;
535  }
536  break;
537  case 'c':
538  if ((amt = jettison_check(g, amt, (int)(s->popn))) > 0) {
539  s->popn -= amt;
540  s->mass -= amt * Race->mass;
541  sprintf(buf, "%d crew %s into deep space.\n", amt,
542  (amt == 1) ? "hurls itself" : "hurl themselves");
543  notify(Playernum, Governor, buf);
544  sprintf(buf, "Complement of %s is now %lu.\n",
545  ship_to_string(*s).c_str(), s->popn);
546  notify(Playernum, Governor, buf);
547  Mod = 1;
548  }
549  break;
550  case 'm':
551  if ((amt = jettison_check(g, amt, (int)(s->troops))) > 0) {
552  sprintf(buf, "%d military %s into deep space.\n", amt,
553  (amt == 1) ? "hurls itself" : "hurl themselves");
554  notify(Playernum, Governor, buf);
555  sprintf(buf, "Complement of ship #%lu is now %lu.\n", shipno,
556  s->troops - amt);
557  notify(Playernum, Governor, buf);
558  s->troops -= amt;
559  s->mass -= amt * Race->mass;
560  Mod = 1;
561  }
562  break;
563  case 'd':
564  if ((amt = jettison_check(g, amt, (int)(s->destruct))) > 0) {
565  use_destruct(s, amt);
566  sprintf(buf, "%d destruct jettisoned.\n", amt);
567  notify(Playernum, Governor, buf);
568  if (!max_crew(*s)) {
569  sprintf(buf, "\n%s ", ship_to_string(*s).c_str());
570  notify(Playernum, Governor, buf);
571  if (s->destruct) {
572  g.out << "still boobytrapped.\n";
573  } else {
574  g.out << "no longer boobytrapped.\n";
575  }
576  }
577  Mod = 1;
578  }
579  break;
580  case 'f':
581  if ((amt = jettison_check(g, amt, (int)(s->fuel))) > 0) {
582  use_fuel(s, (double)amt);
583  sprintf(buf, "%d fuel jettisoned.\n", amt);
584  notify(Playernum, Governor, buf);
585  Mod = 1;
586  }
587  break;
588  case 'r':
589  if ((amt = jettison_check(g, amt, (int)(s->resource))) > 0) {
590  use_resource(s, amt);
591  sprintf(buf, "%d resources jettisoned.\n", amt);
592  notify(Playernum, Governor, buf);
593  Mod = 1;
594  }
595  break;
596  default:
597  g.out << "No such commodity valid.\n";
598  return;
599  }
600  if (Mod) putship(s);
601  free(s);
602  } else
603  free(s);
604 }
605 
606 static int jettison_check(GameObj &g, int amt, int max) {
607  player_t Playernum = g.player;
608  governor_t Governor = g.governor;
609  if (amt == 0) amt = max;
610  if (amt < 0) {
611  g.out << "Nice try.\n";
612  return -1;
613  }
614  if (amt > max) {
615  sprintf(buf, "You can jettison at most %d\n", max);
616  notify(Playernum, Governor, buf);
617  return -1;
618  }
619  return amt;
620 }
621 
622 void dump(const command_t &argv, GameObj &g) {
623  player_t Playernum = g.player;
624  governor_t Governor = g.governor;
625  int APcount = 10;
626  int player;
627  int star;
628  int j;
629  racetype *Race;
630  racetype *r;
631  placetype where;
632 
633  if (!enufAP(Playernum, Governor, Stars[g.snum]->AP[Playernum - 1], APcount))
634  return;
635 
636  if (!(player = get_player(argv[1]))) {
637  sprintf(buf, "No such player.\n");
638  notify(Playernum, Governor, buf);
639  return;
640  }
641  r = races[player - 1];
642 
643  if (r->Guest) {
644  g.out << "Cheater!\n";
645  return;
646  }
647 
648  /* transfer all planet and star knowledge to the player */
649  /* get all stars and planets */
650  Race = races[Playernum - 1];
651  if (Race->Guest) {
652  g.out << "Cheater!\n";
653  return;
654  }
655  if (Governor) {
656  g.out << "Only leaders are allowed to use dump.\n";
657  return;
658  }
659  getsdata(&Sdata);
660 
661  if (argv.size() < 3) {
662  for (star = 0; star < Sdata.numstars; star++) {
663  getstar(&Stars[star], star);
664 
665  if (isset(Stars[star]->explored, Playernum)) {
666  setbit(Stars[star]->explored, player);
667 
668  for (size_t i = 0; i < Stars[star]->numplanets; i++) {
669  auto planet = getplanet(star, i);
670  if (planet.info[Playernum - 1].explored) {
671  planet.info[player - 1].explored = 1;
672  putplanet(planet, Stars[star], i);
673  }
674  }
675  putstar(Stars[star], star);
676  }
677  }
678  } else { /* list of places given */
679  for (size_t i = 2; i < argv.size(); i++) {
680  where = getplace(g, argv[i], 1);
681  if (!where.err && where.level != ScopeLevel::LEVEL_UNIV &&
682  where.level != ScopeLevel::LEVEL_SHIP) {
683  star = where.snum;
684  getstar(&Stars[star], star);
685 
686  if (isset(Stars[star]->explored, Playernum)) {
687  setbit(Stars[star]->explored, player);
688 
689  for (j = 0; j < Stars[star]->numplanets; j++) {
690  auto planet = getplanet(star, j);
691  if (planet.info[Playernum - 1].explored) {
692  planet.info[player - 1].explored = 1;
693  putplanet(planet, Stars[star], j);
694  }
695  }
696  putstar(Stars[star], star);
697  }
698  }
699  }
700  }
701 
702  deductAPs(Playernum, Governor, APcount, g.snum, 0);
703 
704  sprintf(buf, "%s [%d] has given you exploration data.\n", Race->name,
705  Playernum);
706  warn_race(player, buf);
707  g.out << "Exploration Data transferred.\n";
708 }
709 
710 void transfer(const command_t &argv, GameObj &g) {
711  player_t Playernum = g.player;
712  governor_t Governor = g.governor;
713  int APcount = 1;
714  player_t player;
715  char commod = 0;
716 
717  if (g.level != ScopeLevel::LEVEL_PLAN) {
718  sprintf(buf, "You need to be in planet scope to do this.\n");
719  notify(Playernum, Governor, buf);
720  return;
721  }
722 
723  if (!enufAP(Playernum, Governor, Stars[g.snum]->AP[Playernum - 1], APcount))
724  return;
725 
726  if (!(player = get_player(argv[1]))) {
727  sprintf(buf, "No such player.\n");
728  notify(Playernum, Governor, buf);
729  return;
730  }
731 
732  auto planet = getplanet(g.snum, g.pnum);
733 
734  sscanf(argv[2].c_str(), "%c", &commod);
735  // TODO(jeffbailey): May throw an exception on a negative number.
736  resource_t give = std::stoul(argv[3]);
737 
738  sprintf(temp, "%s/%s:", Stars[g.snum]->name, Stars[g.snum]->pnames[g.pnum]);
739  switch (commod) {
740  case 'r':
741  if (give > planet.info[Playernum - 1].resource) {
742  sprintf(buf, "You don't have %lu on this planet.\n", give);
743  notify(Playernum, Governor, buf);
744  } else {
745  planet.info[Playernum - 1].resource -= give;
746  planet.info[player - 1].resource += give;
747  sprintf(buf,
748  "%s %lu resources transferred from player %d to player #%d\n",
749  temp, give, Playernum, player);
750  notify(Playernum, Governor, buf);
751  warn_race(player, buf);
752  }
753  break;
754  case 'x':
755  case '&':
756  if (give > planet.info[Playernum - 1].crystals) {
757  sprintf(buf, "You don't have %lu on this planet.\n", give);
758  notify(Playernum, Governor, buf);
759  } else {
760  planet.info[Playernum - 1].crystals -= give;
761  planet.info[player - 1].crystals += give;
762  sprintf(buf,
763  "%s %lu crystal(s) transferred from player %d to player #%d\n",
764  temp, give, Playernum, player);
765  notify(Playernum, Governor, buf);
766  warn_race(player, buf);
767  }
768  break;
769  case 'f':
770  if (give > planet.info[Playernum - 1].fuel) {
771  sprintf(buf, "You don't have %lu fuel on this planet.\n", give);
772  notify(Playernum, Governor, buf);
773  } else {
774  planet.info[Playernum - 1].fuel -= give;
775  planet.info[player - 1].fuel += give;
776  sprintf(buf, "%s %lu fuel transferred from player %d to player #%d\n",
777  temp, give, Playernum, player);
778  notify(Playernum, Governor, buf);
779  warn_race(player, buf);
780  }
781  break;
782  case 'd':
783  if (give > planet.info[Playernum - 1].destruct) {
784  sprintf(buf, "You don't have %lu destruct on this planet.\n", give);
785  notify(Playernum, Governor, buf);
786  } else {
787  planet.info[Playernum - 1].destruct -= give;
788  planet.info[player - 1].destruct += give;
789  sprintf(buf,
790  "%s %lu destruct transferred from player %d to player #%d\n",
791  temp, give, Playernum, player);
792  notify(Playernum, Governor, buf);
793  warn_race(player, buf);
794  }
795  break;
796  default:
797  sprintf(buf, "What?\n");
798  notify(Playernum, Governor, buf);
799  }
800 
801  putplanet(planet, Stars[g.snum], g.pnum);
802 
803  deductAPs(Playernum, Governor, APcount, g.snum, 0);
804 }
805 
806 void mount(const command_t &argv, GameObj &g) {
807  const player_t Playernum = g.player;
808  const governor_t Governor = g.governor;
809  bool mnt;
810  mnt = argv[0] == "mount";
811 
812  Ship *ship;
813  shipnum_t shipno;
814  shipnum_t nextshipno;
815 
816  nextshipno = start_shiplist(g, argv[1]);
817  while ((shipno = do_shiplist(&ship, &nextshipno)))
818  if (in_list(Playernum, argv[1], *ship, &nextshipno) &&
819  authorized(Governor, *ship)) {
820  if (!ship->mount) {
821  notify(Playernum, Governor,
822  "This ship is not equipped with a crystal mount.\n");
823  free(ship);
824  continue;
825  }
826  if (ship->mounted && mnt) {
827  g.out << "You already have a crystal mounted.\n";
828  free(ship);
829  continue;
830  }
831  if (!ship->mounted && !mnt) {
832  g.out << "You don't have a crystal mounted.\n";
833  free(ship);
834  continue;
835  }
836  if (!ship->mounted && mnt) {
837  if (!ship->crystals) {
838  g.out << "You have no crystals on board.\n";
839  free(ship);
840  continue;
841  }
842  ship->mounted = 1;
843  ship->crystals--;
844  g.out << "Mounted.\n";
845  } else if (ship->mounted && !mnt) {
846  if (ship->crystals == max_crystals(*ship)) {
847  notify(Playernum, Governor,
848  "You can't dismount the crystal. Max "
849  "allowed already on board.\n");
850  free(ship);
851  continue;
852  }
853  ship->mounted = 0;
854  ship->crystals++;
855  g.out << "Dismounted.\n";
856  if (ship->hyper_drive.charge || ship->hyper_drive.ready) {
857  ship->hyper_drive.charge = 0;
858  ship->hyper_drive.ready = 0;
859  g.out << "Discharged.\n";
860  }
861  if (ship->laser && ship->fire_laser) {
862  ship->fire_laser = 0;
863  g.out << "Laser deactivated.\n";
864  }
865  } else {
866  g.out << "Weird error in 'mount'.\n";
867  free(ship);
868  continue;
869  }
870  putship(ship);
871  free(ship);
872  } else
873  free(ship);
874 }
875 
876 void use_fuel(Ship *s, double amt) {
877  s->fuel -= amt;
878  s->mass -= amt * MASS_FUEL;
879 }
880 
881 void use_destruct(Ship *s, int amt) {
882  s->destruct -= amt;
883  s->mass -= (double)amt * MASS_DESTRUCT;
884 }
885 
886 void use_resource(Ship *s, int amt) {
887  s->resource -= amt;
888  s->mass -= (double)amt * MASS_RESOURCE;
889 }
890 
891 void rcv_fuel(Ship *s, double amt) {
892  s->fuel += amt;
893  s->mass += amt * MASS_FUEL;
894 }
895 
896 void rcv_resource(Ship *s, int amt) {
897  s->resource += amt;
898  s->mass += (double)amt * MASS_RESOURCE;
899 }
900 
901 void rcv_destruct(Ship *s, int amt) {
902  s->destruct += amt;
903  s->mass += (double)amt * MASS_DESTRUCT;
904 }
905 
906 void rcv_popn(Ship *s, int amt, double mass) {
907  s->popn += amt;
908  s->mass += (double)amt * mass;
909 }
910 
911 void rcv_troops(Ship *s, int amt, double mass) {
912  s->troops += amt;
913  s->mass += (double)amt * mass;
914 }
915 
916 static void do_transporter(racetype *Race, GameObj &g, Ship *s) {
917  player_t Playernum = g.player;
918  governor_t Governor = g.governor;
919  Ship *s2;
920 
921  Playernum = Race->Playernum;
922 
923  if (!landed(*s)) {
924  g.out << "Origin ship not landed.\n";
925  return;
926  }
927  if (s->storbits != g.snum || s->pnumorbits != g.pnum) {
928  sprintf(buf, "Change scope to the planet the ship is landed on!\n");
929  notify(Playernum, Governor, buf);
930  return;
931  }
932  if (s->damage) {
933  g.out << "Origin device is damaged.\n";
934  return;
935  }
936  if (!getship(&s2, (int)s->special.transport.target)) {
937  sprintf(buf, "The hopper seems to be blocked.\n");
938  notify(Playernum, Governor, buf);
939  return;
940  }
941  if (!s2->alive || s2->type != ShipType::OTYPE_TRANSDEV || !s2->on) {
942  sprintf(buf, "The target device is not receiving.\n");
943  notify(Playernum, Governor, buf);
944  free(s2);
945  return;
946  }
947  if (!landed(*s2)) {
948  g.out << "Target ship not landed.\n";
949  free(s2);
950  return;
951  }
952  if (s2->damage) {
953  g.out << "Target device is damaged.\n";
954  free(s2);
955  return;
956  }
957 
958  sprintf(buf, "Zap\07!\n"); /* ^G */
959  notify(Playernum, Governor, buf);
960  /* send stuff to other ship (could be transport device) */
961  if (s->resource) {
962  rcv_resource(s2, (int)s->resource);
963  sprintf(buf, "%lu resources transferred.\n", s->resource);
964  notify(Playernum, Governor, buf);
965  sprintf(bufr, "%lu Resources\n", s->resource);
966  use_resource(s, (int)s->resource);
967  } else
968  bufr[0] = '\0';
969  if (s->fuel) {
970  rcv_fuel(s2, s->fuel);
971  sprintf(buf, "%g fuel transferred.\n", s->fuel);
972  notify(Playernum, Governor, buf);
973  sprintf(buff, "%g Fuel\n", s->fuel);
974  use_fuel(s, s->fuel);
975  } else
976  buff[0] = '\0';
977 
978  if (s->destruct) {
979  rcv_destruct(s2, (int)s->destruct);
980  sprintf(buf, "%d destruct transferred.\n", s->destruct);
981  notify(Playernum, Governor, buf);
982  sprintf(bufd, "%d Destruct\n", s->destruct);
983  use_destruct(s, (int)s->destruct);
984  } else
985  bufd[0] = '\0';
986 
987  if (s->popn) {
988  s2->mass += s->popn * Race->mass;
989  s2->popn += s->popn;
990 
991  sprintf(buf, "%lu population transferred.\n", s->popn);
992  notify(Playernum, Governor, buf);
993  sprintf(bufc, "%lu %s\n", s->popn,
994  Race->Metamorph ? "tons of biomass" : "population");
995  s->mass -= s->popn * Race->mass;
996  s->popn -= s->popn;
997  } else
998  bufc[0] = '\0';
999 
1000  if (s->crystals) {
1001  s2->crystals += s->crystals;
1002 
1003  sprintf(buf, "%d crystal(s) transferred.\n", s->crystals);
1004  notify(Playernum, Governor, buf);
1005  sprintf(bufx, "%d crystal(s)\n", s->crystals);
1006 
1007  s->crystals = 0;
1008  } else
1009  bufx[0] = '\0';
1010 
1011  if (s2->owner != s->owner) {
1012  sprintf(telegram_buf, "Audio-vibatory-physio-molecular transport device #");
1013  sprintf(buf, "%s gave your ship %s the following:\n",
1014  ship_to_string(*s).c_str(), ship_to_string(*s2).c_str());
1015  strcat(telegram_buf, buf);
1016  strcat(telegram_buf, bufr);
1017  strcat(telegram_buf, bufd);
1018  strcat(telegram_buf, buff);
1019  strcat(telegram_buf, bufc);
1020  strcat(telegram_buf, bufm);
1021  strcat(telegram_buf, bufx);
1022  warn(s2->owner, s2->governor, telegram_buf);
1023  }
1024 
1025  putship(s2);
1026  free(s2);
1027 }
1028 
1029 static int landed_on(Ship *s, shipnum_t shipno) {
1030  return (s->whatorbits == ScopeLevel::LEVEL_SHIP && s->destshipno == shipno);
1031 }
1032 
1033 static void unload_onto_alien_sector(GameObj &g, Planet *planet, Ship *ship,
1034  Sector &sect, int what, int people) {
1035  player_t Playernum = g.player;
1036  governor_t Governor = g.governor;
1037  double astrength;
1038  double dstrength;
1039  int oldowner;
1040  int oldgov;
1041  int oldpopn;
1042  int old2popn;
1043  int old3popn;
1044  int casualties;
1045  int casualties2;
1046  int casualties3;
1047  int absorbed;
1048  int defense;
1049  racetype *Race;
1050  racetype *alien;
1051 
1052  if (people <= 0) {
1053  notify(Playernum, Governor,
1054  "You have to unload to assault alien sectors.\n");
1055  return;
1056  }
1057  ground_assaults[Playernum - 1][sect.owner - 1][g.snum] += 1;
1058  Race = races[Playernum - 1];
1059  alien = races[sect.owner - 1];
1060  /* races find out about each other */
1061  alien->translate[Playernum - 1] =
1062  MIN(alien->translate[Playernum - 1] + 5, 100);
1063  Race->translate[sect.owner - 1] =
1064  MIN(Race->translate[sect.owner - 1] + 5, 100);
1065 
1066  oldowner = (int)sect.owner;
1067  oldgov = Stars[g.snum]->governor[sect.owner - 1];
1068 
1069  if (what == CIV)
1070  ship->popn -= people;
1071  else
1072  ship->troops -= people;
1073  ship->mass -= people * Race->mass;
1074  sprintf(buf, "%d %s unloaded...\n", people, what == CIV ? "civ" : "mil");
1075  notify(Playernum, Governor, buf);
1076  sprintf(buf, "Crew compliment %lu civ %lu mil\n", ship->popn, ship->troops);
1077  notify(Playernum, Governor, buf);
1078 
1079  sprintf(buf, "%d %s assault %lu civ/%lu mil\n", people,
1080  what == CIV ? "civ" : "mil", sect.popn, sect.troops);
1081 
1082  notify(Playernum, Governor, buf);
1083  oldpopn = people;
1084  old2popn = sect.popn;
1085  old3popn = sect.troops;
1086 
1087  defense = Defensedata[sect.condition];
1088  ground_attack(Race, alien, &people, what, &sect.popn, &sect.troops,
1089  (int)ship->armor, defense, 1.0 - (double)ship->damage / 100.0,
1090  alien->likes[sect.condition], &astrength, &dstrength,
1091  &casualties, &casualties2, &casualties3);
1092  sprintf(buf, "Attack: %.2f Defense: %.2f.\n", astrength, dstrength);
1093  notify(Playernum, Governor, buf);
1094 
1095  if (!(sect.popn + sect.troops)) { /* we got 'em */
1096  /* mesomorphs absorb the bodies of their victims */
1097  absorbed = 0;
1098  if (Race->absorb) {
1099  absorbed = int_rand(0, old2popn + old3popn);
1100  sprintf(buf, "%d alien bodies absorbed.\n", absorbed);
1101  notify(Playernum, Governor, buf);
1102  sprintf(buf, "Metamorphs have absorbed %d bodies!!!\n", absorbed);
1103  notify(oldowner, oldgov, buf);
1104  }
1105  if (what == CIV)
1106  sect.popn = people + absorbed;
1107  else if (what == MIL) {
1108  sect.popn = absorbed;
1109  sect.troops = people;
1110  }
1111  sect.owner = Playernum;
1112  adjust_morale(Race, alien, (int)alien->fighters);
1113  } else { /* retreat */
1114  absorbed = 0;
1115  if (alien->absorb) {
1116  absorbed = int_rand(0, oldpopn - people);
1117  sprintf(buf, "%d alien bodies absorbed.\n", absorbed);
1118  notify(oldowner, oldgov, buf);
1119  sprintf(buf, "Metamorphs have absorbed %d bodies!!!\n", absorbed);
1120  notify(Playernum, Governor, buf);
1121  sect.popn += absorbed;
1122  }
1123  /* load them back up */
1124  sprintf(buf, "Loading %d %s\n", people, what == CIV ? "civ" : "mil");
1125  notify(Playernum, Governor, buf);
1126  if (what == CIV)
1127  ship->popn += people;
1128  else
1129  ship->troops += people;
1130  ship->mass -= people * Race->mass;
1131  adjust_morale(alien, Race, (int)Race->fighters);
1132  }
1133  sprintf(telegram_buf, "/%s/%s: %s [%d] %s assaults %s [%d] %c(%d,%d) %s\n",
1134  Stars[g.snum]->name, Stars[g.snum]->pnames[g.pnum], Race->name,
1135  Playernum, ship_to_string(*ship).c_str(), alien->name,
1136  alien->Playernum, Dessymbols[sect.condition], ship->land_x,
1137  ship->land_y, (sect.owner == Playernum ? "VICTORY" : "DEFEAT"));
1138 
1139  if (sect.owner == Playernum) {
1140  sprintf(buf, "VICTORY! The sector is yours!\n");
1141  notify(Playernum, Governor, buf);
1142  sprintf(buf, "Sector CAPTURED!\n");
1143  strcat(telegram_buf, buf);
1144  if (people) {
1145  sprintf(buf, "%d %s move in.\n", people,
1146  what == CIV ? "civilians" : "troops");
1147  notify(Playernum, Governor, buf);
1148  }
1149  planet->info[Playernum - 1].numsectsowned++;
1150  planet->info[Playernum - 1].mob_points += sect.mobilization;
1151  planet->info[oldowner - 1].numsectsowned--;
1152  planet->info[oldowner - 1].mob_points -= sect.mobilization;
1153  } else {
1154  sprintf(buf, "The invasion was repulsed; try again.\n");
1155  notify(Playernum, Governor, buf);
1156  sprintf(buf, "You fought them off!\n");
1157  strcat(telegram_buf, buf);
1158  }
1159  if (!(sect.popn + sect.troops + people)) {
1160  sprintf(buf, "You killed all of them!\n");
1161  strcat(telegram_buf, buf);
1162  /* increase modifier */
1163  Race->translate[oldowner - 1] = MIN(Race->translate[oldowner - 1] + 5, 100);
1164  }
1165  if (!people) {
1166  sprintf(buf, "Oh no! They killed your party to the last man!\n");
1167  notify(Playernum, Governor, buf);
1168  /* increase modifier */
1169  alien->translate[Playernum - 1] =
1170  MIN(alien->translate[Playernum - 1] + 5, 100);
1171  }
1172  putrace(alien);
1173  putrace(Race);
1174 
1175  sprintf(buf, "Casualties: You: %d civ/%d mil, Them: %d %s\n", casualties2,
1176  casualties3, casualties, what == CIV ? "civ" : "mil");
1177  strcat(telegram_buf, buf);
1178  warn(oldowner, oldgov, telegram_buf);
1179  sprintf(buf, "Casualties: You: %d %s, Them: %d civ/%d mil\n", casualties,
1180  what == CIV ? "civ" : "mil", casualties2, casualties3);
1181  notify(Playernum, Governor, buf);
1182 }
void mount(const command_t &argv, GameObj &g)
Definition: load.cc:806
#define MASS_FUEL
Definition: tweakables.h:98
void use_fuel(Ship *s, double amt)
Definition: load.cc:876
#define MIL
Definition: tweakables.h:262
#define CIV
Definition: tweakables.h:261
void rcv_resource(Ship *s, int amt)
Definition: load.cc:896
#define MASS_DESTRUCT
Definition: tweakables.h:100
void rcv_fuel(Ship *s, double amt)
Definition: load.cc:891
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
int overloaded(Ship *s)
Definition: land.cc:426
#define isset(a, i)
Definition: vars.h:312
void putsector(const Sector &s, const Planet &p, const int x, const int y)
Definition: files_shl.cc:1076
#define setbit(a, i)
Definition: vars.h:310
static char bufx[128]
Definition: load.cc:28
static char bufr[128]
Definition: load.cc:28
#define MIN(x, y)
Definition: tweakables.h:213
void rcv_popn(Ship *s, int amt, double mass)
Definition: load.cc:906
static char bufc[128]
Definition: load.cc:28
void dump(const command_t &argv, GameObj &g)
Definition: load.cc:622
void deductAPs(const player_t Playernum, const governor_t Governor, unsigned int n, starnum_t snum, int sdata)
Definition: shlmisc.cc:214
void jettison(const command_t &argv, GameObj &g)
Definition: load.cc:470
int enufAP(int Playernum, int Governor, unsigned short AP, int x)
Definition: shlmisc.cc:131
void load(const command_t &argv, GameObj &g)
Definition: load.cc:37
static void unload_onto_alien_sector(GameObj &, Planet *, Ship *, Sector &, int, int)
Definition: load.cc:1033
void use_destruct(Ship *s, int amt)
Definition: load.cc:881
void transfer(const command_t &argv, GameObj &g)
Definition: load.cc:710
void putstar(startype *s, starnum_t snum)
Definition: files_shl.cc:813
shipnum_t do_shiplist(Ship **s, shipnum_t *nextshipno)
Definition: shlmisc.cc:94
void getsdata(struct stardata *S)
Definition: files_shl.cc:272
void putplanet(const Planet &p, startype *star, const int pnum)
Definition: files_shl.cc:934
void use_resource(Ship *s, int amt)
Definition: load.cc:886
void getstar(startype **s, int star)
Definition: files_shl.cc:281
void putship(Ship *s)
Definition: files_shl.cc:1317
static char bufm[128]
Definition: load.cc:28
static char bufd[128]
Definition: load.cc:28
void rcv_destruct(Ship *s, int amt)
Definition: load.cc:901
void rcv_troops(Ship *s, int amt, double mass)
Definition: load.cc:911
static int jettison_check(GameObj &, int, int)
Definition: load.cc:606
static void do_transporter(racetype *Race, GameObj &g, Ship *s)
Definition: load.cc:916
static int landed_on(Ship *, shipnum_t)
Definition: load.cc:1029
Sector getsector(const Planet &p, const int x, const int y)
Definition: files_shl.cc:480
void putrace(Race *r)
Definition: files_shl.cc:808
void ground_attack(racetype *Race, racetype *alien, int *people, int what, population_t *civ, population_t *mil, unsigned int def1, unsigned int def2, double alikes, double dlikes, double *astrength, double *dstrength, int *casualties, int *casualties2, int *casualties3)
Definition: move.cc:832
static char buff[128]
Definition: load.cc:28
#define MASS_RESOURCE
Definition: tweakables.h:99