14 #include "gb/GB_server.h" 15 #include "gb/buffers.h" 16 #include "gb/defense.h" 18 #include "gb/files_shl.h" 20 #include "gb/getplace.h" 22 #include "gb/mobiliz.h" 25 #include "gb/shlmisc.h" 26 #include "gb/shootblast.h" 28 #include "gb/tweakables.h" 29 #include "gb/utils/rand.h" 32 static void mech_defend(
int,
int,
int *,
int,
const Planet &,
int,
int,
35 const Sector &,
int,
int,
int,
char *,
char *);
37 int,
int,
char *,
char *);
39 void arm(
const command_t &argv, GameObj &g) {
40 const player_t Playernum = g.player;
41 const governor_t Governor = g.governor;
43 if (argv[0] ==
"arm") {
55 if (g.level != ScopeLevel::LEVEL_PLAN) {
56 g.out <<
"Change scope to planet level first.\n";
60 g.out <<
"You are not authorized to do that here.\n";
65 if (planet.slaved_to > 0 && planet.slaved_to != Playernum) {
66 g.out <<
"That planet has been enslaved!\n";
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";
77 if (sect.owner != Playernum) {
78 g.out <<
"You don't own that sector.\n";
82 max_allowed =
MIN(sect.popn, planet.info[Playernum - 1].destruct *
83 (sect.mobilization + 1));
87 amount = std::stoul(argv[2]);
89 g.out <<
"You must specify a positive number of civs to arm.\n";
93 amount = std::min(amount, max_allowed);
95 g.out <<
"You can't arm any civilians now.\n";
98 Race = races[Playernum - 1];
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,
104 notify(Playernum, Governor, buf);
107 Race->governor[Governor].money -= enlist_cost;
110 cost = std::max(1U, amount / (sect.mobilization + 1));
111 sect.troops += 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;
119 "%d population armed at a cost of %ldd (now %lu civilians, %lu " 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);
127 amount = sect.troops;
129 amount = std::stoi(argv[2]);
131 g.out <<
"You must specify a positive number of civs to arm.\n";
134 amount =
MIN(sect.troops, 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);
151 const player_t Playernum = g.player;
152 const governor_t Governor = g.governor;
154 if (argv[0] ==
"move") {
183 if (g.level != ScopeLevel::LEVEL_PLAN) {
184 sprintf(buf,
"Wrong scope\n");
187 if (!
control(Playernum
, Governor
, Stars[g.snum]
)) {
188 g.out <<
"You are not authorized to do that here.\n";
193 if (planet.slaved_to > 0 && planet.slaved_to != Playernum) {
194 sprintf(buf,
"That planet has been enslaved!\n");
195 notify(Playernum, Governor, buf);
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);
210 if (sect.owner != Playernum) {
211 sprintf(buf,
"You don't own sector %d,%d!\n", x, y);
212 notify(Playernum, Governor, buf);
215 if (!get_move(argv[2][n++], x, y, &x2, &y2, planet)) {
216 g.out <<
"Finished.\n";
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);
229 sprintf(buf,
"Illegal move - to adjacent sectors only!\n");
230 notify(Playernum, Governor, buf);
236 if (argv.size() >= 4) {
237 people = std::stoi(argv[3]);
240 people = sect.popn + people;
241 else if (what ==
MIL)
242 people = sect.troops + people;
247 else if (what ==
MIL)
248 people = sect.troops;
251 if ((what ==
CIV && (abs(people) > sect.popn)) ||
252 (what ==
MIL && (abs(people) > sect.troops)) || people <= 0) {
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);
262 sprintf(buf,
"%d %s moved.\n", people,
263 what ==
CIV ?
"population" :
"troops");
264 notify(Playernum, Governor, buf);
272 g.out <<
"Attack aborted.\n";
276 if (sect2.owner && (sect2.owner != Playernum))
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;
287 if (!
enufAP(Playernum
, Governor
, Stars[g.snum]->AP[Playernum - 1]
, 294 ground_assaults[Playernum - 1][sect2.owner - 1][g.snum] += 1;
295 Race = races[Playernum - 1];
296 alien = races[sect2.owner - 1];
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);
303 old2owner = (
int)(sect2.owner);
304 old2gov = Stars[g.snum]->governor[sect2.owner - 1];
306 sect.popn = std::max(0UL, sect.popn - people);
307 else if (what ==
MIL)
308 sect.troops = std::max(0UL, sect.troops - people);
311 sprintf(buf,
"%d civ assault %lu civ/%lu mil\n", people, sect2.popn,
313 else if (what ==
MIL)
314 sprintf(buf,
"%d mil assault %lu civ/%lu mil\n", people, sect2.popn,
316 notify(Playernum, Governor, buf);
318 old2popn = sect2.popn;
319 old3popn = sect2.troops;
322 Defensedata[sect.condition]
, Defensedata[sect2.condition]
, 323 Race->likes[sect.condition]
, alien->likes[sect2.condition]
, 324 &astrength
, &dstrength
, &casualties
, &casualties2
, 327 sprintf(buf,
"Attack: %.2f Defense: %.2f.\n", astrength, dstrength);
328 notify(Playernum, Governor, buf);
330 if (!(sect2.popn + sect2.troops)) {
331 sect2.owner = Playernum;
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);
342 sect2.popn = people + absorbed;
343 else if (what ==
MIL) {
344 sect2.popn = absorbed;
345 sect2.troops = people;
347 adjust_morale(Race, alien, (
int)alien->fighters);
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;
360 else if (what ==
MIL)
361 sect.troops += people;
362 adjust_morale(alien, Race, (
int)Race->fighters);
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"));
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);
378 sprintf(buf,
"%d %s move in.\n", people,
379 what ==
CIV ?
"civilians" :
"troops");
380 notify(Playernum, Governor, buf);
382 planet.info[Playernum - 1].mob_points += (
int)sect2.mobilization;
383 planet.info[old2owner - 1].mob_points -= (
int)sect2.mobilization;
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);
392 if (!(sect.popn + sect.troops + people)) {
393 sprintf(buf,
"You killed all of them!\n");
394 strcat(telegram_buf, buf);
396 Race->translate[old2owner - 1] =
397 MIN(Race->translate[old2owner - 1] + 5, 100);
400 sprintf(buf,
"Oh no! They killed your party to the last man!\n");
401 notify(Playernum, Governor, buf);
403 alien->translate[Playernum - 1] =
404 MIN(alien->translate[Playernum - 1] + 5, 100);
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);
419 sect2.popn += people;
420 }
else if (what ==
MIL) {
421 sect.troops -= people;
422 sect2.troops += people;
425 planet.info[Playernum - 1].mob_points += (
int)sect2.mobilization;
426 sect2.owner = Playernum;
429 if (!(sect.popn + sect.troops)) {
430 planet.info[Playernum - 1].mob_points -= (
int)sect.mobilization;
434 if (!(sect2.popn + sect2.troops)) {
446 g.out <<
"Finished.\n";
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;
468 if (argv.size() < 2) {
469 g.out <<
"Walk what?\n";
472 auto shipno = string_to_shipnum(argv[1]);
473 if (!shipno || !getship(&ship, *shipno)) {
474 g.out <<
"No such ship.\n";
478 g.out <<
"You do not control this ship.\n";
482 if (ship->type != ShipType::OTYPE_AFV) {
483 g.out <<
"This ship doesn't walk!\n";
487 if (!landed(*ship)) {
488 g.out <<
"This ship is not landed on a planet.\n";
493 g.out <<
"No crew.\n";
498 sprintf(buf,
"You don't have %.1f fuel to move it.\n",
AFV_FUEL_COST);
499 notify(Playernum, Governor, buf);
503 if (!
enufAP(Playernum
, Governor
, Stars[ship->storbits]->AP[Playernum - 1]
, 508 auto p =
getplanet((
int)ship->storbits
, (
int)ship->pnumorbits
);
509 Race = races[Playernum - 1];
511 if (!get_move(argv[2][0], (
int)ship->land_x, (
int)ship->land_y, &x, &y, p)) {
512 g.out <<
"Illegal move.\n";
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);
525 if (!Race->likes[sect.condition]) {
526 notify(Playernum, Governor,
527 "Your ships cannot walk into that sector type!\n");
532 Shiplist shiplist{p.ships};
533 for (
auto ship2 : shiplist) {
534 if (ship2.owner != Playernum && ship2.type == ShipType::OTYPE_AFV &&
536 (ship2.land_y == y)) {
537 alien = races[ship2.owner - 1];
538 if (!
isset(Race->allied, (
int)ship2.owner) ||
539 !
isset(alien->allied, Playernum)) {
542 bcopy(ship, &dummy,
sizeof(Ship));
544 notify(Playernum, Governor, long_buf);
545 warn(ship2.owner, ship2.governor, long_buf);
547 notify_star(Playernum, Governor, ship->storbits, short_buf);
550 notify(Playernum, Governor, long_buf);
551 warn(ship2.owner, ship2.governor, long_buf);
553 notify_star(Playernum, Governor, ship->storbits, short_buf);
559 if (!ship->alive)
break;
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)) {
568 g.out <<
"You have nothing to attack with!\n";
573 civ = (
int)sect.popn;
574 mil = (
int)sect.troops;
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);
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);
591 if (!(sect.popn + sect.troops)) {
592 p.info[sect.owner - 1].mob_points -= (
int)sect.mobilization;
603 if ((sect.owner == Playernum ||
isset(Race->allied, (
int)sect.owner) ||
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));
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);
624 int get_move(
char direction,
int x,
int y,
int *x2,
int *y2,
625 const Planet &planet) {
631 if (*x2 == -1) *x2 = planet.Maxx - 1;
642 if (*x2 == planet.Maxx) *x2 = 0;
648 if (*x2 == -1) *x2 = planet.Maxx - 1;
654 if (*x2 == planet.Maxx) *x2 = 0;
660 if (*x2 == -1) *x2 = planet.Maxx - 1;
671 if (*x2 == planet.Maxx) *x2 = 0;
680 static void mech_defend(
int Playernum,
int Governor,
int *people,
int type,
681 const Planet &p,
int x2,
int y2,
const Sector &s2) {
693 Race = races[Playernum - 1];
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 &&
700 (ship.land_y == y2)) {
701 alien = races[ship.owner - 1];
702 if (!
isset(Race->allied, ship.owner) ||
703 !
isset(alien->allied, Playernum)) {
705 oldgov = Stars[ship.storbits]->governor[alien->Playernum - 1];
707 long_buf
, short_buf
);
708 notify(Playernum, Governor, long_buf);
709 warn(alien->Playernum, oldgov, long_buf);
712 long_buf
, short_buf
);
713 notify(Playernum, Governor, long_buf);
714 warn(alien->Playernum, oldgov, long_buf);
725 racetype *alien,
const Sector §,
int x,
726 int y,
int ignore,
char *long_msg,
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) *
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) *
753 ammo = (
int)log10((
double)dstrength + 1.0) - 1;
754 ammo = std::min(std::max(ammo, 0), strength);
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);
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,
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);
780 racetype *alien,
const Sector §,
int x,
781 int y,
char *long_msg,
char *short_msg) {
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) *
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) *
804 ammo = (
int)log10((
double)astrength + 1.0) - 1;
805 ammo = std::min(strength, std::max(0, 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) {
812 kill_ship(Race->Playernum, ship);
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,
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);
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) {
839 *astrength = (
double)(*people * Race->fighters * (what ==
MIL ? 10 : 1)) *
840 (alikes + 1.0) * ((
double)def1 + 1.0) *
842 *dstrength = (
double)((*civ + *mil * 10) * alien->fighters) * (dlikes + 1.0) *
843 ((
double)def2 + 1.0) *
846 casualty_scale =
MIN(*people * (what ==
MIL ? 10 : 1) * Race->fighters,
847 (*civ + *mil * 10) * alien->fighters);
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;
856 int_rand(0, round_rand((
double)casualty_scale * *astrength / *dstrength));
857 *casualties2 =
MIN(*civ, *casualties2);
858 *civ -= *casualties2;
860 *casualties3 = int_rand(
861 0, round_rand((
double)(casualty_scale / 10) * *astrength / *dstrength));
862 *casualties3 =
MIN(*mil, *casualties3);
863 *mil -= *casualties3;
void use_fuel(Ship *s, double amt)
void post(const char *origmsg, int type)
int retal_strength(Ship *s)
double morale_factor(double x)
void walk(const command_t &argv, GameObj &g)
Planet getplanet(const starnum_t star, const planetnum_t pnum)
static void mech_defend(int, int, int *, int, const Planet &, int, int, const Sector &)
void putsector(const Sector &s, const Planet &p, const int x, const int y)
static void people_attack_mech(Ship *ship, int civ, int mil, racetype *Race, racetype *alien, const Sector §, int x, int y, char *long_msg, char *short_msg)
void deductAPs(const player_t Playernum, const governor_t Governor, unsigned int n, starnum_t snum, int sdata)
int enufAP(int Playernum, int Governor, unsigned short AP, int x)
void use_destruct(Ship *s, int amt)
int get_move(char direction, int x, int y, int *x2, int *y2, const Planet &planet)
void putplanet(const Planet &p, startype *star, const int pnum)
int adjacent(int fx, int fy, int tx, int ty, const Planet &p)
static void mech_attack_people(Ship *ship, int *civ, int *mil, racetype *Race, racetype *alien, const Sector §, int x, int y, int ignore, char *long_msg, char *short_msg)
void move_popn(const command_t &argv, GameObj &g)
void arm(const command_t &argv, GameObj &g)
bool testship(const player_t playernum, const governor_t governor, const Ship &s)
Sector getsector(const Planet &p, const int x, const int y)
int control(int Playernum, int Governor, startype *star)
void do_collateral(Ship *, int, int *, int *, int *, int *)
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)