Galactic Bloodshed
move.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 /* move.c -- move population and assault aliens on target sector */
6 
7 #include "gb/move.h"
8 
9 #include <cmath>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 
14 #include "gb/GB_server.h"
15 #include "gb/buffers.h"
16 #include "gb/defense.h"
17 #include "gb/files.h"
18 #include "gb/files_shl.h"
19 #include "gb/fire.h"
20 #include "gb/getplace.h"
21 #include "gb/load.h"
22 #include "gb/mobiliz.h"
23 #include "gb/races.h"
24 #include "gb/ships.h"
25 #include "gb/shlmisc.h"
26 #include "gb/shootblast.h"
27 #include "gb/tele.h"
28 #include "gb/tweakables.h"
29 #include "gb/utils/rand.h"
30 #include "gb/vars.h"
31 
32 static void mech_defend(int, int, int *, int, const Planet &, int, int,
33  const Sector &);
34 static void mech_attack_people(Ship *, int *, int *, Race *, Race *,
35  const Sector &, int, int, int, char *, char *);
36 static void people_attack_mech(Ship *, int, int, Race *, Race *, const Sector &,
37  int, int, char *, char *);
38 
39 void arm(const command_t &argv, GameObj &g) {
40  const player_t Playernum = g.player;
41  const governor_t Governor = g.governor;
42  int mode;
43  if (argv[0] == "arm") {
44  mode = 1;
45  } else {
46  mode = 0; // disarm
47  }
48  racetype *Race;
49  int x = -1;
50  int y = -1;
51  int max_allowed;
52  int amount = 0;
53  money_t cost = 0;
54 
55  if (g.level != ScopeLevel::LEVEL_PLAN) {
56  g.out << "Change scope to planet level first.\n";
57  return;
58  }
59  if (!control(Playernum, Governor, Stars[g.snum])) {
60  g.out << "You are not authorized to do that here.\n";
61  return;
62  }
63  auto planet = getplanet(g.snum, g.pnum);
64 
65  if (planet.slaved_to > 0 && planet.slaved_to != Playernum) {
66  g.out << "That planet has been enslaved!\n";
67  return;
68  }
69 
70  sscanf(argv[1].c_str(), "%d,%d", &x, &y);
71  if (x < 0 || y < 0 || x > planet.Maxx - 1 || y > planet.Maxy - 1) {
72  g.out << "Illegal coordinates.\n";
73  return;
74  }
75 
76  auto sect = getsector(planet, x, y);
77  if (sect.owner != Playernum) {
78  g.out << "You don't own that sector.\n";
79  return;
80  }
81  if (mode) {
82  max_allowed = MIN(sect.popn, planet.info[Playernum - 1].destruct *
83  (sect.mobilization + 1));
84  if (argv.size() < 3)
85  amount = max_allowed;
86  else {
87  amount = std::stoul(argv[2]);
88  if (amount <= 0) {
89  g.out << "You must specify a positive number of civs to arm.\n";
90  return;
91  }
92  }
93  amount = std::min(amount, max_allowed);
94  if (!amount) {
95  g.out << "You can't arm any civilians now.\n";
96  return;
97  }
98  Race = races[Playernum - 1];
99  /* enlist_cost = ENLIST_TROOP_COST * amount; */
100  money_t enlist_cost = Race->fighters * amount;
101  if (enlist_cost > Race->governor[Governor].money) {
102  sprintf(buf, "You need %ld money to enlist %d troops.\n", enlist_cost,
103  amount);
104  notify(Playernum, Governor, buf);
105  return;
106  }
107  Race->governor[Governor].money -= enlist_cost;
108  putrace(Race);
109 
110  cost = std::max(1U, amount / (sect.mobilization + 1));
111  sect.troops += amount;
112  sect.popn -= amount;
113  planet.popn -= amount;
114  planet.info[Playernum - 1].popn -= amount;
115  planet.troops += amount;
116  planet.info[Playernum - 1].troops += amount;
117  planet.info[Playernum - 1].destruct -= cost;
118  sprintf(buf,
119  "%d population armed at a cost of %ldd (now %lu civilians, %lu "
120  "military)\n",
121  amount, cost, sect.popn, sect.troops);
122  notify(Playernum, Governor, buf);
123  sprintf(buf, "This mobilization cost %ld money.\n", enlist_cost);
124  notify(Playernum, Governor, buf);
125  } else {
126  if (argv.size() < 3)
127  amount = sect.troops;
128  else {
129  amount = std::stoi(argv[2]);
130  if (amount <= 0) {
131  g.out << "You must specify a positive number of civs to arm.\n";
132  return;
133  }
134  amount = MIN(sect.troops, amount);
135  }
136  sect.popn += amount;
137  sect.troops -= amount;
138  planet.popn += amount;
139  planet.troops -= amount;
140  planet.info[Playernum - 1].popn += amount;
141  planet.info[Playernum - 1].troops -= amount;
142  sprintf(buf, "%d troops disarmed (now %lu civilians, %lu military)\n",
143  amount, sect.popn, sect.troops);
144  notify(Playernum, Governor, buf);
145  }
146  putsector(sect, planet, x, y);
147  putplanet(planet, Stars[g.snum], g.pnum);
148 }
149 
150 void move_popn(const command_t &argv, GameObj &g) {
151  const player_t Playernum = g.player;
152  const governor_t Governor = g.governor;
153  int what;
154  if (argv[0] == "move") {
155  what = CIV;
156  } else {
157  what = MIL; // deploy
158  }
159  int Assault;
160  int APcost; /* unfriendly movement */
161  int casualties;
162  int casualties2;
163  int casualties3;
164 
165  int people;
166  int oldpopn;
167  int old2popn;
168  int old3popn;
169  int x = -1;
170  int y = -1;
171  int x2 = -1;
172  int y2 = -1;
173  int old2owner;
174  int old2gov;
175  int absorbed;
176  int n;
177  int done;
178  double astrength;
179  double dstrength;
180  racetype *Race;
181  racetype *alien;
182 
183  if (g.level != ScopeLevel::LEVEL_PLAN) {
184  sprintf(buf, "Wrong scope\n");
185  return;
186  }
187  if (!control(Playernum, Governor, Stars[g.snum])) {
188  g.out << "You are not authorized to do that here.\n";
189  return;
190  }
191  auto planet = getplanet(g.snum, g.pnum);
192 
193  if (planet.slaved_to > 0 && planet.slaved_to != Playernum) {
194  sprintf(buf, "That planet has been enslaved!\n");
195  notify(Playernum, Governor, buf);
196  return;
197  }
198  sscanf(argv[1].c_str(), "%d,%d", &x, &y);
199  if (x < 0 || y < 0 || x > planet.Maxx - 1 || y > planet.Maxy - 1) {
200  sprintf(buf, "Origin coordinates illegal.\n");
201  notify(Playernum, Governor, buf);
202  return;
203  }
204 
205  /* movement loop */
206  done = 0;
207  n = 0;
208  while (!done) {
209  auto sect = getsector(planet, x, y);
210  if (sect.owner != Playernum) {
211  sprintf(buf, "You don't own sector %d,%d!\n", x, y);
212  notify(Playernum, Governor, buf);
213  return;
214  }
215  if (!get_move(argv[2][n++], x, y, &x2, &y2, planet)) {
216  g.out << "Finished.\n";
217  putplanet(planet, Stars[g.snum], g.pnum);
218  return;
219  }
220 
221  if (x2 < 0 || y2 < 0 || x2 > planet.Maxx - 1 || y2 > planet.Maxy - 1) {
222  sprintf(buf, "Illegal coordinates %d,%d.\n", x2, y2);
223  notify(Playernum, Governor, buf);
224  putplanet(planet, Stars[g.snum], g.pnum);
225  return;
226  }
227 
228  if (!adjacent(x, y, x2, y2, planet)) {
229  sprintf(buf, "Illegal move - to adjacent sectors only!\n");
230  notify(Playernum, Governor, buf);
231  return;
232  }
233 
234  /* ok, the move is legal */
235  auto sect2 = getsector(planet, x2, y2);
236  if (argv.size() >= 4) {
237  people = std::stoi(argv[3]);
238  if (people < 0) {
239  if (what == CIV)
240  people = sect.popn + people;
241  else if (what == MIL)
242  people = sect.troops + people;
243  }
244  } else {
245  if (what == CIV)
246  people = sect.popn;
247  else if (what == MIL)
248  people = sect.troops;
249  }
250 
251  if ((what == CIV && (abs(people) > sect.popn)) ||
252  (what == MIL && (abs(people) > sect.troops)) || people <= 0) {
253  if (what == CIV)
254  sprintf(buf, "Bad value - %lu civilians in [%d,%d]\n", sect.popn, x, y);
255  else if (what == MIL)
256  sprintf(buf, "Bad value - %lu troops in [%d,%d]\n", sect.troops, x, y);
257  notify(Playernum, Governor, buf);
258  putplanet(planet, Stars[g.snum], g.pnum);
259  return;
260  }
261 
262  sprintf(buf, "%d %s moved.\n", people,
263  what == CIV ? "population" : "troops");
264  notify(Playernum, Governor, buf);
265 
266  /* check for defending mechs */
267  mech_defend(Playernum, Governor, &people, what, planet, x2, y2, sect2);
268  if (!people) {
269  putsector(sect, planet, x, y);
270  putsector(sect2, planet, x2, y2);
271  putplanet(planet, Stars[g.snum], g.pnum);
272  g.out << "Attack aborted.\n";
273  return;
274  }
275 
276  if (sect2.owner && (sect2.owner != Playernum))
277  Assault = 1;
278  else
279  Assault = 0;
280 
281  /* action point cost depends on the size of the group being moved */
282  if (what == CIV)
283  APcost = MOVE_FACTOR * ((int)log(1.0 + (double)people) + Assault) + 1;
284  else if (what == MIL)
285  APcost = MOVE_FACTOR * ((int)log10(1.0 + (double)people) + Assault) + 1;
286 
287  if (!enufAP(Playernum, Governor, Stars[g.snum]->AP[Playernum - 1],
288  APcost)) {
289  putplanet(planet, Stars[g.snum], g.pnum);
290  return;
291  }
292 
293  if (Assault) {
294  ground_assaults[Playernum - 1][sect2.owner - 1][g.snum] += 1;
295  Race = races[Playernum - 1];
296  alien = races[sect2.owner - 1];
297  /* races find out about each other */
298  alien->translate[Playernum - 1] =
299  MIN(alien->translate[Playernum - 1] + 5, 100);
300  Race->translate[sect2.owner - 1] =
301  MIN(Race->translate[sect2.owner - 1] + 5, 100);
302 
303  old2owner = (int)(sect2.owner);
304  old2gov = Stars[g.snum]->governor[sect2.owner - 1];
305  if (what == CIV)
306  sect.popn = std::max(0UL, sect.popn - people);
307  else if (what == MIL)
308  sect.troops = std::max(0UL, sect.troops - people);
309 
310  if (what == CIV)
311  sprintf(buf, "%d civ assault %lu civ/%lu mil\n", people, sect2.popn,
312  sect2.troops);
313  else if (what == MIL)
314  sprintf(buf, "%d mil assault %lu civ/%lu mil\n", people, sect2.popn,
315  sect2.troops);
316  notify(Playernum, Governor, buf);
317  oldpopn = people;
318  old2popn = sect2.popn;
319  old3popn = sect2.troops;
320 
321  ground_attack(Race, alien, &people, what, &sect2.popn, &sect2.troops,
322  Defensedata[sect.condition], Defensedata[sect2.condition],
323  Race->likes[sect.condition], alien->likes[sect2.condition],
324  &astrength, &dstrength, &casualties, &casualties2,
325  &casualties3);
326 
327  sprintf(buf, "Attack: %.2f Defense: %.2f.\n", astrength, dstrength);
328  notify(Playernum, Governor, buf);
329 
330  if (!(sect2.popn + sect2.troops)) { /* we got 'em */
331  sect2.owner = Playernum;
332  /* mesomorphs absorb the bodies of their victims */
333  absorbed = 0;
334  if (Race->absorb) {
335  absorbed = int_rand(0, old2popn + old3popn);
336  sprintf(buf, "%d alien bodies absorbed.\n", absorbed);
337  notify(Playernum, Governor, buf);
338  sprintf(buf, "Metamorphs have absorbed %d bodies!!!\n", absorbed);
339  notify(old2owner, old2gov, buf);
340  }
341  if (what == CIV)
342  sect2.popn = people + absorbed;
343  else if (what == MIL) {
344  sect2.popn = absorbed;
345  sect2.troops = people;
346  }
347  adjust_morale(Race, alien, (int)alien->fighters);
348  } else { /* retreat */
349  absorbed = 0;
350  if (alien->absorb) {
351  absorbed = int_rand(0, oldpopn - people);
352  sprintf(buf, "%d alien bodies absorbed.\n", absorbed);
353  notify(old2owner, old2gov, buf);
354  sprintf(buf, "Metamorphs have absorbed %d bodies!!!\n", absorbed);
355  notify(Playernum, Governor, buf);
356  sect2.popn += absorbed;
357  }
358  if (what == CIV)
359  sect.popn += people;
360  else if (what == MIL)
361  sect.troops += people;
362  adjust_morale(alien, Race, (int)Race->fighters);
363  }
364 
365  sprintf(telegram_buf,
366  "/%s/%s: %s [%d] %c(%d,%d) assaults %s [%d] %c(%d,%d) %s\n",
367  Stars[g.snum]->name, Stars[g.snum]->pnames[g.pnum], Race->name,
368  Playernum, Dessymbols[sect.condition], x, y, alien->name,
369  alien->Playernum, Dessymbols[sect2.condition], x2, y2,
370  (sect2.owner == Playernum ? "VICTORY" : "DEFEAT"));
371 
372  if (sect2.owner == Playernum) {
373  sprintf(buf, "VICTORY! The sector is yours!\n");
374  notify(Playernum, Governor, buf);
375  sprintf(buf, "Sector CAPTURED!\n");
376  strcat(telegram_buf, buf);
377  if (people) {
378  sprintf(buf, "%d %s move in.\n", people,
379  what == CIV ? "civilians" : "troops");
380  notify(Playernum, Governor, buf);
381  }
382  planet.info[Playernum - 1].mob_points += (int)sect2.mobilization;
383  planet.info[old2owner - 1].mob_points -= (int)sect2.mobilization;
384  } else {
385  sprintf(buf, "The invasion was repulsed; try again.\n");
386  notify(Playernum, Governor, buf);
387  sprintf(buf, "You fought them off!\n");
388  strcat(telegram_buf, buf);
389  done = 1; /* end loop */
390  }
391 
392  if (!(sect.popn + sect.troops + people)) {
393  sprintf(buf, "You killed all of them!\n");
394  strcat(telegram_buf, buf);
395  /* increase modifier */
396  Race->translate[old2owner - 1] =
397  MIN(Race->translate[old2owner - 1] + 5, 100);
398  }
399  if (!people) {
400  sprintf(buf, "Oh no! They killed your party to the last man!\n");
401  notify(Playernum, Governor, buf);
402  /* increase modifier */
403  alien->translate[Playernum - 1] =
404  MIN(alien->translate[Playernum - 1] + 5, 100);
405  }
406  putrace(alien);
407  putrace(Race);
408 
409  sprintf(buf, "Casualties: You: %d civ/%d mil, Them: %d %s\n", casualties2,
410  casualties3, casualties, what == CIV ? "civ" : "mil");
411  strcat(telegram_buf, buf);
412  warn(old2owner, old2gov, telegram_buf);
413  sprintf(buf, "Casualties: You: %d %s, Them: %d civ/%d mil\n", casualties,
414  what == CIV ? "civ" : "mil", casualties2, casualties3);
415  notify(Playernum, Governor, buf);
416  } else {
417  if (what == CIV) {
418  sect.popn -= people;
419  sect2.popn += people;
420  } else if (what == MIL) {
421  sect.troops -= people;
422  sect2.troops += people;
423  }
424  if (!sect2.owner)
425  planet.info[Playernum - 1].mob_points += (int)sect2.mobilization;
426  sect2.owner = Playernum;
427  }
428 
429  if (!(sect.popn + sect.troops)) {
430  planet.info[Playernum - 1].mob_points -= (int)sect.mobilization;
431  sect.owner = 0;
432  }
433 
434  if (!(sect2.popn + sect2.troops)) {
435  sect2.owner = 0;
436  done = 1;
437  }
438 
439  putsector(sect, planet, x, y);
440  putsector(sect2, planet, x2, y2);
441 
442  deductAPs(Playernum, Governor, APcost, g.snum, 0);
443  x = x2;
444  y = y2; /* get ready for the next round */
445  }
446  g.out << "Finished.\n";
447 }
448 
449 void walk(const command_t &argv, GameObj &g) {
450  const player_t Playernum = g.player;
451  const governor_t Governor = g.governor;
452  const int APcount = 1;
453  Ship *ship;
454  Ship dummy;
455  int x;
456  int y;
457  int i;
458  int succ = 0;
459  int civ;
460  int mil;
461  int oldowner;
462  int oldgov;
463  int strength;
464  int strength1;
465  racetype *Race;
466  racetype *alien;
467 
468  if (argv.size() < 2) {
469  g.out << "Walk what?\n";
470  return;
471  }
472  auto shipno = string_to_shipnum(argv[1]);
473  if (!shipno || !getship(&ship, *shipno)) {
474  g.out << "No such ship.\n";
475  return;
476  }
477  if (testship(Playernum, Governor, *ship)) {
478  g.out << "You do not control this ship.\n";
479  free(ship);
480  return;
481  }
482  if (ship->type != ShipType::OTYPE_AFV) {
483  g.out << "This ship doesn't walk!\n";
484  free(ship);
485  return;
486  }
487  if (!landed(*ship)) {
488  g.out << "This ship is not landed on a planet.\n";
489  free(ship);
490  return;
491  }
492  if (!ship->popn) {
493  g.out << "No crew.\n";
494  free(ship);
495  return;
496  }
497  if (ship->fuel < AFV_FUEL_COST) {
498  sprintf(buf, "You don't have %.1f fuel to move it.\n", AFV_FUEL_COST);
499  notify(Playernum, Governor, buf);
500  free(ship);
501  return;
502  }
503  if (!enufAP(Playernum, Governor, Stars[ship->storbits]->AP[Playernum - 1],
504  APcount)) {
505  free(ship);
506  return;
507  }
508  auto p = getplanet((int)ship->storbits, (int)ship->pnumorbits);
509  Race = races[Playernum - 1];
510 
511  if (!get_move(argv[2][0], (int)ship->land_x, (int)ship->land_y, &x, &y, p)) {
512  g.out << "Illegal move.\n";
513  free(ship);
514  return;
515  }
516  if (x < 0 || y < 0 || x > p.Maxx - 1 || y > p.Maxy - 1) {
517  sprintf(buf, "Illegal coordinates %d,%d.\n", x, y);
518  notify(Playernum, Governor, buf);
519  free(ship);
520  putplanet(p, Stars[g.snum], g.pnum);
521  return;
522  }
523  /* check to see if player is permited on the sector type */
524  auto sect = getsector(p, x, y);
525  if (!Race->likes[sect.condition]) {
526  notify(Playernum, Governor,
527  "Your ships cannot walk into that sector type!\n");
528  free(ship);
529  return;
530  }
531  /* if the sector is occupied by non-aligned AFVs, each one will attack */
532  Shiplist shiplist{p.ships};
533  for (auto ship2 : shiplist) {
534  if (ship2.owner != Playernum && ship2.type == ShipType::OTYPE_AFV &&
535  landed(ship2) && retal_strength(&ship2) && (ship2.land_x == x) &&
536  (ship2.land_y == y)) {
537  alien = races[ship2.owner - 1];
538  if (!isset(Race->allied, (int)ship2.owner) ||
539  !isset(alien->allied, Playernum)) {
540  while ((strength = retal_strength(&ship2)) &&
541  (strength1 = retal_strength(ship))) {
542  bcopy(ship, &dummy, sizeof(Ship));
543  use_destruct(&ship2, strength);
544  notify(Playernum, Governor, long_buf);
545  warn(ship2.owner, ship2.governor, long_buf);
546  if (!ship2.alive) post(short_buf, COMBAT);
547  notify_star(Playernum, Governor, ship->storbits, short_buf);
548  if (strength1) {
549  use_destruct(ship, strength1);
550  notify(Playernum, Governor, long_buf);
551  warn(ship2.owner, ship2.governor, long_buf);
552  if (!ship2.alive) post(short_buf, COMBAT);
553  notify_star(Playernum, Governor, ship->storbits, short_buf);
554  }
555  }
556  putship(&ship2);
557  }
558  }
559  if (!ship->alive) break;
560  }
561  /* if the sector is occupied by non-aligned player, attack them first */
562  if (ship->popn && ship->alive && sect.owner && sect.owner != Playernum) {
563  oldowner = sect.owner;
564  oldgov = Stars[ship->storbits]->governor[sect.owner - 1];
565  alien = races[oldowner - 1];
566  if (!isset(Race->allied, oldowner) || !isset(alien->allied, Playernum)) {
567  if (!retal_strength(ship)) {
568  g.out << "You have nothing to attack with!\n";
569  free(ship);
570  return;
571  }
572  while ((sect.popn + sect.troops) && retal_strength(ship)) {
573  civ = (int)sect.popn;
574  mil = (int)sect.troops;
575  mech_attack_people(ship, &civ, &mil, Race, alien, sect, x, y, 0,
576  long_buf, short_buf);
577  notify(Playernum, Governor, long_buf);
578  warn(alien->Playernum, oldgov, long_buf);
579  notify_star(Playernum, Governor, ship->storbits, short_buf);
580  post(short_buf, COMBAT);
581 
582  people_attack_mech(ship, sect.popn, sect.troops, alien, Race, sect, x,
583  y, long_buf, short_buf);
584  notify(Playernum, Governor, long_buf);
585  warn(alien->Playernum, oldgov, long_buf);
586  notify_star(Playernum, Governor, ship->storbits, short_buf);
587  if (!ship->alive) post(short_buf, COMBAT);
588 
589  sect.popn = civ;
590  sect.troops = mil;
591  if (!(sect.popn + sect.troops)) {
592  p.info[sect.owner - 1].mob_points -= (int)sect.mobilization;
593  sect.owner = 0;
594  }
595  }
596  }
597  putrace(alien);
598  putrace(Race);
599  putplanet(p, Stars[g.snum], g.pnum);
600  putsector(sect, p, x, y);
601  }
602 
603  if ((sect.owner == Playernum || isset(Race->allied, (int)sect.owner) ||
604  !sect.owner) &&
605  ship->alive)
606  succ = 1;
607 
608  if (ship->alive && ship->popn && succ) {
609  sprintf(buf, "%s moving from %d,%d to %d,%d on %s.\n",
610  ship_to_string(*ship).c_str(), (int)ship->land_x, (int)ship->land_y,
611  x, y, Dispshiploc(ship));
612  ship->land_x = x;
613  ship->land_y = y;
615  for (i = 1; i <= Num_races; i++)
616  if (i != Playernum && p.info[i - 1].numsectsowned)
617  notify(i, (int)Stars[g.snum]->governor[i - 1], buf);
618  }
619  putship(ship);
620  deductAPs(Playernum, Governor, APcount, (int)ship->storbits, 0);
621  free(ship);
622 }
623 
624 int get_move(char direction, int x, int y, int *x2, int *y2,
625  const Planet &planet) {
626  switch (direction) {
627  case '1':
628  case 'b':
629  *x2 = x - 1;
630  *y2 = y + 1;
631  if (*x2 == -1) *x2 = planet.Maxx - 1;
632  return 1;
633  case '2':
634  case 'k':
635  *x2 = x;
636  *y2 = y + 1;
637  return 1;
638  case '3':
639  case 'n':
640  *x2 = x + 1;
641  *y2 = y + 1;
642  if (*x2 == planet.Maxx) *x2 = 0;
643  return 1;
644  case '4':
645  case 'h':
646  *x2 = x - 1;
647  *y2 = y;
648  if (*x2 == -1) *x2 = planet.Maxx - 1;
649  return 1;
650  case '6':
651  case 'l':
652  *x2 = x + 1;
653  *y2 = y;
654  if (*x2 == planet.Maxx) *x2 = 0;
655  return 1;
656  case '7':
657  case 'y':
658  *x2 = x - 1;
659  *y2 = y - 1;
660  if (*x2 == -1) *x2 = planet.Maxx - 1;
661  return 1;
662  case '8':
663  case 'j':
664  *x2 = x;
665  *y2 = y - 1;
666  return 1;
667  case '9':
668  case 'u':
669  *x2 = x + 1;
670  *y2 = y - 1;
671  if (*x2 == planet.Maxx) *x2 = 0;
672  return 1;
673  default:
674  *x2 = x;
675  *y2 = y;
676  return 0;
677  }
678 }
679 
680 static void mech_defend(int Playernum, int Governor, int *people, int type,
681  const Planet &p, int x2, int y2, const Sector &s2) {
682  int civ = 0;
683  int mil = 0;
684  int oldgov;
685  racetype *Race;
686  racetype *alien;
687 
688  if (type == CIV)
689  civ = *people;
690  else
691  mil = *people;
692 
693  Race = races[Playernum - 1];
694 
695  Shiplist shiplist{p.ships};
696  for (auto ship : shiplist) {
697  if (civ + mil == 0) break;
698  if (ship.owner != Playernum && ship.type == ShipType::OTYPE_AFV &&
699  landed(ship) && retal_strength(&ship) && (ship.land_x == x2) &&
700  (ship.land_y == y2)) {
701  alien = races[ship.owner - 1];
702  if (!isset(Race->allied, ship.owner) ||
703  !isset(alien->allied, Playernum)) {
704  while ((civ + mil) > 0 && retal_strength(&ship)) {
705  oldgov = Stars[ship.storbits]->governor[alien->Playernum - 1];
706  mech_attack_people(&ship, &civ, &mil, alien, Race, s2, x2, y2, 1,
707  long_buf, short_buf);
708  notify(Playernum, Governor, long_buf);
709  warn(alien->Playernum, oldgov, long_buf);
710  if (civ + mil) {
711  people_attack_mech(&ship, civ, mil, Race, alien, s2, x2, y2,
712  long_buf, short_buf);
713  notify(Playernum, Governor, long_buf);
714  warn(alien->Playernum, oldgov, long_buf);
715  }
716  }
717  }
718  putship(&ship);
719  }
720  }
721  *people = civ + mil;
722 }
723 
724 static void mech_attack_people(Ship *ship, int *civ, int *mil, racetype *Race,
725  racetype *alien, const Sector &sect, int x,
726  int y, int ignore, char *long_msg,
727  char *short_msg) {
728  int strength;
729  int oldciv;
730  int oldmil;
731  double astrength;
732  double dstrength;
733  int cas_civ;
734  int cas_mil;
735  int ammo;
736 
737  oldciv = *civ;
738  oldmil = *mil;
739 
740  strength = retal_strength(ship);
741  astrength = MECH_ATTACK * ship->tech * (double)strength *
742  ((double)ship->armor + 1.0) * .01 *
743  (100.0 - (double)ship->damage) * .01 *
744  (Race->likes[sect.condition] + 1.0) *
745  morale_factor((double)(Race->morale - alien->morale));
746 
747  dstrength = (double)(10 * oldmil * alien->fighters + oldciv) * 0.01 *
748  alien->tech * .01 * (alien->likes[sect.condition] + 1.0) *
749  ((double)Defensedata[sect.condition] + 1.0) *
750  morale_factor((double)(alien->morale - Race->morale));
751 
752  if (ignore) {
753  ammo = (int)log10((double)dstrength + 1.0) - 1;
754  ammo = std::min(std::max(ammo, 0), strength);
755  use_destruct(ship, ammo);
756  } else
757  use_destruct(ship, strength);
758 
759  cas_civ = int_rand(0, round_rand((double)oldciv * astrength / dstrength));
760  cas_civ = MIN(oldciv, cas_civ);
761  cas_mil = int_rand(0, round_rand((double)oldmil * astrength / dstrength));
762  cas_mil = MIN(oldmil, cas_mil);
763  *civ -= cas_civ;
764  *mil -= cas_mil;
765  sprintf(short_msg, "%s: %s %s %s [%d]\n", Dispshiploc(ship),
766  ship_to_string(*ship).c_str(),
767  (*civ + *mil) ? "attacked" : "slaughtered", alien->name,
768  alien->Playernum);
769  strcpy(long_msg, short_msg);
770  sprintf(buf, "\tBattle at %d,%d %s: %d guns fired on %d civ/%d mil\n", x, y,
771  Desnames[sect.condition], strength, oldciv, oldmil);
772  strcat(long_msg, buf);
773  sprintf(buf, "\tAttack: %.3f Defense: %.3f.\n", astrength, dstrength);
774  strcat(long_msg, buf);
775  sprintf(buf, "\t%d civ/%d mil killed.\n", cas_civ, cas_mil);
776  strcat(long_msg, buf);
777 }
778 
779 static void people_attack_mech(Ship *ship, int civ, int mil, racetype *Race,
780  racetype *alien, const Sector &sect, int x,
781  int y, char *long_msg, char *short_msg) {
782  int strength;
783  double astrength;
784  double dstrength;
785  int cas_civ;
786  int cas_mil;
787  int pdam;
788  int sdam;
789  int damage;
790  int ammo;
791 
792  strength = retal_strength(ship);
793 
794  dstrength = MECH_ATTACK * ship->tech * (double)strength *
795  ((double)ship->armor + 1.0) * .01 *
796  (100.0 - (double)ship->damage) * .01 *
797  (alien->likes[sect.condition] + 1.0) *
798  morale_factor((double)(alien->morale - Race->morale));
799 
800  astrength = (double)(10 * mil * Race->fighters + civ) * .01 * Race->tech *
801  .01 * (Race->likes[sect.condition] + 1.0) *
802  ((double)Defensedata[sect.condition] + 1.0) *
803  morale_factor((double)(Race->morale - alien->morale));
804  ammo = (int)log10((double)astrength + 1.0) - 1;
805  ammo = std::min(strength, std::max(0, ammo));
806  use_destruct(ship, ammo);
807  damage = int_rand(0, round_rand(100.0 * astrength / dstrength));
808  damage = std::min(100, damage);
809  ship->damage += damage;
810  if (ship->damage >= 100) {
811  ship->damage = 100;
812  kill_ship(Race->Playernum, ship);
813  }
814  do_collateral(ship, damage, &cas_civ, &cas_mil, &pdam, &sdam);
815  sprintf(short_msg, "%s: %s [%d] %s %s\n", Dispshiploc(ship), Race->name,
816  Race->Playernum, ship->alive ? "attacked" : "DESTROYED",
817  ship_to_string(*ship).c_str());
818  strcpy(long_msg, short_msg);
819  sprintf(buf, "\tBattle at %d,%d %s: %d civ/%d mil assault %s\n", x, y,
820  Desnames[sect.condition], civ, mil, Shipnames[ship->type]);
821  strcat(long_msg, buf);
822  sprintf(buf, "\tAttack: %.3f Defense: %.3f.\n", astrength, dstrength);
823  strcat(long_msg, buf);
824  sprintf(buf, "\t%d%% damage inflicted for a total of %d%%\n", damage,
825  ship->damage);
826  strcat(long_msg, buf);
827  sprintf(buf, "\t%d civ/%d mil killed %d prim/%d sec guns knocked out\n",
828  cas_civ, cas_mil, pdam, sdam);
829  strcat(long_msg, buf);
830 }
831 
832 void ground_attack(racetype *Race, racetype *alien, int *people, int what,
833  population_t *civ, population_t *mil, unsigned int def1,
834  unsigned int def2, double alikes, double dlikes,
835  double *astrength, double *dstrength, int *casualties,
836  int *casualties2, int *casualties3) {
837  int casualty_scale;
838 
839  *astrength = (double)(*people * Race->fighters * (what == MIL ? 10 : 1)) *
840  (alikes + 1.0) * ((double)def1 + 1.0) *
841  morale_factor((double)(Race->morale - alien->morale));
842  *dstrength = (double)((*civ + *mil * 10) * alien->fighters) * (dlikes + 1.0) *
843  ((double)def2 + 1.0) *
844  morale_factor((double)(alien->morale - Race->morale));
845  /* nuke both populations */
846  casualty_scale = MIN(*people * (what == MIL ? 10 : 1) * Race->fighters,
847  (*civ + *mil * 10) * alien->fighters);
848 
849  *casualties = int_rand(
850  0, round_rand((double)((casualty_scale / (what == MIL ? 10 : 1)) *
851  *dstrength / *astrength)));
852  *casualties = std::min(*people, *casualties);
853  *people -= *casualties;
854 
855  *casualties2 =
856  int_rand(0, round_rand((double)casualty_scale * *astrength / *dstrength));
857  *casualties2 = MIN(*civ, *casualties2);
858  *civ -= *casualties2;
859  /* and for troops */
860  *casualties3 = int_rand(
861  0, round_rand((double)(casualty_scale / 10) * *astrength / *dstrength));
862  *casualties3 = MIN(*mil, *casualties3);
863  *mil -= *casualties3;
864 }
void use_fuel(Ship *s, double amt)
Definition: load.cc:876
#define MIL
Definition: tweakables.h:262
void post(const char *origmsg, int type)
Definition: tele.cc:63
#define CIV
Definition: tweakables.h:261
int retal_strength(Ship *s)
Definition: fire.cc:731
double morale_factor(double x)
Definition: shlmisc.cc:239
void walk(const command_t &argv, GameObj &g)
Definition: move.cc:449
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
static void mech_defend(int, int, int *, int, const Planet &, int, int, const Sector &)
Definition: move.cc:680
#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
static void people_attack_mech(Ship *ship, int civ, int mil, racetype *Race, racetype *alien, const Sector &sect, int x, int y, char *long_msg, char *short_msg)
Definition: move.cc:779
#define MIN(x, y)
Definition: tweakables.h:213
#define MOVE_FACTOR
Definition: tweakables.h:14
void deductAPs(const player_t Playernum, const governor_t Governor, unsigned int n, starnum_t snum, int sdata)
Definition: shlmisc.cc:214
#define MECH_ATTACK
Definition: tweakables.h:290
int enufAP(int Playernum, int Governor, unsigned short AP, int x)
Definition: shlmisc.cc:131
void use_destruct(Ship *s, int amt)
Definition: load.cc:881
int get_move(char direction, int x, int y, int *x2, int *y2, const Planet &planet)
Definition: move.cc:624
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 AFV_FUEL_COST
Definition: tweakables.h:288
#define COMBAT
Definition: files.h:19
int adjacent(int fx, int fy, int tx, int ty, const Planet &p)
Definition: fire.cc:758
static void mech_attack_people(Ship *ship, int *civ, int *mil, racetype *Race, racetype *alien, const Sector &sect, int x, int y, int ignore, char *long_msg, char *short_msg)
Definition: move.cc:724
void move_popn(const command_t &argv, GameObj &g)
Definition: move.cc:150
void arm(const command_t &argv, GameObj &g)
Definition: move.cc:39
bool testship(const player_t playernum, const governor_t governor, const Ship &s)
Definition: getplace.cc:248
Sector getsector(const Planet &p, const int x, const int y)
Definition: files_shl.cc:480
int control(int Playernum, int Governor, startype *star)
Definition: mobiliz.cc:110
void do_collateral(Ship *, int, int *, int *, int *, int *)
Definition: shootblast.cc:603
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