Galactic Bloodshed
doturncmd.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 /* doturn -- does one turn. */
6 
7 #include "gb/doturncmd.h"
8 
9 #include <cctype>
10 #include <cmath>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 
15 #include "gb/GB_server.h"
16 #include "gb/buffers.h"
17 #include "gb/build.h"
18 #include "gb/doplanet.h"
19 #include "gb/doship.h"
20 #include "gb/doturn.h"
21 #include "gb/files.h"
22 #include "gb/files_shl.h"
23 #include "gb/moveplanet.h"
24 #include "gb/power.h"
25 #include "gb/races.h"
26 #include "gb/ships.h"
27 #include "gb/shlmisc.h"
28 #include "gb/tele.h"
29 #include "gb/tweakables.h"
30 #include "gb/utils/rand.h"
31 #include "gb/vars.h"
32 
33 #ifdef MARKET
34 static constexpr void maintain(Race &r, Race::gov &governor,
35  const money_t amount) noexcept {
36  if (governor.money >= amount)
37  governor.money -= amount;
38  else {
39  r.morale -= (amount - governor.money) / 10;
40  governor.money = 0;
41  }
42 }
43 #endif
44 
45 static int APadd(int, int, Race *);
46 static int attack_planet(Ship *);
47 static void fix_stability(startype *);
48 static int governed(Race *);
49 static void make_discoveries(Race *);
50 static void output_ground_attacks();
51 static int planet_points(const Planet &);
52 
53 void do_turn(int update) {
54  commodtype *c;
55  unsigned long dummy[2];
56  double dist;
57  struct victstruct {
58  int numsects;
59  int shipcost;
60  int shiptech;
61  int morale;
62  int res;
63  int des;
64  int fuel;
65  money_t money;
66  } * victory;
67 
68  /* make all 0 for first iteration of doplanet */
69  if (update) {
70  bzero((char *)starpopns, sizeof(starpopns));
71  bzero((char *)starnumships, sizeof(starnumships));
72  bzero((char *)Sdatanumships, sizeof(Sdatanumships));
73  bzero((char *)Stinfo, sizeof(Stinfo));
74  bzero((char *)StarsInhab, sizeof(StarsInhab));
75  bzero((char *)Power, sizeof(Power));
76  bzero((char *)inhabited, sizeof(inhabited));
77  }
78 
79  Num_ships = Numships();
80 
81  for (shipnum_t i = 1; i <= Num_ships; i++) domine(i, 0);
82 
83  ships = (Ship **)malloc(sizeof(Ship *) * (Num_ships + 1));
84  for (shipnum_t i = 1; i <= Num_ships; i++) (void)getship(&ships[i], i);
85 
86  /* get all stars and planets */
87  getsdata(&Sdata);
88  Planet_count = 0;
89  for (starnum_t star = 0; star < Sdata.numstars; star++) {
90  getstar(&Stars[star], star);
91  if (update) fix_stability(Stars[star]); /* nova */
92 
93  for (planetnum_t i = 0; i < Stars[star]->numplanets; i++) {
94  planets[star][i] = new Planet(getplanet(star, i));
95  if (planets[star][i]->type != PlanetType::ASTEROID) Planet_count++;
96  if (update) moveplanet(star, planets[star][i], i);
97  if (Stars[star]->pnames[i] == nullptr)
98  sprintf(Stars[star]->pnames[i], "NULL-%d", i);
99  }
100  if (Stars[star]->name[0] == '\0')
101  sprintf(Stars[star]->name, "NULL-%d", star);
102  }
103 
104  VN_brain.Most_mad = 0; /* not mad at anyone for starts */
105 
106  for (player_t i = 1; i <= Num_races; i++) {
107  /* increase tech; change to something else */
108  if (update) {
109  /* Reset controlled planet count */
110  races[i - 1]->controlled_planets = 0;
111  races[i - 1]->planet_points = 0;
112  for (auto &governor : races[i - 1]->governor)
113  if (governor.active) {
114 #ifdef MARKET
115  governor.maintain = 0;
116  governor.cost_market = 0;
117  governor.profit_market = 0;
118 #endif
119  governor.cost_tech = 0;
120  governor.income = 0;
121  }
122  /* add VN program */
123  VN_brain.Total_mad += Sdata.VN_hitlist[i - 1];
124  /* find out who they're most mad at */
125  if (VN_brain.Most_mad > 0 &&
126  Sdata.VN_hitlist[VN_brain.Most_mad - 1] <= Sdata.VN_hitlist[i - 1])
127  VN_brain.Most_mad = i;
128  }
129 #ifdef VOTING
130  /* Reset their vote for Update go. */
131  races[i - 1]->votes &= ~VOTE_UPDATE_GO;
132 #endif
133  }
135 #ifdef MARKET
136  if (update) {
137  /* reset market */
138  Num_commods = Numcommods();
140  for (commodnum_t i = Num_commods; i >= 1; i--) {
141  getcommod(&c, i);
142  if (!c->deliver) {
143  c->deliver = 1;
144  putcommod(c, i);
145  free(c);
146  continue;
147  }
148  if (c->owner && c->bidder &&
149  (races[c->bidder - 1]->governor[c->bidder_gov].money >= c->bid)) {
150  races[c->bidder - 1]->governor[c->bidder_gov].money -= c->bid;
151  races[c->owner - 1]->governor[c->governor].money += c->bid;
152  int cost = shipping_cost((int)c->star_to, (int)c->star_from, &dist,
153  (int)c->bid);
154  races[c->bidder - 1]->governor[c->bidder_gov].cost_market +=
155  c->bid + cost;
156  races[c->owner - 1]->governor[c->governor].profit_market += c->bid;
157  maintain(*races[c->bidder - 1],
158  races[c->bidder - 1]->governor[c->bidder_gov], cost);
159  switch (c->type) {
160  case RESOURCE:
161  planets[c->star_to][c->planet_to]->info[c->bidder - 1].resource +=
162  c->amount;
163  break;
164  case FUEL:
165  planets[c->star_to][c->planet_to]->info[c->bidder - 1].fuel +=
166  c->amount;
167  break;
168  case DESTRUCT:
169  planets[c->star_to][c->planet_to]->info[c->bidder - 1].destruct +=
170  c->amount;
171  break;
172  case CRYSTAL:
173  planets[c->star_to][c->planet_to]->info[c->bidder - 1].crystals +=
174  c->amount;
175  break;
176  }
177  sprintf(buf,
178  "Lot %lu purchased from %s [%d] at a cost of %ld.\n %ld "
179  "%s arrived at /%s/%s\n",
180  i, races[c->owner - 1]->name, c->owner, c->bid, c->amount,
181  Commod[c->type], Stars[c->star_to]->name,
182  Stars[c->star_to]->pnames[c->planet_to]);
183  push_telegram((int)c->bidder, (int)c->bidder_gov, buf);
184  sprintf(buf, "Lot %lu (%lu %s) sold to %s [%d] at a cost of %ld.\n", i,
185  c->amount, Commod[c->type], races[c->bidder - 1]->name,
186  c->bidder, c->bid);
187  push_telegram((int)c->owner, (int)c->governor, buf);
188  c->owner = c->governor = 0;
189  c->bidder = c->bidder_gov = 0;
190  } else {
191  c->bidder = c->bidder_gov = 0;
192  c->bid = 0;
193  }
194  if (!c->owner) makecommoddead(i);
195  putcommod(c, i);
196  free(c);
197  }
198  }
199 #endif
200 
201  /* check ship masses - ownership */
202  for (shipnum_t i = 1; i <= Num_ships; i++)
203  if (ships[i]->alive) {
204  domass(ships[i]);
205  doown(ships[i]);
206  }
207 
208  /* do all ships one turn - do slower ships first */
209  for (int j = 0; j <= 9; j++)
210  for (shipnum_t i = 1; i <= Num_ships; i++) {
211  if (ships[i]->alive && ships[i]->speed == j) {
212  doship(ships[i], update);
213  if ((ships[i]->type == ShipType::STYPE_MISSILE) &&
214  !attack_planet(ships[i]))
215  domissile(ships[i]);
216  }
217  }
218 
219 #ifdef MARKET
220  /* do maintenance costs */
221  if (update)
222  for (shipnum_t i = 1; i <= Num_ships; i++)
223  if (ships[i]->alive && Shipdata[ships[i]->type][ABIL_MAINTAIN]) {
224  if (ships[i]->popn)
225  races[ships[i]->owner - 1]->governor[ships[i]->governor].maintain +=
226  ships[i]->build_cost;
227  if (ships[i]->troops)
228  races[ships[i]->owner - 1]->governor[ships[i]->governor].maintain +=
229  UPDATE_TROOP_COST * ships[i]->troops;
230  }
231 #endif
232 
233  /* prepare dead ships for recycling */
235  for (shipnum_t i = 1; i <= Num_ships; i++)
236  if (!ships[i]->alive) makeshipdead(i);
237 
238  /* erase next ship pointers - reset in insert_sh_... */
239  for (shipnum_t i = 1; i <= Num_ships; i++) {
240  ships[i]->nextship = 0;
241  ships[i]->ships = 0;
242  }
243  /* clear ship list for insertion */
244  Sdata.ships = 0;
245  for (starnum_t star = 0; star < Sdata.numstars; star++) {
246  Stars[star]->ships = 0;
247  for (planetnum_t i = 0; i < Stars[star]->numplanets; i++)
248  planets[star][i]->ships = 0;
249  }
250 
251  /* insert ship into the list of wherever it might be */
252  for (shipnum_t i = Num_ships; i >= 1; i--) {
253  if (ships[i]->alive) {
254  switch (ships[i]->whatorbits) {
255  case ScopeLevel::LEVEL_UNIV:
256  insert_sh_univ(&Sdata, ships[i]);
257  break;
258  case ScopeLevel::LEVEL_STAR:
259  insert_sh_star(Stars[ships[i]->storbits], ships[i]);
260  break;
261  case ScopeLevel::LEVEL_PLAN:
262  insert_sh_plan(planets[ships[i]->storbits][ships[i]->pnumorbits],
263  ships[i]);
264  break;
265  case ScopeLevel::LEVEL_SHIP:
266  insert_sh_ship(ships[i], ships[ships[i]->destshipno]);
267  break;
268  }
269  }
270  }
271 
272  /* put ABMs and surviving missiles here because ABMs need to have the missile
273  in the shiplist of the target planet Maarten */
274  for (shipnum_t i = 1; i <= Num_ships; i++) /* ABMs defend planet */
275  if ((ships[i]->type == ShipType::OTYPE_ABM) && ships[i]->alive)
276  doabm(ships[i]);
277 
278  for (shipnum_t i = 1; i <= Num_ships; i++)
279  if ((ships[i]->type == ShipType::STYPE_MISSILE) && ships[i]->alive &&
280  attack_planet(ships[i]))
281  domissile(ships[i]);
282 
283  for (shipnum_t i = Num_ships; i >= 1; i--) putship(ships[i]);
284 
285  for (starnum_t star = 0; star < Sdata.numstars; star++) {
286  for (planetnum_t i = 0; i < Stars[star]->numplanets; i++) {
287  /* store occupation for VPs */
288  for (player_t j = 1; j <= Num_races; j++) {
289  if (planets[star][i]->info[j - 1].numsectsowned) {
290  setbit(inhabited[star], j);
291  setbit(Stars[star]->inhabited, j);
292  }
293  if (planets[star][i]->type != PlanetType::ASTEROID &&
294  (planets[star][i]->info[j - 1].numsectsowned >
295  planets[star][i]->Maxx * planets[star][i]->Maxy / 2))
296  races[j - 1]->controlled_planets++;
297 
298  if (planets[star][i]->info[j - 1].numsectsowned)
299  races[j - 1]->planet_points += planet_points(*planets[star][i]);
300  }
301  if (update) {
302  if (doplanet(star, planets[star][i], i)) {
303  /* save smap gotten & altered by doplanet
304  only if the planet is expl*/
305  // TODO(jeffbailey): Added this in doplanet, but need to audit other
306  // getsmaps to make sure they have matching putsmaps
307  // putsmap(smap, *planets[star][i]);
308  }
309  }
310  putplanet(*planets[star][i], Stars[star], i);
311  }
312  /* do AP's for ea. player */
313  if (update)
314  for (player_t i = 1; i <= Num_races; i++) {
315  if (starpopns[star][i - 1])
316  setbit(Stars[star]->inhabited, i);
317  else
318  clrbit(Stars[star]->inhabited, i);
319 
320  if (isset(Stars[star]->inhabited, i)) {
321  int APs;
322 
323  APs = Stars[star]->AP[i - 1] + APadd((int)starnumships[star][i - 1],
324  (int)starpopns[star][i - 1],
325  races[i - 1]);
326  if (APs < LIMIT_APs)
327  Stars[star]->AP[i - 1] = APs;
328  else
329  Stars[star]->AP[i - 1] = LIMIT_APs;
330  }
331  /* compute victory points for the block */
332  if (inhabited[star][0] + inhabited[star][1]) {
333  dummy[0] = (Blocks[i - 1].invite[0] & Blocks[i - 1].pledge[0]);
334  dummy[1] = (Blocks[i - 1].invite[1] & Blocks[i - 1].pledge[1]);
335  Blocks[i - 1].systems_owned +=
336  ((inhabited[star][0] | dummy[0]) == dummy[0]) &&
337  ((inhabited[star][1] | dummy[1]) == dummy[1]);
338  }
339  }
340  putstar(Stars[star], star);
341  }
342 
343  /* add APs to sdata for ea. player */
344  if (update)
345  for (player_t i = 1; i <= Num_races; i++) {
346  Blocks[i - 1].systems_owned = 0; /*recount systems owned*/
347  if (governed(races[i - 1])) {
348  int APs;
349 
350  APs = Sdata.AP[i - 1] + races[i - 1]->planet_points;
351  if (APs < LIMIT_APs)
352  Sdata.AP[i - 1] = APs;
353  else
354  Sdata.AP[i - 1] = LIMIT_APs;
355  }
356  }
357 
358  putsdata(&Sdata);
359 
360  /* here is where we do victory calculations. */
361  if (update) {
362  victory =
363  (struct victstruct *)malloc(Num_races * sizeof(struct victstruct));
364  for (player_t i = 1; i <= Num_races; i++) {
365  victory[i - 1].numsects = 0;
366  victory[i - 1].shipcost = 0;
367  victory[i - 1].shiptech = 0;
368  victory[i - 1].morale = races[i - 1]->morale;
369  victory[i - 1].res = 0;
370  victory[i - 1].des = 0;
371  victory[i - 1].fuel = 0;
372  victory[i - 1].money = races[i - 1]->governor[0].money;
373  for (auto &governor : races[i - 1]->governor)
374  if (governor.active) victory[i - 1].money += governor.money;
375  }
376 
377  for (starnum_t star = 0; star < Sdata.numstars; star++) {
378  /* do planets in the star next */
379  for (planetnum_t i = 0; i < Stars[star]->numplanets; i++) {
380  for (player_t j = 0; j < Num_races; j++) {
381  if (!planets[star][i]->info[j].explored) continue;
382  victory[j].numsects += (int)planets[star][i]->info[j].numsectsowned;
383  victory[j].res += (int)planets[star][i]->info[j].resource;
384  victory[j].des += (int)planets[star][i]->info[j].destruct;
385  victory[j].fuel += (int)planets[star][i]->info[j].fuel;
386  }
387  } /* end of planet searchings */
388  } /* end of star searchings */
389 
390  for (shipnum_t i = 1; i <= Num_ships; i++) {
391  if (!ships[i]->alive) continue;
392  victory[ships[i]->owner - 1].shipcost += ships[i]->build_cost;
393  victory[ships[i]->owner - 1].shiptech += ships[i]->tech;
394  victory[ships[i]->owner - 1].res += ships[i]->resource;
395  victory[ships[i]->owner - 1].des += ships[i]->destruct;
396  victory[ships[i]->owner - 1].fuel += ships[i]->fuel;
397  }
398  /* now that we have the info.. calculate the raw score */
399 
400  for (player_t i = 0; i < Num_races; i++) {
401  races[i]->victory_score =
402  (VICT_SECT * (int)victory[i].numsects) +
403  (VICT_SHIP * ((int)victory[i].shipcost +
404  (VICT_TECH * (int)victory[i].shiptech))) +
405  (VICT_RES * ((int)victory[i].res + (int)victory[i].des)) +
406  (VICT_FUEL * (int)victory[i].fuel) +
407  (VICT_MONEY * (int)victory[i].money);
408  races[i]->victory_score /= VICT_DIVISOR;
409  races[i]->victory_score = (int)(morale_factor((double)victory[i].morale) *
410  races[i]->victory_score);
411  }
412  free(victory);
413  } /* end of if (update) */
414 
415  for (shipnum_t i = 1; i <= Num_ships; i++) {
416  putship(ships[i]);
417  free(ships[i]);
418  }
419 
420  if (update) {
421  for (player_t i = 1; i <= Num_races; i++) {
422  /* collective intelligence */
423  if (races[i - 1]->collective_iq) {
424  double x = ((2. / 3.14159265) *
425  atan((double)Power[i - 1].popn / MESO_POP_SCALE));
426  races[i - 1]->IQ = races[i - 1]->IQ_limit * x * x;
427  }
428  races[i - 1]->tech += (double)(races[i - 1]->IQ) / 100.0;
429  races[i - 1]->morale += Power[i - 1].planets_owned;
430  make_discoveries(races[i - 1]);
431  races[i - 1]->turn += 1;
432  if (races[i - 1]->controlled_planets >=
433  Planet_count * VICTORY_PERCENT / 100)
434  races[i - 1]->victory_turns++;
435  else
436  races[i - 1]->victory_turns = 0;
437 
438  if (races[i - 1]->controlled_planets >=
439  Planet_count * VICTORY_PERCENT / 200)
440  for (player_t j = 1; j <= Num_races; j++)
441  races[j - 1]->translate[i - 1] = 100;
442 
443  Blocks[i - 1].VPs = 10 * Blocks[i - 1].systems_owned;
444 #ifdef MARKET
445  for (auto &governor : races[i - 1]->governor)
446  if (governor.active)
447  maintain(*races[i - 1], governor, governor.maintain);
448 #endif
449  }
450  for (player_t i = 1; i <= Num_races; i++) putrace(races[i - 1]);
451  }
452 
453  free(ships);
454 
455  if (update) {
456  compute_power_blocks();
457  for (player_t i = 1; i <= Num_races; i++) {
458  Power[i - 1].money = 0;
459  for (auto &governor : races[i - 1]->governor)
460  if (governor.active) Power[i - 1].money += governor.money;
461  }
462  Putpower(Power);
463  Putblock(Blocks);
464  }
465 
466  for (player_t j = 1; j <= Num_races; j++) {
467  if (update)
468  notify_race(j, "Finished with update.\n");
469  else
470  notify_race(j, "Finished with movement segment.\n");
471  }
472 }
473 
474 /* routine for number of AP's to add to each player in ea. system,scaled
475  by amount of crew in their palace */
476 
477 static int APadd(int sh, int popn, Race *race) {
478  int APs;
479 
480  APs = round_rand((double)sh / 10.0 + 5. * log10(1.0 + (double)popn));
481 
482  if (governed(race)) return APs;
483  /* dont have an active gov center */
484  return round_rand((double)APs / 20.);
485 }
486 
487 int governed(Race *race) {
488  return (race->Gov_ship && race->Gov_ship <= Num_ships &&
489  ships[race->Gov_ship] != nullptr && ships[race->Gov_ship]->alive &&
490  ships[race->Gov_ship]->docked &&
491  (ships[race->Gov_ship]->whatdest == ScopeLevel::LEVEL_PLAN ||
492  (ships[race->Gov_ship]->whatorbits == ScopeLevel::LEVEL_SHIP &&
493  ships[ships[race->Gov_ship]->destshipno]->type ==
494  ShipType::STYPE_HABITAT &&
495  (ships[ships[race->Gov_ship]->destshipno]->whatorbits ==
496  ScopeLevel::LEVEL_PLAN ||
497  ships[ships[race->Gov_ship]->destshipno]->whatorbits ==
498  ScopeLevel::LEVEL_STAR))));
499 }
500 
501 /* fix stability for stars */
502 void fix_stability(startype *s) {
503  int a;
504  int i;
505 
506  if (s->nova_stage > 0) {
507  if (s->nova_stage > 14) {
508  s->stability = 20;
509  s->nova_stage = 0;
510  sprintf(telegram_buf, "Notice\n");
511  sprintf(buf, "\n Scientists report that star %s\n", s->name);
512  strcat(telegram_buf, buf);
513  sprintf(buf, "is no longer undergoing nova.\n");
514  strcat(telegram_buf, buf);
515  for (i = 1; i <= Num_races; i++) push_telegram_race(i, telegram_buf);
516 
517  /* telegram everyone when nova over? */
518  } else
519  s->nova_stage++;
520  } else if (s->stability > 20) {
521  a = int_rand(-1, 3);
522  /* nova just starting; notify everyone */
523  if ((s->stability + a) > 100) {
524  s->stability = 100;
525  s->nova_stage = 1;
526  sprintf(telegram_buf, "***** BULLETIN! ******\n");
527  sprintf(buf, "\n Scientists report that star %s\n", s->name);
528  strcat(telegram_buf, buf);
529  sprintf(buf, "is undergoing nova.\n");
530  strcat(telegram_buf, buf);
531  for (i = 1; i <= Num_races; i++) push_telegram_race(i, telegram_buf);
532  } else
533  s->stability += a;
534  } else {
535  a = int_rand(-1, 1);
536  if (((int)s->stability + a) < 0)
537  s->stability = 0;
538  else
539  s->stability += a;
540  }
541 }
542 
544 #ifndef VICTORY
545 #else
546 
547  int i, j;
548  int game_over = 0;
549  int win_category[64];
550 
551  const int BIG_WINNER = 1;
552  const int LITTLE_WINNER = 2;
553 
554  for (i = 1; i <= Num_races; i++) {
555  win_category[i - 1] = 0;
556  if (races[i - 1]->controlled_planets >=
557  Planet_count * VICTORY_PERCENT / 100) {
558  win_category[i - 1] = LITTLE_WINNER;
559  }
560  if (races[i - 1]->victory_turns >= VICTORY_UPDATES) {
561  game_over++;
562  win_category[i - 1] = BIG_WINNER;
563  }
564  }
565  if (game_over) {
566  for (i = 1; i <= Num_races; i++) {
567  sprintf(telegram_buf, "*** Attention ***");
568  push_telegram_race(i, telegram_buf);
569  sprintf(telegram_buf, "This game of Galactic Bloodshed is now *over*");
570  push_telegram_race(i, telegram_buf);
571  sprintf(telegram_buf, "The big winner%s",
572  (game_over == 1) ? " is" : "s are");
573  push_telegram_race(i, telegram_buf);
574  for (j = 1; j <= Num_races; j++)
575  if (win_category[j - 1] == BIG_WINNER) {
576  sprintf(telegram_buf, "*** [%2d] %-30.30s ***", j,
577  races[j - 1]->name);
578  push_telegram_race(i, telegram_buf);
579  }
580  sprintf(telegram_buf, "Lesser winners:");
581  push_telegram_race(i, telegram_buf);
582  for (j = 1; j <= Num_races; j++)
583  if (win_category[j - 1] == LITTLE_WINNER) {
584  sprintf(telegram_buf, "+++ [%2d] %-30.30s +++", j,
585  races[j - 1]->name);
586  push_telegram_race(i, telegram_buf);
587  }
588  }
589  }
590 #endif
591 }
592 
593 static void make_discoveries(Race *r) {
594  /* would be nicer to do this with a loop of course - but it's late */
595  if (!Hyper_drive(r) && r->tech >= TECH_HYPER_DRIVE) {
596  push_telegram_race(r->Playernum,
597  "You have discovered HYPERDRIVE technology.\n");
598  r->discoveries[D_HYPER_DRIVE] = 1;
599  }
600  if (!Laser(r) && r->tech >= TECH_LASER) {
601  push_telegram_race(r->Playernum, "You have discovered LASER technology.\n");
602  r->discoveries[D_LASER] = 1;
603  }
604  if (!Cew(r) && r->tech >= TECH_CEW) {
605  push_telegram_race(r->Playernum, "You have discovered CEW technology.\n");
606  r->discoveries[D_CEW] = 1;
607  }
608  if (!Vn(r) && r->tech >= TECH_VN) {
609  push_telegram_race(r->Playernum, "You have discovered VN technology.\n");
610  r->discoveries[D_VN] = 1;
611  }
612  if (!Tractor_beam(r) && r->tech >= TECH_TRACTOR_BEAM) {
613  push_telegram_race(r->Playernum,
614  "You have discovered TRACTOR BEAM technology.\n");
615  r->discoveries[D_TRACTOR_BEAM] = 1;
616  }
617  if (!Transporter(r) && r->tech >= TECH_TRANSPORTER) {
618  push_telegram_race(r->Playernum,
619  "You have discovered TRANSPORTER technology.\n");
620  r->discoveries[D_TRANSPORTER] = 1;
621  }
622  if (!Avpm(r) && r->tech >= TECH_AVPM) {
623  push_telegram_race(r->Playernum, "You have discovered AVPM technology.\n");
624  r->discoveries[D_AVPM] = 1;
625  }
626  if (!Cloak(r) && r->tech >= TECH_CLOAK) {
627  push_telegram_race(r->Playernum, "You have discovered CLOAK technology.\n");
628  r->discoveries[D_CLOAK] = 1;
629  }
630  if (!Wormhole(r) && r->tech >= TECH_WORMHOLE) {
631  push_telegram_race(r->Playernum,
632  "You have discovered WORMHOLE technology.\n");
633  r->discoveries[D_WORMHOLE] = 1;
634  }
635  if (!Crystal(r) && r->tech >= TECH_CRYSTAL) {
636  push_telegram_race(r->Playernum,
637  "You have discovered CRYSTAL technology.\n");
638  r->discoveries[D_CRYSTAL] = 1;
639  }
640 }
641 
642 static int attack_planet(Ship *ship) {
643  if (ship->whatdest == ScopeLevel::LEVEL_PLAN) return 1;
644 
645  return 0;
646 }
647 
648 static void output_ground_attacks() {
649  int star;
650  int i;
651  int j;
652 
653  for (star = 0; star < Sdata.numstars; star++)
654  for (i = 1; i <= Num_races; i++)
655  for (j = 1; j <= Num_races; j++)
656  if (ground_assaults[i - 1][j - 1][star]) {
657  sprintf(buf, "%s: %s [%d] assaults %s [%d] %d times.\n",
658  Stars[star]->name, races[i - 1]->name, i, races[j - 1]->name,
659  j, ground_assaults[i - 1][j - 1][star]);
660  post(buf, COMBAT);
661  ground_assaults[i - 1][j - 1][star] = 0;
662  }
663 }
664 
665 static int planet_points(const Planet &p) {
666  switch (p.type) {
667  case PlanetType::ASTEROID:
668  return ASTEROID_POINTS;
669  case PlanetType::EARTH:
670  return EARTH_POINTS;
671  case PlanetType::MARS:
672  return MARS_POINTS;
673  case PlanetType::ICEBALL:
674  return ICEBALL_POINTS;
675  case PlanetType::GASGIANT:
676  return GASGIANT_POINTS;
677  case PlanetType::WATER:
678  return WATER_POINTS;
679  case PlanetType::FOREST:
680  return FOREST_POINTS;
681  case PlanetType::DESERT:
682  return DESERT_POINTS;
683  }
684 }
#define Wormhole(r)
Definition: races.h:121
#define Vn(r)
Definition: races.h:116
#define FOREST_POINTS
Definition: tweakables.h:246
#define TECH_HYPER_DRIVE
Definition: races.h:124
void doship(Ship *, int)
Definition: doship.cc:50
void post(const char *origmsg, int type)
Definition: tele.cc:63
void doown(Ship *)
Definition: doship.cc:226
#define VICT_RES
Definition: tweakables.h:300
void domissile(Ship *)
Definition: doship.cc:237
#define TECH_AVPM
Definition: races.h:130
#define Cloak(r)
Definition: races.h:120
#define D_HYPER_DRIVE
Definition: races.h:102
#define RESOURCE
Definition: tweakables.h:268
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
void makecommoddead(int commodnum)
Definition: files_shl.cc:1601
static void output_ground_attacks()
Definition: doturncmd.cc:648
#define MESO_POP_SCALE
Definition: tweakables.h:169
#define MARS_POINTS
Definition: tweakables.h:242
#define VICT_FUEL
Definition: tweakables.h:301
#define D_LASER
Definition: races.h:103
#define D_WORMHOLE
Definition: races.h:110
#define EARTH_POINTS
Definition: tweakables.h:240
#define VICT_MONEY
Definition: tweakables.h:302
#define Crystal(r)
Definition: races.h:122
#define TECH_CLOAK
Definition: races.h:131
#define D_CLOAK
Definition: races.h:109
int Numcommods()
Definition: files_shl.cc:1533
#define clrbit(a, i)
Definition: vars.h:311
#define isset(a, i)
Definition: vars.h:312
#define TECH_LASER
Definition: races.h:125
#define setbit(a, i)
Definition: vars.h:310
#define VICT_TECH
Definition: tweakables.h:298
#define D_TRACTOR_BEAM
Definition: races.h:106
#define UPDATE_TROOP_COST
Definition: tweakables.h:179
#define D_TRANSPORTER
Definition: races.h:107
shipnum_t Numships()
Definition: files_shl.cc:1516
#define Cew(r)
Definition: races.h:115
#define VOTE_UPDATE_GO
Definition: races.h:99
static int governed(Race *)
Definition: doturncmd.cc:487
#define Tractor_beam(r)
Definition: races.h:117
static int planet_points(const Planet &)
Definition: doturncmd.cc:665
#define ICEBALL_POINTS
Definition: tweakables.h:243
void makeshipdead(int shipnum)
Definition: files_shl.cc:1577
void clr_shipfree()
Definition: files_shl.cc:1570
#define TECH_TRANSPORTER
Definition: races.h:129
#define WATER_POINTS
Definition: tweakables.h:245
#define GASGIANT_POINTS
Definition: tweakables.h:244
#define D_AVPM
Definition: races.h:108
static void make_discoveries(Race *)
Definition: doturncmd.cc:593
void do_turn(int update)
Definition: doturncmd.cc:53
void moveplanet(int, Planet *, int)
Definition: moveplanet.cc:16
void clr_commodfree()
Definition: files_shl.cc:1572
void putcommod(commodtype *c, int commodnum)
Definition: files_shl.cc:1504
#define MARKET
Definition: config.h:27
#define CRYSTAL
Definition: tweakables.h:271
#define Hyper_drive(r)
Definition: races.h:113
#define Transporter(r)
Definition: races.h:118
#define VICT_DIVISOR
Definition: tweakables.h:303
#define TECH_VN
Definition: races.h:127
#define TECH_TRACTOR_BEAM
Definition: races.h:128
void Putblock(struct block b[MAXPLAYERS])
Definition: files_shl.cc:1649
void putstar(startype *s, starnum_t snum)
Definition: files_shl.cc:813
int doplanet(const int, Planet *, const int)
Definition: doplanet.cc:48
#define LIMIT_APs
Definition: tweakables.h:226
void getsdata(struct stardata *S)
Definition: files_shl.cc:272
int shipping_cost(int to, int from, double *dist, int value)
Definition: build.cc:1767
void putplanet(const Planet &p, startype *star, const int pnum)
Definition: files_shl.cc:934
static constexpr void maintain(Race &r, Race::gov &governor, const money_t amount) noexcept
Definition: doturncmd.cc:34
#define D_CEW
Definition: races.h:104
static void fix_stability(startype *)
Definition: doturncmd.cc:502
void getstar(startype **s, int star)
Definition: files_shl.cc:281
#define Avpm(r)
Definition: races.h:119
void handle_victory()
Definition: doturncmd.cc:543
void domass(Ship *)
Definition: doship.cc:204
void putship(Ship *s)
Definition: files_shl.cc:1317
#define D_CRYSTAL
Definition: races.h:111
#define VICT_SHIP
Definition: tweakables.h:297
#define TECH_CRYSTAL
Definition: races.h:133
static int APadd(int, int, Race *)
Definition: doturncmd.cc:477
int getcommod(commodtype **c, commodnum_t commodnum)
Definition: files_shl.cc:730
#define TECH_CEW
Definition: races.h:126
#define VICTORY_PERCENT
Definition: tweakables.h:84
#define COMBAT
Definition: files.h:19
void putsdata(struct stardata *S)
Definition: files_shl.cc:804
#define Laser(r)
Definition: races.h:114
#define D_VN
Definition: races.h:105
#define VICT_SECT
Definition: tweakables.h:296
static int attack_planet(Ship *)
Definition: doturncmd.cc:642
#define TECH_WORMHOLE
Definition: races.h:132
#define FUEL
Definition: tweakables.h:270
#define DESERT_POINTS
Definition: tweakables.h:247
#define DESTRUCT
Definition: tweakables.h:269
void domine(int, int)
Definition: doship.cc:316
void Putpower(struct power p[MAXPLAYERS])
Definition: files_shl.cc:1625
#define VOTING
Definition: config.h:31
#define ASTEROID_POINTS
Definition: tweakables.h:241
void doabm(Ship *)
Definition: doship.cc:419