Galactic Bloodshed
doship.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 /* doship -- do one ship turn. */
6 
7 #include "gb/doship.h"
8 
9 #include <cmath>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 
14 #include "gb/GB_server.h"
15 #include "gb/VN.h"
16 #include "gb/buffers.h"
17 #include "gb/build.h"
18 #include "gb/doturn.h"
19 #include "gb/files.h"
20 #include "gb/files_shl.h"
21 #include "gb/fire.h"
22 #include "gb/load.h"
23 #include "gb/max.h"
24 #include "gb/moveship.h"
25 #include "gb/perm.h"
26 #include "gb/power.h"
27 #include "gb/races.h"
28 #include "gb/ships.h"
29 #include "gb/shlmisc.h"
30 #include "gb/shootblast.h"
31 #include "gb/tele.h"
32 #include "gb/tweakables.h"
33 #include "gb/utils/rand.h"
34 #include "gb/vars.h"
35 
36 static double ap_planet_factor(Planet *);
37 static double crew_factor(Ship *);
38 static void do_ap(Ship *);
39 static void do_canister(Ship *);
40 static void do_greenhouse(Ship *);
41 static void do_god(Ship *);
42 static void do_habitat(Ship *);
43 static void do_meta_infect(int, Planet *);
44 static void do_mirror(Ship *);
45 static void do_oap(Ship *);
46 static void do_pod(Ship *);
47 static void do_repair(Ship *);
48 static int infect_planet(int, int, int);
49 
50 void doship(Ship *ship, int update) {
51  racetype *Race;
52 
53  /*ship is active */
54  ship->active = 1;
55 
56  if (!ship->owner) ship->alive = 0;
57 
58  if (ship->alive) {
59  /* repair radiation */
60  if (ship->rad) {
61  ship->active = 1;
62  /* irradiated ships are immobile.. */
63  /* kill off some people */
64  /* check to see if ship is active */
65  if (success(ship->rad)) ship->active = 0;
66  if (update) {
67  ship->popn = round_rand(ship->popn * .80);
68  ship->troops = round_rand(ship->troops * .80);
69  if (ship->rad >= (int)REPAIR_RATE)
70  ship->rad -= int_rand(0, (int)REPAIR_RATE);
71  else
72  ship->rad -= int_rand(0, (int)ship->rad);
73  }
74  } else
75  ship->active = 1;
76 
77  if (!ship->popn && max_crew(*ship) && !ship->docked)
78  ship->whatdest = ScopeLevel::LEVEL_UNIV;
79 
80  if (ship->whatorbits != ScopeLevel::LEVEL_UNIV &&
81  Stars[ship->storbits]->nova_stage > 0) {
82  /* damage ships from supernovae */
83  /* Maarten: modified to take into account MOVES_PER_UPDATE */
84  ship->damage += 5 * Stars[ship->storbits]->nova_stage /
85  ((armor(*ship) + 1) * segments);
86  if (ship->damage >= 100) {
87  kill_ship((int)(ship->owner), ship);
88  return;
89  }
90  }
91 
92  if (ship->type == ShipType::OTYPE_FACTORY && !ship->on) {
93  Race = races[ship->owner - 1];
94  ship->tech = Race->tech;
95  }
96 
97  if (ship->active) moveship(ship, update, 1, 0);
98 
99  ship->size = ship_size(*ship); /* for debugging */
100 
101  if (ship->whatorbits == ScopeLevel::LEVEL_SHIP) {
102  auto ship2 = getship(ship->destshipno);
103  if (ship2->owner != ship->owner) {
104  ship2->owner = ship->owner;
105  ship2->governor = ship->governor;
106  putship(&*ship2);
107  }
108  /* just making sure */
109  } else if (ship->whatorbits != ScopeLevel::LEVEL_UNIV &&
110  (ship->popn || ship->type == ShipType::OTYPE_PROBE)) {
111  /* Though I have often used TWCs for exploring, I don't think it is right
112  */
113  /* to be able to map out worlds with this type of junk. Either a manned
114  * ship, */
115  /* or a probe, which is designed for this kind of work. Maarten */
116  StarsInhab[ship->storbits] = 1;
117  setbit(Stars[ship->storbits]->inhabited, ship->owner);
118  setbit(Stars[ship->storbits]->explored, ship->owner);
119  if (ship->whatorbits == ScopeLevel::LEVEL_PLAN) {
120  planets[ship->storbits][ship->pnumorbits]
121  ->info[ship->owner - 1]
122  .explored = 1;
123  }
124  }
125 
126  /* add ships, popn to total count to add AP's */
127  if (update) {
128  Power[ship->owner - 1].ships_owned++;
129  Power[ship->owner - 1].resource += ship->resource;
130  Power[ship->owner - 1].fuel += ship->fuel;
131  Power[ship->owner - 1].destruct += ship->destruct;
132  Power[ship->owner - 1].popn += ship->popn;
133  Power[ship->owner - 1].troops += ship->troops;
134  }
135 
136  if (ship->whatorbits == ScopeLevel::LEVEL_UNIV) {
137  Sdatanumships[ship->owner - 1]++;
138  Sdatapopns[ship->owner] += ship->popn;
139  } else {
140  starnumships[ship->storbits][ship->owner - 1]++;
141  /* add popn of ships to popn */
142  starpopns[ship->storbits][ship->owner - 1] += ship->popn;
143  /* set inhabited for ship */
144  /* only if manned or probe. Maarten */
145  if (ship->popn || ship->type == ShipType::OTYPE_PROBE) {
146  StarsInhab[ship->storbits] = 1;
147  setbit(Stars[ship->storbits]->inhabited, ship->owner);
148  setbit(Stars[ship->storbits]->explored, ship->owner);
149  }
150  }
151 
152  if (ship->active) {
153  /* bombard the planet */
154  if (can_bombard(*ship) && ship->bombard &&
155  ship->whatorbits == ScopeLevel::LEVEL_PLAN &&
156  ship->whatdest == ScopeLevel::LEVEL_PLAN &&
157  ship->deststar == ship->storbits &&
158  ship->destpnum == ship->pnumorbits) {
159  /* ship bombards planet */
160  Stinfo[ship->storbits][ship->pnumorbits].inhab = 1;
161  }
162 
163  /* repair ship by the amount of crew it has */
164  /* industrial complexes can repair (robot ships
165  and offline factories can't repair) */
166  if (ship->damage && repair(*ship)) do_repair(ship);
167 
168  if (update) switch (ship->type) { /* do this stuff during updates only*/
169  case ShipType::OTYPE_CANIST:
170  do_canister(ship);
171  break;
172  case ShipType::OTYPE_GREEN:
173  do_greenhouse(ship);
174  break;
175  case ShipType::STYPE_MIRROR:
176  do_mirror(ship);
177  break;
178  case ShipType::STYPE_GOD:
179  do_god(ship);
180  break;
181  case ShipType::OTYPE_AP:
182  do_ap(ship);
183  break;
184  case ShipType::OTYPE_VN: /* Von Neumann machine */
185  case ShipType::OTYPE_BERS:
186  if (!ship->special.mind.progenitor)
187  ship->special.mind.progenitor = 1;
188  do_VN(ship);
189  break;
190  case ShipType::STYPE_OAP:
191  do_oap(ship);
192  break;
193  case ShipType::STYPE_HABITAT:
194  do_habitat(ship);
195  break;
196  default:
197  break;
198  }
199  if (ship->type == ShipType::STYPE_POD) do_pod(ship);
200  }
201  }
202 }
203 
204 void domass(Ship *ship) {
205  double rmass;
206  int sh;
207 
208  rmass = races[ship->owner - 1]->mass;
209 
210  sh = ship->ships;
211  ship->mass = 0.0;
212  ship->hanger = 0;
213  while (sh) {
214  domass(ships[sh]); /* recursive call */
215  ship->mass += ships[sh]->mass;
216  ship->hanger += ships[sh]->size;
217  sh = ships[sh]->nextship;
218  }
219  ship->mass += getmass(*ship);
220  ship->mass += (double)(ship->popn + ship->troops) * rmass;
221  ship->mass += (double)ship->destruct * MASS_DESTRUCT;
222  ship->mass += ship->fuel * MASS_FUEL;
223  ship->mass += (double)ship->resource * MASS_RESOURCE;
224 }
225 
226 void doown(Ship *ship) {
227  int sh;
228  sh = ship->ships;
229  while (sh) {
230  doown(ships[sh]); /* recursive call */
231  ships[sh]->owner = ship->owner;
232  ships[sh]->governor = ship->governor;
233  sh = ships[sh]->nextship;
234  }
235 }
236 
237 void domissile(Ship *ship) {
238  int sh2;
239  int bombx;
240  int bomby;
241  int numdest;
242  int pdn;
243  int i;
244  double dist;
245 
246  if (!ship->alive || !ship->owner) return;
247  if (!ship->on || ship->docked) return;
248 
249  /* check to see if it has arrived at it's destination */
250  if (ship->whatdest == ScopeLevel::LEVEL_PLAN &&
251  ship->whatorbits == ScopeLevel::LEVEL_PLAN &&
252  ship->destpnum == ship->pnumorbits) {
253  auto p = planets[ship->storbits][ship->pnumorbits];
254  /* check to see if PDNs are present */
255  pdn = 0;
256  sh2 = p->ships;
257  while (sh2 && !pdn) {
258  if (ships[sh2]->alive && ships[sh2]->type == ShipType::OTYPE_PLANDEF) {
259  /* attack the PDN instead */
260  ship->whatdest =
261  ScopeLevel::LEVEL_SHIP; /* move missile to PDN for attack */
262  ship->xpos = ships[sh2]->xpos;
263  ship->ypos = ships[sh2]->ypos;
264  ship->destshipno = sh2;
265  pdn = sh2;
266  }
267  sh2 = ships[sh2]->nextship;
268  }
269  if (!pdn) {
270  if (ship->special.impact.scatter) {
271  bombx = int_rand(1, (int)p->Maxx) - 1;
272  bomby = int_rand(1, (int)p->Maxy) - 1;
273  } else {
274  bombx = ship->special.impact.x % p->Maxx;
275  bomby = ship->special.impact.y % p->Maxy;
276  }
277  sprintf(buf, "%s dropped on sector %d,%d at planet %s.\n",
278  ship_to_string(*ship).c_str(), bombx, bomby,
279  prin_ship_orbits(ship));
280 
281  auto smap = getsmap(*p);
282  numdest = shoot_ship_to_planet(ship, p, (int)ship->destruct, bombx, bomby,
283  smap, 0, GTYPE_HEAVY, long_buf, short_buf);
284  putsmap(smap, *p);
285  push_telegram((int)ship->owner, (int)ship->governor, long_buf);
286  kill_ship((int)ship->owner, ship);
287  sprintf(buf, "%s dropped on %s.\n\t%d sectors destroyed.\n",
288  ship_to_string(*ship).c_str(), prin_ship_orbits(ship), numdest);
289  for (i = 1; i <= Num_races; i++)
290  if (p->info[i - 1].numsectsowned && i != ship->owner)
291  push_telegram(i, Stars[ship->storbits]->governor[i - 1], buf);
292  if (numdest) {
293  sprintf(buf, "%s dropped on %s.\n", ship_to_string(*ship).c_str(),
294  prin_ship_orbits(ship));
295  post(buf, COMBAT);
296  }
297  }
298  } else if (ship->whatdest == ScopeLevel::LEVEL_SHIP) {
299  sh2 = ship->destshipno;
300  dist = sqrt(
301  Distsq(ship->xpos, ship->ypos, ships[sh2]->xpos, ships[sh2]->ypos));
302  if (dist <= ((double)ship->speed * STRIKE_DISTANCE_FACTOR *
303  (100.0 - (double)ship->damage) / 100.0)) {
304  /* do the attack */
305  (void)shoot_ship_to_ship(ship, ships[sh2], (int)ship->destruct, 0, 0,
306  long_buf, short_buf);
307  push_telegram((int)ship->owner, (int)ship->governor, long_buf);
308  push_telegram((int)ships[sh2]->owner, (int)ships[sh2]->governor,
309  long_buf);
310  kill_ship((int)ship->owner, ship);
311  post(short_buf, COMBAT);
312  }
313  }
314 }
315 
316 void domine(int shipno, int detonate) {
317  int i;
318  shipnum_t sh;
319  Race *r;
320 
321  auto ship = getship(shipno);
322 
323  if (ship->type != ShipType::STYPE_MINE || !ship->alive || !ship->owner) {
324  return;
325  }
326  /* check around and see if we should explode. */
327  if (ship->on || detonate) {
328  double xd;
329  double yd;
330  double range;
331 
332  switch (ship->whatorbits) {
333  case ScopeLevel::LEVEL_STAR:
334  sh = Stars[ship->storbits]->ships;
335  break;
336  case ScopeLevel::LEVEL_PLAN: {
337  const auto planet = getplanet(ship->storbits, ship->pnumorbits);
338  sh = planet.ships;
339  } break;
340  default:
341  return;
342  }
343  /* traverse the list, look for ships that
344  are closer than the trigger radius... */
345  bool rad = false;
346  if (!detonate) {
347  r = races[ship->owner - 1];
348  Shiplist shiplist(sh);
349  for (auto s : shiplist) {
350  xd = s.xpos - ship->xpos;
351  yd = s.ypos - ship->ypos;
352  range = sqrt(xd * xd + yd * yd);
353  if (!isset(r->allied, s.owner) && (s.owner != ship->owner) &&
354  ((int)range <= ship->special.trigger.radius)) {
355  rad = true;
356  break;
357  }
358  }
359  } else
360  rad = true;
361 
362  if (rad) {
363  sprintf(buf, "%s detonated at %s\n", ship_to_string(*ship).c_str(),
364  prin_ship_orbits(&*ship));
365  post(buf, COMBAT);
366  notify_star(ship->owner, ship->governor, ship->storbits, buf);
367  Shiplist shiplist(sh);
368  for (auto s : shiplist) {
369  if (sh != shipno && s.alive && (s.type != ShipType::OTYPE_CANIST) &&
370  (s.type != ShipType::OTYPE_GREEN)) {
371  auto damage = shoot_ship_to_ship(&*ship, &s, (int)(ship->destruct), 0,
372  0, long_buf, short_buf);
373  if (damage > 0) {
374  post(short_buf, COMBAT);
375  warn(s.owner, s.governor, long_buf);
376  putship(&s);
377  }
378  }
379  }
380 
381  /* if the mine is in orbit around a planet, nuke the planet too! */
382  if (ship->whatorbits == ScopeLevel::LEVEL_PLAN) {
383  /* pick a random sector to nuke */
384  int x;
385  int y;
386  int numdest;
387  auto planet = getplanet((int)ship->storbits, (int)ship->pnumorbits);
388  if (landed(*ship)) {
389  x = ship->land_x;
390  y = ship->land_y;
391  } else {
392  x = int_rand(0, (int)planet.Maxx - 1);
393  y = int_rand(0, (int)planet.Maxy - 1);
394  }
395  auto smap = getsmap(planet);
396  numdest =
397  shoot_ship_to_planet(&*ship, &planet, (int)(ship->destruct), x, y,
398  smap, 0, GTYPE_LIGHT, long_buf, short_buf);
399  putsmap(smap, planet);
400  putplanet(planet, Stars[ship->storbits], (int)ship->pnumorbits);
401 
402  sprintf(telegram_buf, "%s", buf);
403  if (numdest > 0) {
404  sprintf(buf, " - %d sectors destroyed.", numdest);
405  strcat(telegram_buf, buf);
406  }
407  strcat(telegram_buf, "\n");
408  for (i = 1; i <= Num_races; i++)
409  if (Nuked[i - 1])
410  warn(i, Stars[ship->storbits]->governor[i - 1], telegram_buf);
411  notify((ship->owner), ship->governor, telegram_buf);
412  }
413  kill_ship((ship->owner), &*ship);
414  }
415  putship(&*ship);
416  }
417 }
418 
419 void doabm(Ship *ship) {
420  int sh2;
421  int numdest;
422 
423  if (!ship->alive || !ship->owner) return;
424  if (!ship->on || !ship->retaliate || !ship->destruct) return;
425 
426  if (landed(*ship)) {
427  const auto &p = planets[ship->storbits][ship->pnumorbits];
428  /* check to see if missiles/mines are present */
429  sh2 = p->ships;
430  while (sh2 && ship->destruct) {
431  if (ships[sh2]->alive &&
432  ((ships[sh2]->type == ShipType::STYPE_MISSILE) ||
433  (ships[sh2]->type == ShipType::STYPE_MINE)) &&
434  (ships[sh2]->owner != ship->owner) &&
435  !(isset(races[ship->owner - 1]->allied, ships[sh2]->owner) &&
436  isset(races[ships[sh2]->owner - 1]->allied, ship->owner))) {
437  /* added last two tests to prevent mutually allied missiles
438  getting shot up. */
439  /* attack the missile/mine */
440  numdest = retal_strength(ship);
441  numdest = MIN(numdest, ship->destruct);
442  numdest = MIN(numdest, ship->retaliate);
443  ship->destruct -= numdest;
444  (void)shoot_ship_to_ship(ship, ships[sh2], numdest, 0, 0, long_buf,
445  short_buf);
446  push_telegram((int)(ship->owner), (int)ship->governor, long_buf);
447  push_telegram((int)(ships[sh2]->owner), (int)ships[sh2]->governor,
448  long_buf);
449  post(short_buf, COMBAT);
450  }
451  sh2 = ships[sh2]->nextship;
452  }
453  }
454 }
455 
456 static void do_repair(Ship *ship) {
457  int drep;
458  int cost;
459  double maxrep;
460 
461  maxrep = REPAIR_RATE / (double)segments;
462  /* stations repair for free, and ships docked with them */
463  if (Shipdata[ship->type][ABIL_REPAIR])
464  cost = 0;
465  else if (ship->docked && ship->whatdest == ScopeLevel::LEVEL_SHIP &&
466  ships[ship->destshipno]->type == ShipType::STYPE_STATION)
467  cost = 0;
468  else if (ship->docked && ship->whatorbits == ScopeLevel::LEVEL_SHIP &&
469  ships[ship->destshipno]->type == ShipType::STYPE_STATION)
470  cost = 0;
471  else {
472  maxrep *= (double)(ship->popn) / (double)ship->max_crew;
473  cost = (int)(0.005 * maxrep * shipcost(*ship));
474  }
475  if (cost <= ship->resource) {
476  use_resource(ship, cost);
477  drep = (int)maxrep;
478  ship->damage = std::max(0, (int)(ship->damage) - drep);
479  } else {
480  /* use up all of the ships resources */
481  drep = (int)(maxrep * ((double)ship->resource / (int)cost));
482  use_resource(ship, ship->resource);
483  ship->damage = std::max(0, (int)(ship->damage) - drep);
484  }
485 }
486 
487 static void do_habitat(Ship *ship) {
488  int sh;
489  int add;
490  double fuse;
491 
492  /* In v5.0+ Habitats make resources out of fuel */
493  if (ship->on) {
494  fuse = ship->fuel * ((double)ship->popn / (double)ship->max_crew) *
495  (1.0 - .01 * (double)ship->damage);
496  add = (int)fuse / 20;
497  if (ship->resource + add > ship->max_resource)
498  add = ship->max_resource - ship->resource;
499  fuse = 20.0 * (double)add;
500  rcv_resource(ship, add);
501  use_fuel(ship, fuse);
502 
503  sh = ship->ships;
504  while (sh) {
505  if (ships[sh]->type == ShipType::OTYPE_WPLANT)
506  rcv_destruct(ship, do_weapon_plant(ships[sh]));
507  sh = ships[sh]->nextship;
508  }
509  }
510  add = round_rand((double)ship->popn * races[ship->owner - 1]->birthrate);
511  if (ship->popn + add > max_crew(*ship)) add = max_crew(*ship) - ship->popn;
512  rcv_popn(ship, add, races[ship->owner - 1]->mass);
513 }
514 
515 static void do_pod(Ship *ship) {
516  int i;
517 
518  if (ship->whatorbits == ScopeLevel::LEVEL_STAR) {
519  if (ship->special.pod.temperature >= POD_THRESHOLD) {
520  i = int_rand(0, (int)Stars[ship->storbits]->numplanets - 1);
521  sprintf(telegram_buf, "%s has warmed and exploded at %s\n",
522  ship_to_string(*ship).c_str(), prin_ship_orbits(ship));
523  if (infect_planet((int)ship->owner, (int)ship->storbits, i)) {
524  sprintf(buf, "\tmeta-colony established on %s.",
525  Stars[ship->storbits]->pnames[i]);
526  } else
527  sprintf(buf, "\tno spores have survived.");
528  strcat(telegram_buf, buf);
529  push_telegram((int)(ship->owner), (int)ship->governor, telegram_buf);
530  kill_ship((int)(ship->owner), ship);
531  } else
532  ship->special.pod.temperature += round_rand(
533  (double)Stars[ship->storbits]->temperature / (double)segments);
534  } else if (ship->whatorbits == ScopeLevel::LEVEL_PLAN) {
535  if (ship->special.pod.decay >= POD_DECAY) {
536  sprintf(telegram_buf, "%s has decayed at %s\n",
537  ship_to_string(*ship).c_str(), prin_ship_orbits(ship));
538  push_telegram((int)ship->owner, (int)ship->governor, telegram_buf);
539  kill_ship((int)ship->owner, ship);
540  } else {
541  ship->special.pod.decay += round_rand(1.0 / (double)segments);
542  }
543  }
544 }
545 
546 static int infect_planet(int who, int star, int p) {
547  if (success(SPORE_SUCCESS_RATE)) {
548  do_meta_infect(who, planets[star][p]);
549  return 1;
550  }
551  return 0;
552 }
553 
554 static void do_meta_infect(int who, Planet *p) {
555  int owner;
556  int x;
557  int y;
558 
559  auto smap = getsmap(*p);
560  PermuteSects(*p);
561  bzero((char *)Sectinfo, sizeof(Sectinfo));
562  x = int_rand(0, p->Maxx - 1);
563  y = int_rand(0, p->Maxy - 1);
564  owner = smap.get(x, y).owner;
565  if (!owner ||
566  (who != owner &&
567  (double)int_rand(1, 100) >
568  100.0 *
569  (1.0 - exp(-((double)(smap.get(x, y).troops *
570  races[owner - 1]->fighters / 50.0)))))) {
571  p->info[who - 1].explored = 1;
572  p->info[who - 1].numsectsowned += 1;
573  smap.get(x, y).troops = 0;
574  smap.get(x, y).popn = races[who - 1]->number_sexes;
575  smap.get(x, y).owner = who;
576  smap.get(x, y).condition = smap.get(x, y).type;
577 #ifdef POD_TERRAFORM
578  smap.get(x, y).condition = races[who - 1]->likesbest;
579 #endif
580  putsmap(smap, *p);
581  }
582 }
583 
584 static void do_canister(Ship *ship) {
585  if (ship->whatorbits == ScopeLevel::LEVEL_PLAN && !landed(*ship)) {
586  if (++ship->special.timer.count < DISSIPATE) {
587  if (Stinfo[ship->storbits][ship->pnumorbits].temp_add < -90)
588  Stinfo[ship->storbits][ship->pnumorbits].temp_add = -100;
589  else
590  Stinfo[ship->storbits][ship->pnumorbits].temp_add -= 10;
591  } else { /* timer expired; destroy canister */
592  int j = 0;
593  kill_ship((int)(ship->owner), ship);
594  sprintf(telegram_buf,
595  "Canister of dust previously covering %s has dissipated.\n",
596  prin_ship_orbits(ship));
597  for (j = 1; j <= Num_races; j++)
598  if (planets[ship->storbits][ship->pnumorbits]
599  ->info[j - 1]
600  .numsectsowned)
601  push_telegram(j, (int)Stars[ship->storbits]->governor[j - 1],
602  telegram_buf);
603  }
604  }
605 }
606 
607 static void do_greenhouse(Ship *ship) {
608  if (ship->whatorbits == ScopeLevel::LEVEL_PLAN && !landed(*ship)) {
609  if (++ship->special.timer.count < DISSIPATE) {
610  if (Stinfo[ship->storbits][ship->pnumorbits].temp_add > 90)
611  Stinfo[ship->storbits][ship->pnumorbits].temp_add = 100;
612  else
613  Stinfo[ship->storbits][ship->pnumorbits].temp_add += 10;
614  } else { /* timer expired; destroy canister */
615  int j = 0;
616 
617  kill_ship((int)(ship->owner), ship);
618  sprintf(telegram_buf, "Greenhouse gases at %s have dissipated.\n",
619  prin_ship_orbits(ship));
620  for (j = 1; j <= Num_races; j++)
621  if (planets[ship->storbits][ship->pnumorbits]
622  ->info[j - 1]
623  .numsectsowned)
624  push_telegram(j, (int)Stars[ship->storbits]->governor[j - 1],
625  telegram_buf);
626  }
627  }
628 }
629 
630 static void do_mirror(Ship *ship) {
631  switch (ship->special.aimed_at.level) {
632  case ScopeLevel::LEVEL_SHIP: /* ship aimed at is a legal ship now */
633  /* if in the same system */
634  if ((ship->whatorbits == ScopeLevel::LEVEL_STAR ||
635  ship->whatorbits == ScopeLevel::LEVEL_PLAN) &&
636  (ships[ship->special.aimed_at.shipno] != nullptr) &&
637  (ships[ship->special.aimed_at.shipno]->whatorbits ==
638  ScopeLevel::LEVEL_STAR ||
639  ships[ship->special.aimed_at.shipno]->whatorbits ==
640  ScopeLevel::LEVEL_PLAN) &&
641  ship->storbits == ships[ship->special.aimed_at.shipno]->storbits &&
642  ships[ship->special.aimed_at.shipno]->alive) {
643  Ship *s;
644  int i;
645  double range;
646  s = ships[ship->special.aimed_at.shipno];
647  range = sqrt(Distsq(ship->xpos, ship->ypos, s->xpos, s->ypos));
648  i = int_rand(0, round_rand((2. / ((double)(shipbody(*s)))) *
649  (double)(ship->special.aimed_at.intensity) /
650  (range / PLORBITSIZE + 1.0)));
651  sprintf(telegram_buf, "%s aimed at %s\n", ship_to_string(*ship).c_str(),
652  ship_to_string(*s).c_str());
653  s->damage += i;
654  if (i) {
655  sprintf(buf, "%d%% damage done.\n", i);
656  strcat(telegram_buf, buf);
657  }
658  if (s->damage >= 100) {
659  sprintf(buf, "%s DESTROYED!!!\n", ship_to_string(*s).c_str());
660  strcat(telegram_buf, buf);
661  kill_ship((int)(ship->owner), s);
662  }
663  push_telegram((int)s->owner, (int)s->governor, telegram_buf);
664  push_telegram((int)ship->owner, (int)ship->governor, telegram_buf);
665  }
666  break;
667  case ScopeLevel::LEVEL_PLAN: {
668  int i;
669  double range;
670  range = sqrt(Distsq(ship->xpos, ship->ypos,
671  Stars[ship->storbits]->xpos +
672  planets[ship->storbits][ship->pnumorbits]->xpos,
673  Stars[ship->storbits]->ypos +
674  planets[ship->storbits][ship->pnumorbits]->ypos));
675  if (range > PLORBITSIZE)
676  i = PLORBITSIZE * ship->special.aimed_at.intensity / range;
677  else
678  i = ship->special.aimed_at.intensity;
679 
680  i = round_rand(.01 * (100.0 - (double)(ship->damage)) * (double)i);
681  Stinfo[ship->storbits][ship->special.aimed_at.pnum].temp_add += i;
682  } break;
683  case ScopeLevel::LEVEL_STAR: {
684  /* have to be in the same system as the star; otherwise
685  it's not too fair.. */
686  if (ship->special.aimed_at.snum > 0 &&
687  ship->special.aimed_at.snum < Sdata.numstars &&
688  ship->whatorbits > ScopeLevel::LEVEL_UNIV &&
689  ship->special.aimed_at.snum == ship->storbits)
690  Stars[ship->special.aimed_at.snum]->stability += random() & 01;
691  } break;
692  case ScopeLevel::LEVEL_UNIV:
693  break;
694  }
695 }
696 
697 static void do_god(Ship *ship) {
698  /* gods have infinite power.... heh heh heh */
699  if (races[ship->owner - 1]->God) {
700  ship->fuel = max_fuel(*ship);
701  ship->destruct = max_destruct(*ship);
702  ship->resource = max_resource(*ship);
703  }
704 }
705 
706 static void do_ap(Ship *ship) {
707  racetype *Race;
708 
709  /* if landed on planet, change conditions to be like race */
710  if (landed(*ship) && ship->on) {
711  int j;
712  int d;
713  // TODO(jeffbailey): Not obvious here how the modified planet is saved to
714  // disk
715  auto p = planets[ship->storbits][ship->pnumorbits];
716  Race = races[ship->owner - 1];
717  if (ship->fuel >= 3.0) {
718  use_fuel(ship, 3.0);
719  for (j = RTEMP + 1; j <= OTHER; j++) {
720  d = round_rand(ap_planet_factor(p) * crew_factor(ship) *
721  (double)(Race->conditions[j] - p->conditions[j]));
722  if (d) p->conditions[j] += d;
723  }
724  } else if (!ship->notified) {
725  ship->notified = 1;
726  ship->on = 0;
727  msg_OOF(ship);
728  }
729  }
730 }
731 
732 static double crew_factor(Ship *ship) {
733  int maxcrew;
734 
735  if (!(maxcrew = Shipdata[ship->type][ABIL_MAXCREW])) return 0.0;
736  return ((double)ship->popn / (double)maxcrew);
737 }
738 
739 static double ap_planet_factor(Planet *p) {
740  double x;
741 
742  x = (double)p->Maxx * (double)p->Maxy;
743  return (AP_FACTOR / (AP_FACTOR + x));
744 }
745 
746 static void do_oap(Ship *ship) {
747  /* "indimidate" the planet below, for enslavement purposes. */
748  if (ship->whatorbits == ScopeLevel::LEVEL_PLAN)
749  Stinfo[ship->storbits][ship->pnumorbits].intimidated = 1;
750 }
751 
752 int do_weapon_plant(Ship *ship) {
753  int maxrate;
754  int rate;
755  maxrate = (int)(races[ship->owner - 1]->tech / 2.0);
756 
757  rate = round_rand(MIN((double)ship->resource / (double)RES_COST_WPLANT,
758  ship->fuel / FUEL_COST_WPLANT) *
759  (1. - .01 * (double)ship->damage) * (double)ship->popn /
760  (double)ship->max_crew);
761  rate = std::min(rate, maxrate);
762  use_resource(ship, (rate * RES_COST_WPLANT));
763  use_fuel(ship, ((double)rate * FUEL_COST_WPLANT));
764  return rate;
765 }
void msg_OOF(Ship *)
Definition: moveship.cc:355
#define MASS_FUEL
Definition: tweakables.h:98
void use_fuel(Ship *s, double amt)
Definition: load.cc:876
#define POD_DECAY
Definition: tweakables.h:314
#define Distsq(x1, y1, x2, y2)
Definition: tweakables.h:218
void doship(Ship *, int)
Definition: doship.cc:50
void post(const char *origmsg, int type)
Definition: tele.cc:63
#define RES_COST_WPLANT
Definition: tweakables.h:175
static double ap_planet_factor(Planet *)
Definition: doship.cc:739
static void do_god(Ship *)
Definition: doship.cc:697
void doown(Ship *)
Definition: doship.cc:226
void domissile(Ship *)
Definition: doship.cc:237
int retal_strength(Ship *s)
Definition: fire.cc:731
void rcv_resource(Ship *s, int amt)
Definition: load.cc:896
static void do_ap(Ship *)
Definition: doship.cc:706
#define MASS_DESTRUCT
Definition: tweakables.h:100
#define POD_THRESHOLD
Definition: tweakables.h:313
void PermuteSects(const Planet &planet)
Definition: perm.cc:16
static void do_meta_infect(int, Planet *)
Definition: doship.cc:554
int do_weapon_plant(Ship *)
Definition: doship.cc:752
static void do_canister(Ship *)
Definition: doship.cc:584
#define REPAIR_RATE
Definition: tweakables.h:138
int shoot_ship_to_ship(Ship *, Ship *, int, int, int, char *, char *)
Definition: shootblast.cc:43
#define isset(a, i)
Definition: vars.h:312
#define setbit(a, i)
Definition: vars.h:310
int shoot_ship_to_planet(Ship *, Planet *, int, int, int, SectorMap &, int, int, char *, char *)
Definition: shootblast.cc:188
#define DISSIPATE
Definition: tweakables.h:317
static void do_pod(Ship *)
Definition: doship.cc:515
#define MIN(x, y)
Definition: tweakables.h:213
static void do_repair(Ship *)
Definition: doship.cc:456
char * prin_ship_orbits(Ship *s)
Definition: max.cc:63
static int infect_planet(int, int, int)
Definition: doship.cc:546
void putsmap(SectorMap &map, Planet &p)
Definition: files_shl.cc:1108
#define SPORE_SUCCESS_RATE
Definition: tweakables.h:292
static void do_habitat(Ship *)
Definition: doship.cc:487
#define OTHER
Definition: tweakables.h:38
#define AP_FACTOR
Definition: tweakables.h:315
#define PLORBITSIZE
Definition: tweakables.h:82
void use_resource(Ship *s, int amt)
Definition: load.cc:886
void moveship(Ship *, int, int, int)
Definition: moveship.cc:41
static void do_mirror(Ship *)
Definition: doship.cc:630
void domass(Ship *)
Definition: doship.cc:204
void putship(Ship *s)
Definition: files_shl.cc:1317
SectorMap getsmap(const Planet &p)
Definition: files_shl.cc:522
#define FUEL_COST_WPLANT
Definition: tweakables.h:176
#define RTEMP
Definition: tweakables.h:29
void rcv_destruct(Ship *s, int amt)
Definition: load.cc:901
#define COMBAT
Definition: files.h:19
static void do_oap(Ship *)
Definition: doship.cc:746
#define STRIKE_DISTANCE_FACTOR
Definition: tweakables.h:305
static double crew_factor(Ship *)
Definition: doship.cc:732
void domine(int, int)
Definition: doship.cc:316
static void do_greenhouse(Ship *)
Definition: doship.cc:607
void doabm(Ship *)
Definition: doship.cc:419
#define MASS_RESOURCE
Definition: tweakables.h:99