5 #include "gb/shootblast.h" 12 #include "gb/GB_server.h" 13 #include "gb/buffers.h" 15 #include "gb/defense.h" 16 #include "gb/files_shl.h" 18 #include "gb/getplace.h" 22 #include "gb/shlmisc.h" 23 #include "gb/tweakables.h" 24 #include "gb/utils/rand.h" 30 static int do_radiation(Ship *,
double,
int,
int,
const char *,
char *);
31 static int do_damage(
int, Ship *,
double,
int,
int,
int,
int,
double,
32 const char *,
char *);
35 static int CEW_hit(
double,
int);
36 static int Num_hits(
double,
int,
int,
double,
int,
int,
int,
int,
int,
int,
int,
40 static double p_factor(
double,
double);
44 char *long_msg,
char *short_msg) {
61 char damage_msg[1024];
64 if (strength <= 0)
return -1;
66 if (!(from->alive || ignore) || !to->alive)
return -1;
67 if (from->whatorbits == ScopeLevel::LEVEL_SHIP ||
68 from->whatorbits == ScopeLevel::LEVEL_UNIV)
70 if (to->whatorbits == ScopeLevel::LEVEL_SHIP ||
71 to->whatorbits == ScopeLevel::LEVEL_UNIV)
73 if (from->storbits != to->storbits)
return -1;
74 if (has_switch(*from) && !from->on)
return -1;
85 ShipType::STYPE_MISSILE)
88 dist = sqrt((
double)
Distsq(xfrom, yfrom, xto, yto));
89 if (from->type == ShipType::STYPE_MINE) {
93 if ((
double)dist >
gun_range((Race *)
nullptr, from
, 0
))
return -1;
97 auto defense = getdefense(*to);
99 if (laser_on(*from) && from->focus)
105 hits = strength *
CEW_hit((
double)dist
, (
int)from->cew_range
);
108 Num_hits((
double)dist
, focus
, strength
, from->tech
, (
int)from->damage
, 109 fevade
, tevade
, fspeed
, tspeed
, tbody
, caliber
, defense
);
115 sprintf(short_msg,
"%s: %s %s %s\n", Dispshiploc(to),
116 ship_to_string(*from).c_str(), to->alive ?
"attacked" :
"DESTROYED",
117 ship_to_string(*to).c_str());
118 strcpy(long_msg, short_msg);
119 strcat(long_msg, damage_msg);
122 sprintf(weapon,
"strength CEW");
123 else if (laser_on(*from)) {
125 sprintf(weapon,
"strength focused laser");
127 sprintf(weapon,
"strength laser");
131 sprintf(weapon,
"light guns");
134 sprintf(weapon,
"medium guns");
137 sprintf(weapon,
"heavy guns");
140 sprintf(weapon,
"pea-shooter");
144 damage =
do_damage((
int)from->owner
, to
, (
double)from->tech
, strength
, hits
, 145 defense
, caliber
, (
double)dist
, weapon
, damage_msg
);
146 sprintf(short_msg,
"%s: %s %s %s\n", Dispshiploc(to),
147 ship_to_string(*from).c_str(), to->alive ?
"attacked" :
"DESTROYED",
148 ship_to_string(*to).c_str());
149 strcpy(long_msg, short_msg);
150 strcat(long_msg, damage_msg);
157 char *long_msg,
char *short_msg) {
163 char damage_msg[1024];
166 if (strength <= 0)
return -1;
167 if (!ship->alive)
return -1;
169 if (ship->whatorbits != ScopeLevel::LEVEL_PLAN)
return -1;
173 hits =
Num_hits(0.0
, 0
, strength
, Race->tech
, 0
, evade
, 0
, speed
, 0
, body
, 177 GTYPE_MEDIUM
, 0.0
, "medium guns", damage_msg
);
178 sprintf(short_msg,
"%s [%d] %s %s\n", Dispshiploc(ship), Race->Playernum,
179 ship->alive ?
"attacked" :
"DESTROYED",
180 ship_to_string(*ship).c_str());
181 strcpy(long_msg, short_msg);
182 strcat(long_msg, damage_msg);
189 SectorMap &smap,
int ignore,
int caliber,
190 char *long_msg,
char *short_msg) {
204 if (strength <= 0)
return -1;
205 if (!(ship->alive || ignore))
return -1;
206 if (has_switch(*ship) && !ship->on)
return -1;
207 if (ship->whatorbits != ScopeLevel::LEVEL_PLAN)
return -1;
209 if (x < 0 || x > pl->Maxx - 1 || y < 0 || y > pl->Maxy - 1)
return -1;
213 if (ship->fire_laser)
214 caliber = GTYPE_LIGHT;
216 switch (ship->guns) {
218 caliber = ship->primtype;
221 caliber = ship->sectype;
224 caliber = GTYPE_LIGHT;
228 auto &target = smap.get(x, y);
229 oldowner = target.owner;
231 for (i = 1; i <= Num_races; i++) sum_mob[i - 1] = 0;
233 for (y2 = 0; y2 < pl->Maxy; y2++) {
234 for (x2 = 0; x2 < pl->Maxx; x2++) {
237 dx = std::min(abs(x2 - x), abs(x + (pl->Maxx - 1) - x2));
239 d = sqrt((
double)(dx * dx + dy * dy));
240 auto &s = smap.get(x2, y2);
243 fac =
SECTOR_DAMAGE * (
double)strength * (
double)caliber / (d + 1.);
247 kills = int_rand(0, ((
int)(fac / 10.0) * s.popn)) /
248 (1 + (s.condition == SectorType::SEC_PLATED));
254 if (s.troops && (fac > 5.0 * (
double)Defensedata[s.condition])) {
255 kills = int_rand(0, ((
int)(fac / 20.0) * s.troops)) /
256 (1 + (s.condition == SectorType::SEC_PLATED));
257 if (kills > s.troops)
263 if (!(s.popn + s.troops)) s.owner = 0;
268 if (round_rand(fac) > Defensedata[s.condition] * int_rand(0, 10)) {
269 if (s.owner) Nuked[s.owner - 1] = 1;
271 s.troops = int_rand(0, (
int)s.troops);
275 s.resource = s.resource / ((
int)fac + 1);
278 s.crystals = int_rand(0, (
int)s.crystals);
279 s.condition = SectorType::SEC_WASTED;
282 s.fert = std::max(0, (
int)s.fert - (
int)fac);
283 s.eff = std::max(0, (
int)s.eff - (
int)fac);
284 s.mobilization = std::max(0, (
int)s.mobilization - (
int)fac);
285 s.resource = std::max(0, (
int)s.resource - (
int)fac);
288 if (s.owner) sum_mob[s.owner - 1] += s.mobilization;
291 num_sectors = pl->Maxx * pl->Maxy;
292 for (i = 1; i <= Num_races; i++) {
293 pl->info[i - 1].mob_points = sum_mob[i - 1];
294 pl->info[i - 1].comread = sum_mob[i - 1] / num_sectors;
299 pl->conditions[
TOXIC] += (100 - pl->conditions[
TOXIC]) *
300 ((
double)numdest / (
double)(pl->Maxx * pl->Maxy));
302 sprintf(short_msg,
"%s bombards %s [%d]\n", ship_to_string(*ship).c_str(),
303 Dispshiploc(ship), oldowner);
304 strcpy(long_msg, short_msg);
305 sprintf(buf,
"\t%d sectors destroyed\n", numdest);
306 strcat(long_msg, buf);
310 static int do_radiation(Ship *ship,
double tech,
int strength,
int hits,
311 const char *weapon,
char *msg) {
323 (2. / 3.14159265) * atan((
double)(5 * (tech + 1.0) / (ship->tech + 1.0)));
325 arm = std::max(0UL, armor(*ship) - hits / 5);
326 body = shipbody(*ship);
330 for (i = 1; i <= arm; i++) r *= fac;
332 for (i = 1; i <= hits; i++)
333 if (double_rand() <= r) penetrate += 1;
335 dosage = round_rand(40. * (
double)penetrate / (
double)body);
336 dosage = std::min(100, dosage);
338 if (dosage > ship->rad) ship->rad = std::max(ship->rad, dosage);
339 if (success(ship->rad)) ship->active = 0;
343 sprintf(buf,
"\tAttack: %d %s\n\t Hits: %d\n", strength, weapon, hits);
345 sprintf(buf,
"\t Rad: %d%% for a total of %d%%\n", dosage, ship->rad);
347 if (casualties || casualties1) {
348 sprintf(buf,
"\tKilled: %d civ + %d mil\n", casualties, casualties1);
354 static int do_damage(
int who, Ship *ship,
double tech,
int strength,
int hits,
355 int defense,
int caliber,
double range,
const char *weapon,
372 sprintf(buf,
"\tAttack: %d %s at a range of %.0f\n", strength, weapon, range);
378 if (success(hits * caliber)) {
380 sprintf(buf,
"\t\tArmor reduced to %d\n", ship->armor);
386 arm = std::max(0UL, armor(*ship) + defense - hits / 5);
387 body = sqrt((
double)(0.1 * shipbody(*ship)));
393 for (i = 1; i <= arm; i++) r *= fac;
395 for (i = 1; i <= hits; i++)
396 if (double_rand() <= r) penetrate += 1;
398 damage = round_rand(
SHIP_DAMAGE * (
double)caliber * (
double)penetrate /
403 if (crithits) damage += critdam;
405 damage = std::min(100, damage);
406 ship->damage = std::min(100, (
int)(ship->damage) + damage);
410 if (ship->fire_laser) {
412 safe = (
int)((1.0 - .01 * ship->damage) * ship->tech / 4.0);
413 if (ship->fire_laser > safe) ship->fire_laser = safe;
417 sprintf(buf,
"\t\t%d penetrations eff armor=%d defense=%d prob=%.3f\n",
418 penetrate, arm, defense, r);
422 sprintf(buf,
"\t\t%d CRITICAL hits do %d%% damage\n", crithits, critdam);
424 strcat(msg, critmsg);
427 sprintf(buf,
"\tDamage: %d%% damage for a total of %d%%\n", damage,
431 if (primgundamage || secgundamage) {
432 sprintf(buf,
"\t Other: %d primary/%d secondary guns destroyed\n",
433 primgundamage, secgundamage);
436 if (casualties || casualties1) {
437 sprintf(buf,
"\tKilled: %d civ + %d mil casualties\n", casualties,
442 if (ship->damage >= 100) kill_ship(who, ship);
443 ship->build_cost = (
int)cost(*ship);
451 if (ship->active && !ship->docked && (ship->whatdest || ship->navigate.on)) {
452 *evade = ship->protect.evade;
453 *speed = ship->speed;
457 static int CEW_hit(
double dist,
int cew_range) {
464 if (success(prob)) hits = 1;
469 static int Num_hits(
double dist,
int focus,
int guns,
double tech,
int fdam,
470 int fev,
int tev,
int fspeed,
int tspeed,
int body,
471 int caliber,
int defense) {
482 if (success(prob * prob / 100)) hits = guns;
485 for (i = 1; i <= guns; i++)
486 if (success(prob)) hits++;
493 int hit_odds(
double range,
int *factor,
double tech,
int fdam,
int fev,
int tev,
494 int fspeed,
int tspeed,
int body,
int caliber,
int defense) {
500 if (caliber == GTYPE_NONE) {
505 a = log10(1.0 + (
double)tech) * 80.0 * pow((
double)body, 0.33333);
506 b = 72.0 / ((2.0 + (
double)tev) * (2.0 + (
double)fev) *
507 (18.0 + (
double)tspeed + (
double)fspeed));
508 c = a * b / (
double)caliber;
509 *factor = (
int)(c * (1.0 - (
double)fdam / 100.));
513 (
int)((
double)((*factor) * 100) / ((
double)((*factor) + (
int)range)));
514 odds = (
int)((
double)odds * (1.0 - 0.1 * (
double)defense));
522 factor = (range + 1.0) / ((
double)cew_range + 1.0);
523 odds = (
int)(100.0 * exp((
double)(-50.0 * (factor - 1.0) * (factor - 1.0))));
531 if (mode)
return (logscale((
int)(r->tech + 1.0)) *
SYSTEMSIZE);
533 return (logscale((
int)(s->tech + 1.0)) *
SYSTEMSIZE);
540 if (type == ShipType::OTYPE_GTELE)
541 return log1p((
double)tech) * 400 +
SYSTEMSIZE / 8;
543 return log1p((
double)tech) * 1500 +
SYSTEMSIZE / 3;
547 if (ship->laser && ship->fire_laser)
return GTYPE_LIGHT;
548 if (ship->type == ShipType::STYPE_MINE)
return GTYPE_LIGHT;
549 if (ship->type == ShipType::STYPE_MISSILE)
return GTYPE_HEAVY;
550 if (ship->guns ==
PRIMARY)
return ship->primtype;
551 if (ship->guns ==
SECONDARY)
return ship->sectype;
557 int *critdam,
int caliber,
char *critmsg) {
563 eff_size = std::max(1, shipbody(*ship) / caliber);
564 for (i = 1; i <= penetrate; i++)
565 if (!int_rand(0, eff_size - 1)) {
567 dam = int_rand(0, 100);
570 *critdam = std::min(100, *critdam);
572 strcpy(critmsg,
"\t\tSpecial systems damage: ");
573 if (ship->cew && success(*critdam)) {
574 strcat(critmsg,
"CEW ");
577 if (ship->laser && success(*critdam)) {
578 strcat(critmsg,
"Laser ");
581 if (ship->cloak && success(*critdam)) {
582 strcat(critmsg,
"Cloak ");
585 if (ship->hyper_drive.has && success(*critdam)) {
586 strcat(critmsg,
"Hyper-drive ");
587 ship->hyper_drive.has = 0;
589 if (ship->max_speed && success(*critdam)) {
591 ship->max_speed = int_rand(0, (
int)ship->max_speed - 1);
592 sprintf(buf,
"Speed=%d ", ship->max_speed);
593 strcat(critmsg, buf);
595 if (ship->armor && success(*critdam)) {
596 ship->armor = int_rand(0, (
int)ship->armor - 1);
597 sprintf(buf,
"Armor=%d ", ship->armor);
598 strcat(critmsg, buf);
600 strcat(critmsg,
"\n");
603 void do_collateral(Ship *ship,
int damage,
int *casualties,
int *casualties1,
604 int *primgundamage,
int *secgundamage) {
612 for (i = 1; i <= ship->popn; i++) *casualties += success(damage);
613 ship->popn -= *casualties;
614 for (i = 1; i <= ship->troops; i++) *casualties1 += success(damage);
615 ship->troops -= *casualties1;
616 for (i = 1; i <= ship->primary; i++) *primgundamage += success(damage);
617 ship->primary -= *primgundamage;
618 for (i = 1; i <= ship->secondary; i++) *secgundamage += success(damage);
619 ship->secondary -= *secgundamage;
620 if (!ship->primary) ship->primtype = GTYPE_NONE;
621 if (!ship->secondary) ship->sectype = GTYPE_NONE;
624 static double p_factor(
double attacker,
double defender) {
625 return ((2. / 3.141592) *
626 atan(5 * (
double)((attacker + 1.0) / (defender + 1.0))));
630 if (points < 0)
return 0;
631 return std::min(20, points / 1000);
635 if (int_rand(0, 6) >= Defensedata[s.condition]) s.condition = s.type;
static void do_critical_hits(int, Ship *, int *, int *, int, char *)
static void mutate_sector(Sector &)
#define Distsq(x1, y1, x2, y2)
int current_caliber(Ship *)
static void ship_disposition(Ship *, int *, int *, int *)
static int do_radiation(Ship *, double, int, int, const char *, char *)
int shoot_ship_to_ship(Ship *, Ship *, int, int, int, char *, char *)
int shoot_ship_to_planet(Ship *, Planet *, int, int, int, SectorMap &, int, int, char *, char *)
static double penetration_factor
int shoot_planet_to_ship(Race *, Ship *, int, char *, char *)
int hit_odds(double, int *, double, int, int, int, int, int, int, int, int)
static int CEW_hit(double, int)
static int Num_hits(double, int, int, double, int, int, int, int, int, int, int, int)
static int cew_hit_odds(double, int)
static int do_damage(int, Ship *, double, int, int, int, int, double, const char *, char *)
double gun_range(Race *, Ship *, int)
static double p_factor(double, double)
double tele_range(int, double)
void do_collateral(Ship *, int, int *, int *, int *, int *)
static int hit_probability