Galactic Bloodshed
capture.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 #include "gb/commands/capture.h"
6 
7 #include <cstdio>
8 #include <cstdlib>
9 #include <cstring>
10 
11 #include "gb/GB_server.h"
12 #include "gb/buffers.h"
13 #include "gb/defense.h"
14 #include "gb/files.h"
15 #include "gb/files_shl.h"
16 #include "gb/fire.h"
17 #include "gb/getplace.h"
18 #include "gb/races.h"
19 #include "gb/ships.h"
20 #include "gb/shlmisc.h"
21 #include "gb/tele.h"
22 #include "gb/tweakables.h"
23 #include "gb/utils/rand.h"
24 #include "gb/vars.h"
25 
26 void capture(const command_t &argv, GameObj &g) {
27  const player_t Playernum = g.player;
28  const governor_t Governor = g.governor;
29  const int APcount = 1;
30  Ship *ship;
31  Ship s;
32  player_t oldowner;
33  governor_t oldgov;
34  int shipdam = 0;
35  int booby = 0;
36  shipnum_t shipno;
37  shipnum_t nextshipno;
38  int x = -1;
39  int y = -1;
40  int what;
41  population_t olddpopn;
42  population_t olddtroops;
43  population_t casualties = 0;
44  population_t casualties1 = 0;
45  population_t casualties2 = 0;
46  population_t casualty_scale = 0;
47  double astrength;
48  double dstrength;
49  racetype *Race;
50  racetype *alien;
51 
52  if (argv.size() < 2) {
53  g.out << "Capture what?\n";
54  return;
55  }
56  if (Governor && Stars[g.snum]->governor[Playernum - 1] != Governor) {
57  g.out << "You are not authorized in this system.\n";
58  return;
59  }
60  nextshipno = start_shiplist(g, argv[1]);
61  while ((shipno = do_shiplist(&ship, &nextshipno)))
62  if (ship->owner != Playernum &&
63  in_list(ship->owner, argv[1], *ship, &nextshipno)) {
64  if (!landed(*ship)) {
65  sprintf(buf, "%s #%ld is not landed on a planet.\n",
66  Shipnames[ship->type], shipno);
67  notify(Playernum, Governor, buf);
68  free(ship);
69  continue;
70  }
71  if (ship->type == ShipType::OTYPE_VN) {
72  g.out << "You can't capture Von Neumann machines.\n";
73  free(ship);
74  continue;
75  }
76  if (!enufAP(Playernum, Governor, Stars[ship->storbits]->AP[Playernum - 1],
77  APcount)) {
78  free(ship);
79  continue;
80  }
81 
82  x = ship->land_x;
83  y = ship->land_y;
84 
85  auto p = getplanet(ship->storbits, ship->pnumorbits);
86  auto sect = getsector(p, x, y);
87 
88  if (sect.owner != Playernum) {
89  sprintf(buf,
90  "You don't own the sector where the ship is landed [%d].\n",
91  sect.owner);
92  notify(Playernum, Governor, buf);
93  free(ship);
94  continue;
95  }
96 
97  if (argv.size() < 4)
98  what = CIV;
99  else if (argv[3] == "civilians")
100  what = CIV;
101  else if (argv[3] == "military")
102  what = MIL;
103  else {
104  g.out << "Capture with what?\n";
105  free(ship);
106  continue;
107  }
108 
109  population_t boarders;
110  if (argv.size() < 3) {
111  if (what == CIV)
112  boarders = sect.popn;
113  else // MIL
114  boarders = sect.troops;
115  } else
116  boarders = std::stoul(argv[2]);
117 
118  if (boarders == 0) {
119  g.out << "Illegal number of boarders.\n";
120  free(ship);
121  continue;
122  }
123 
124  if ((boarders > sect.popn) && what == CIV)
125  boarders = sect.popn;
126  else if ((boarders > sect.troops) && what == MIL)
127  boarders = sect.troops;
128 
129  Race = races[Playernum - 1];
130  alien = races[ship->owner - 1];
131 
132  if (isset(Race->allied, (ship->owner))) {
133  sprintf(buf, "Boarding the ship of your ally, %s\n", alien->name);
134  notify(Playernum, Governor, buf);
135  }
136 
137  olddpopn = ship->popn;
138  olddtroops = ship->troops;
139  oldowner = ship->owner;
140  oldgov = ship->governor;
141  bcopy(ship, &s, sizeof(Ship));
142 
143  shipdam = 0;
144  casualties = 0;
145  casualties1 = 0;
146  casualties2 = 0;
147 
148  if (what == CIV)
149  sect.popn -= boarders;
150  else if (what == MIL)
151  sect.troops -= boarders;
152 
153  if (olddpopn + olddtroops) {
154  sprintf(
155  buf, "Attack strength: %.2f Defense strength: %.2f\n",
156  astrength = (double)boarders *
157  (what == MIL ? (double)Race->fighters * 10.0 : 1.0) *
158  .01 * Race->tech *
159  (Race->likes[sect.condition] + 0.01) *
160  ((double)Defensedata[sect.condition] + 1.0) *
161  morale_factor((double)(Race->morale - alien->morale)),
162  dstrength = ((double)ship->popn + (double)ship->troops * 10.0 *
163  (double)alien->fighters) *
164  .01 * alien->tech * ((double)(armor(*ship)) + 0.01) *
165  .01 * (100.0 - (double)ship->damage) *
166  morale_factor((double)(alien->morale - Race->morale)));
167  notify(Playernum, Governor, buf);
168  casualty_scale = std::min(boarders, ship->popn + ship->troops);
169  if (astrength > 0.0)
170  casualties =
171  int_rand(0, round_rand((double)casualty_scale *
172  (dstrength + 1.0) / (astrength + 1.0)));
173 
174  if (dstrength > 0.0) {
175  casualties1 =
176  int_rand(0, round_rand((double)casualty_scale *
177  (astrength + 1.0) / (dstrength + 1.0)));
178  casualties2 =
179  int_rand(0, round_rand((double)casualty_scale *
180  (astrength + 1.0) / (dstrength + 1.0)));
181  shipdam = int_rand(
182  0, round_rand(25. * (astrength + 1.0) / (dstrength + 1.0)));
183  ship->damage = std::min(100, ship->damage + shipdam);
184  }
185 
186  casualties = std::min(boarders, casualties);
187  boarders -= casualties;
188 
189  casualties1 = std::min(olddpopn, casualties1);
190  ship->popn -= casualties1;
191  ship->mass -= casualties1 * alien->mass;
192 
193  casualties2 = std::min(olddtroops, casualties2);
194  ship->troops -= casualties2;
195  ship->mass -= casualties2 * alien->mass;
196 
197  } else if (ship->destruct) { /* booby trapped robot ships */
198  booby = int_rand(0, 10 * ship->destruct);
199  booby = std::min(100, booby);
200  casualties = casualties2 = 0;
201  for (unsigned long i = 0; i < boarders; i++)
202  casualties += (int_rand(1, 100) < booby);
203  boarders -= casualties;
204  shipdam += booby;
205  ship->damage += booby;
206  }
207  shipdam = std::min(100, shipdam);
208  if (ship->damage >= 100) kill_ship(Playernum, ship);
209 
210  if (!(ship->popn + ship->troops) && ship->alive) {
211  /* we got 'em */
212  ship->owner = Playernum;
213  ship->governor = Governor;
214  if (what == CIV) {
215  ship->popn = std::min(boarders, max_crew(*ship));
216  sect.popn += boarders - ship->popn;
217  ship->mass += ship->popn * Race->mass;
218  } else if (what == MIL) {
219  ship->troops = std::min(boarders, max_mil(*ship));
220  sect.troops += boarders - ship->troops;
221  ship->mass += ship->troops * Race->mass;
222  }
223  if (olddpopn + olddtroops && ship->type != ShipType::OTYPE_FACTORY)
224  adjust_morale(Race, alien, ship->build_cost);
225  /* unoccupied ships and factories don't count */
226  } else { /* retreat */
227  if (what == CIV)
228  sect.popn += boarders;
229  else if (what == MIL)
230  sect.troops += boarders;
231  }
232 
233  if (!(sect.popn + sect.troops)) sect.owner = 0;
234 
235  sprintf(buf, "BULLETIN from %s/%s!!\n", Stars[ship->storbits]->name,
236  Stars[ship->storbits]->pnames[ship->pnumorbits]);
237  strcpy(telegram_buf, buf);
238  sprintf(
239  buf, "You are being attacked by%s Player #%d (%s)!!!\n",
240  (isset(alien->allied, Playernum)
241  ? " your ally"
242  : (isset(alien->atwar, Playernum) ? " your enemy" : " neutral")),
243  Playernum, Race->name);
244  strcat(telegram_buf, buf);
245  sprintf(buf, "%s at sector %d,%d [owner %d] !\n",
246  ship_to_string(*ship).c_str(), x, y, sect.owner);
247  strcat(telegram_buf, buf);
248 
249  if (booby) {
250  sprintf(buf, "Booby trap triggered causing %d%% damage.\n", booby);
251  strcat(telegram_buf, buf);
252  notify(Playernum, Governor, buf);
253  }
254 
255  if (shipdam) {
256  sprintf(buf, "Total damage: %d%% (now %d%%)\n", shipdam, ship->damage);
257  strcat(telegram_buf, buf);
258  sprintf(buf, "Damage inflicted: Them: %d%% (now %d%%)\n", shipdam,
259  ship->damage);
260  notify(Playernum, Governor, buf);
261  }
262 
263  if (!ship->alive) {
264  sprintf(buf, " YOUR SHIP WAS DESTROYED!!!\n");
265  strcat(telegram_buf, buf);
266  g.out << " Their ship DESTROYED!!!\n";
267  sprintf(short_buf, "%s: %s [%d] DESTROYED %s\n", Dispshiploc(ship),
268  Race->name, Playernum, ship_to_string(s).c_str());
269  }
270 
271  if (ship->owner == Playernum) {
272  sprintf(buf, "%s CAPTURED!\n", ship_to_string(s).c_str());
273  notify(oldowner, oldgov, buf);
274  sprintf(buf, "VICTORY! The ship is yours!\n");
275  notify(Playernum, Governor, buf);
276  if (what == CIV)
277  sprintf(buf, "%lu boarders move in.\n",
278  std::min(boarders, ship->popn));
279  else if (what == MIL)
280  sprintf(buf, "%lu troops move in.\n",
281  std::min(boarders, ship->troops));
282  notify(Playernum, Governor, buf);
283  capture_stuff(*ship, g);
284  sprintf(short_buf, "%s: %s [%d] CAPTURED %s\n", Dispshiploc(ship),
285  Race->name, Playernum, ship_to_string(s).c_str());
286  } else if (ship->popn + ship->troops) {
287  sprintf(buf, "You fought them off!\n");
288  notify(oldowner, oldgov, buf);
289  g.out << "The boarding was repulsed; try again.\n";
290  sprintf(short_buf, "%s: %s [%d] assaults %s\n", Dispshiploc(ship),
291  Race->name, Playernum, ship_to_string(s).c_str());
292  }
293  if (ship->alive) {
294  if (sect.popn + sect.troops + boarders) {
295  sprintf(buf, "You killed all the aliens in this sector!\n");
296  strcat(telegram_buf, buf);
297  p.info[Playernum - 1].mob_points -= sect.mobilization;
298  }
299  if (!boarders) {
300  g.out << "Oh no! They killed your party to the last man!\n";
301  }
302  } else {
303  sprintf(buf, "Your ship was weakened too much!\n");
304  strcat(telegram_buf, buf);
305  g.out << "The assault weakened their ship too much!\n";
306  }
307 
308  if (casualties || casualties1 || casualties2) {
309  sprintf(buf, "Casualties: Yours: %ld civ/%ld mil, Theirs: %ld %s\n",
310  casualties1, casualties2, casualties,
311  what == CIV ? "civ" : "mil");
312  strcat(telegram_buf, buf);
313  sprintf(buf, "Casualties: Yours: %ld %s, Theirs: %ld civ/%ld mil\n",
314  casualties, what == CIV ? "civ" : "mil", casualties1,
315  casualties2);
316  notify(Playernum, Governor, buf);
317  }
318  warn(oldowner, oldgov, telegram_buf);
319  if (ship->owner != oldowner || !ship->alive) post(short_buf, COMBAT);
320  notify_star(Playernum, Governor, ship->storbits, short_buf);
321  putship(ship);
322  putsector(sect, p, x, y);
323  putplanet(p, Stars[g.snum], g.pnum);
324  putrace(Race);
325  putrace(alien);
326  deductAPs(Playernum, Governor, APcount, ship->storbits, 0);
327  free(ship);
328  } else
329  free(ship);
330 }
#define MIL
Definition: tweakables.h:262
void post(const char *origmsg, int type)
Definition: tele.cc:63
#define CIV
Definition: tweakables.h:261
double morale_factor(double x)
Definition: shlmisc.cc:239
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
#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
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
void capture(const command_t &argv, GameObj &g)
Definition: capture.cc:26
shipnum_t do_shiplist(Ship **s, shipnum_t *nextshipno)
Definition: shlmisc.cc:94
void putplanet(const Planet &p, startype *star, const int pnum)
Definition: files_shl.cc:934
void putship(Ship *s)
Definition: files_shl.cc:1317
#define COMBAT
Definition: files.h:19
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