Galactic Bloodshed
GB_racegen.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 #include "gb/GB_racegen.h"
6 
7 #include <unistd.h>
8 
9 #include <csignal>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 
14 #include "gb/GB_server.h"
15 #include "gb/buffers.h"
16 #include "gb/build.h"
17 #include "gb/files_shl.h"
18 #include "gb/globals.h"
19 #include "gb/map.h"
20 #include "gb/max.h"
21 #include "gb/perm.h"
22 #include "gb/racegen.h"
23 #include "gb/races.h"
24 #include "gb/shipdata.h"
25 #include "gb/ships.h"
26 #include "gb/sql/sql.h"
27 #include "gb/tweakables.h"
28 #include "gb/utils/rand.h"
29 #include "gb/vars.h"
30 
31 static const PlanetType planet_translate[N_HOME_PLANET_TYPES] = {
32  PlanetType::EARTH, PlanetType::FOREST, PlanetType::DESERT,
33  PlanetType::WATER, PlanetType::MARS, PlanetType::ICEBALL,
34  PlanetType::GASGIANT};
35 
36 /* this is a dummy routine */
37 bool notify(const player_t, const governor_t, const std::string &) {
38  return false;
39 }
40 
41 /* this is a dummy routine */
42 void warn(const player_t, const governor_t, const std::string &) {}
43 
44 void init_enroll() { srandom(getpid()); }
45 
46 /*
47  * Returns 0 if successfully enrolled, or 1 if failure. */
49  int x;
50  int y;
51  int star;
52  int pnum;
53  int i;
54  int Playernum;
55  PlanetType ppref;
56  int last_star_left;
57  int indirect[NUMSTARS];
58  sigset_t mask;
59  sigset_t block;
60  Planet planet;
61  startype *star_arena;
62  /*
63  if (race.status == STATUS_ENROLLED) {
64  sprintf(race.rejection, "This race has already been enrolled!\n") ;
65  return 1 ;
66  }
67  */
68  Sql db{};
69  Playernum = Numraces() + 1;
70  if ((Playernum == 1) && (race_info.priv_type != P_GOD)) {
71  sprintf(race_info.rejection,
72  "The first race enrolled must have God privileges.\n");
73  return 1;
74  }
75  if (Playernum >= MAXPLAYERS) {
76  sprintf(race_info.rejection,
77  "There are already %d players; No more allowed.\n", MAXPLAYERS - 1);
78  race_info.status = STATUS_UNENROLLABLE;
79  return 1;
80  }
81 
82  getsdata(&Sdata);
83  star_arena = (startype *)malloc(Sdata.numstars * sizeof(startype));
84  for (star = 0; star < Sdata.numstars; star++) {
85  Stars[star] = &star_arena[star];
86  getstar(&(Stars[star]), star);
87  }
88 
89  printf("Looking for %s..", planet_print_name[race_info.home_planet_type]);
90  fflush(stdout);
91 
92  ppref = planet_translate[race_info.home_planet_type];
93  for (i = 0; i < Sdata.numstars; i++) indirect[i] = i;
94  last_star_left = Sdata.numstars - 1;
95  while (last_star_left >= 0) {
96  i = int_rand(0, last_star_left);
97  star = indirect[i];
98 
99  printf(".");
100  fflush(stdout);
101  /*
102  * Skip over inhabited stars and stars with few planets. */
103  if ((Stars[star]->numplanets < 2) || Stars[star]->inhabited[0] ||
104  Stars[star]->inhabited[1]) {
105  } else {
106  /* look for uninhabited planets */
107  for (pnum = 0; pnum < Stars[star]->numplanets; pnum++) {
108  planet = getplanet(star, pnum);
109  if ((planet.type == ppref) && (planet.conditions[RTEMP] >= -200) &&
110  (planet.conditions[RTEMP] <= 100))
111  goto found_planet;
112  }
113  }
114  /*
115  * Since we are here, this star didn't work out: */
116  indirect[i] = indirect[last_star_left--];
117  }
118 
119  /*
120  * If we get here, then we did not find any good planet. */
121  printf(" failed!\n");
122  sprintf(race_info.rejection,
123  "Didn't find any free %s; choose another home planet type.\n",
124  planet_print_name[race_info.home_planet_type]);
125  race_info.status = STATUS_UNENROLLABLE;
126  return 1;
127 
128 found_planet:
129  printf(" found!\n");
130  auto race = new Race;
131  bzero(race, sizeof(Race));
132 
133  race->Playernum = Playernum;
134  race->God = (race_info.priv_type == P_GOD);
135  race->Guest = (race_info.priv_type == P_GUEST);
136  strcpy(race->name, race_info.name);
137  strcpy(race->password, race_info.password);
138 
139  strcpy(race->governor[0].password, "0");
140  race->governor[0].homelevel = race->governor[0].deflevel =
141  ScopeLevel::LEVEL_PLAN;
142  race->governor[0].homesystem = race->governor[0].defsystem = star;
143  race->governor[0].homeplanetnum = race->governor[0].defplanetnum = pnum;
144  /* display options */
145  race->governor[0].toggle.highlight = Playernum;
146  race->governor[0].toggle.inverse = 1;
147  race->governor[0].toggle.color = 0;
148  race->governor[0].active = 1;
149 
150  for (i = 0; i <= OTHER; i++) race->conditions[i] = planet.conditions[i];
151 #if 0
152  /* make conditions preferred by your people set to (more or less)
153  those of the planet : higher the concentration of gas, the higher
154  percentage difference between planet and race */
155  for (j=0; j<=OTHER; j++)
156  race->conditions[j] = planet->conditions[j]
157  + int_rand(round_rand(-planet->conditions[j]*2.0),
158  round_rand(planet->conditions[j]*2.0) ) ;
159 #endif
160 
161  for (i = 0; i < MAXPLAYERS; i++) {
162  /* messages from autoreport, player #1 are decodable */
163  if ((i == Playernum) || (Playernum == 1) || race->God)
164  race->translate[i - 1] = 100; /* you can talk to own race */
165  else
166  race->translate[i - 1] = 1;
167  }
168 
169 #if 0
170  /* All of the following zeros are not really needed, because the race
171  was bzero'ed out above. */
172  for (i=0; i<80; i++)
173  race->discoveries[i] = 0;
174  race->tech = 0.0;
175  race->morale = 0;
176  race->turn = 0;
177  race->allied[0] = race->allied[1] = 0;
178  race->atwar[0] = race->atwar[1] = 0;
179  for (i=0; i<MAXPLAYERS; i++)
180  race->points[i]=0;
181 #endif
182 
183  /*
184  * Assign racial characteristics. */
185  race->absorb = race_info.attr[ABSORB];
186  race->collective_iq = race_info.attr[COL_IQ];
187  race->Metamorph = (race_info.race_type == R_METAMORPH);
188  race->pods = race_info.attr[PODS];
189 
190  race->fighters = race_info.attr[FIGHT];
191  if (race_info.attr[COL_IQ] == 1.0)
192  race->IQ_limit = race_info.attr[A_IQ];
193  else
194  race->IQ = race_info.attr[A_IQ];
195  race->number_sexes = race_info.attr[SEXES];
196 
197  race->fertilize = race_info.attr[FERT] * 100;
198 
199  race->adventurism = race_info.attr[ADVENT];
200  race->birthrate = race_info.attr[BIRTH];
201  race->mass = race_info.attr[MASS];
202  race->metabolism = race_info.attr[METAB];
203 
204  /*
205  * Assign sector compats and determine a primary sector type. */
206  for (i = FIRST_SECTOR_TYPE; i <= LAST_SECTOR_TYPE; i++) {
207  race->likes[i] = race_info.compat[i] / 100.0;
208  if ((100 == race_info.compat[i]) &&
209  (1.0 == planet_compat_cov[race_info.home_planet_type][i]))
210  race->likesbest = i;
211  }
212 
213  /*
214  * Find sector to build capital on, and populate it: */
215  auto smap = getsmap(planet);
216  PermuteSects(planet);
217  Getxysect(planet, nullptr, nullptr, 1);
218  while ((i = Getxysect(planet, &x, &y, 0)))
219  if (smap.get(x, y).condition == race->likesbest) break;
220  if (!i) x = y = 0;
221  auto &sect = smap.get(x, y);
222  sect.owner = Playernum;
223  sect.race = Playernum;
224  sect.popn = planet.popn = race->number_sexes;
225  sect.fert = 100;
226  sect.eff = 10;
227  sect.troops = planet.troops = 0;
228 
229  race->governors = 0;
230 
231  sigemptyset(&block);
232  sigaddset(&block, SIGHUP);
233  sigaddset(&block, SIGTERM);
234  sigaddset(&block, SIGINT);
235  sigaddset(&block, SIGQUIT);
236  sigaddset(&block, SIGSTOP);
237  sigaddset(&block, SIGTSTP);
238  sigprocmask(SIG_BLOCK, &block, &mask);
239  /* build a capital ship to run the government */
240  {
241  Ship s;
242  int shipno;
243 
244  bzero(&s, sizeof(s));
245  shipno = Numships() + 1;
246  race->Gov_ship = shipno;
247  planet.ships = shipno;
248  s.nextship = 0;
249 
250  s.type = ShipType::OTYPE_GOV;
251  s.xpos = Stars[star]->xpos + planet.xpos;
252  s.ypos = Stars[star]->ypos + planet.ypos;
253  s.land_x = x;
254  s.land_y = y;
255 
256  s.speed = 0;
257  s.owner = Playernum;
258  s.race = Playernum;
259  s.governor = 0;
260 
261  s.tech = 100.0;
262 
263  s.build_type = ShipType::OTYPE_GOV;
264  s.armor = Shipdata[ShipType::OTYPE_GOV][ABIL_ARMOR];
265  s.guns = PRIMARY;
266  s.primary = Shipdata[ShipType::OTYPE_GOV][ABIL_GUNS];
267  s.primtype = Shipdata[ShipType::OTYPE_GOV][ABIL_PRIMARY];
268  s.secondary = Shipdata[ShipType::OTYPE_GOV][ABIL_GUNS];
269  s.sectype = Shipdata[ShipType::OTYPE_GOV][ABIL_SECONDARY];
270  s.max_crew = Shipdata[ShipType::OTYPE_GOV][ABIL_MAXCREW];
271  s.max_destruct = Shipdata[ShipType::OTYPE_GOV][ABIL_DESTCAP];
272  s.max_resource = Shipdata[ShipType::OTYPE_GOV][ABIL_CARGO];
273  s.max_fuel = Shipdata[ShipType::OTYPE_GOV][ABIL_FUELCAP];
274  s.max_speed = Shipdata[ShipType::OTYPE_GOV][ABIL_SPEED];
275  s.build_cost = Shipdata[ShipType::OTYPE_GOV][ABIL_COST];
276  s.size = 100;
277  s.base_mass = 100.0;
278  sprintf(s.shipclass, "Standard");
279 
280  s.fuel = 0.0;
281  s.popn = Shipdata[s.type][ABIL_MAXCREW];
282  s.troops = 0;
283  s.mass = s.base_mass + Shipdata[s.type][ABIL_MAXCREW] * race->mass;
284  s.destruct = s.resource = 0;
285 
286  s.alive = 1;
287  s.active = 1;
288  s.protect.self = 1;
289 
290  s.docked = 1;
291  /* docked on the planet */
292  s.whatorbits = ScopeLevel::LEVEL_PLAN;
293  s.whatdest = ScopeLevel::LEVEL_PLAN;
294  s.deststar = star;
295  s.destpnum = pnum;
296  s.storbits = star;
297  s.pnumorbits = pnum;
298  s.rad = 0;
299  s.damage = 0; /*Shipdata[s.type][ABIL_DAMAGE];*/
300  /* (first capital is 100% efficient */
301  s.retaliate = 0;
302 
303  s.ships = 0;
304 
305  s.on = 1;
306 
307  s.name[0] = '\0';
308  s.number = shipno;
309  putship(&s);
310  }
311 
312  planet.info[Playernum - 1].numsectsowned = 1;
313  planet.explored = 0;
314  planet.info[Playernum - 1].explored = 1;
315  /*planet->info[Playernum-1].autorep = 1;*/
316 
317  planet.maxpopn =
318  maxsupport(race, sect, 100.0, 0) * planet.Maxx * planet.Maxy / 2;
319  /* (approximate) */
320 
321 #ifdef STARTING_INVENTORY
322 
323  if (race->Metamorph)
324  planet.info[Playernum - 1].resource += (START_RES - START_MESO_RES_DIFF);
325  else
326  planet.info[Playernum - 1].resource += START_RES;
327 
328  planet.info[Playernum - 1].fuel += START_FUEL;
329  planet.info[Playernum - 1].destruct += START_DES;
330 
331 #endif
332 
333  putrace(race);
334  putsector(sect, planet, x, y);
335 
336  getstar(&Stars[star], star);
337  putplanet(planet, Stars[star], pnum);
338 
339  /* make star explored and stuff */
340  setbit(Stars[star]->explored, Playernum);
341  setbit(Stars[star]->inhabited, Playernum);
342  Stars[star]->AP[Playernum - 1] = 5;
343  putstar(Stars[star], star);
344 
345  sigprocmask(SIG_SETMASK, &mask, nullptr);
346 
347  printf("Player %d (%s) created on sector %d,%d on %s/%s.\n", Playernum,
348  race_info.name, x, y, Stars[star]->name, Stars[star]->pnames[pnum]);
349  race_info.status = STATUS_ENROLLED;
350  return 0;
351 }
#define ADVENT
Definition: racegen.h:45
#define MASS
Definition: racegen.h:53
#define P_GUEST
Definition: racegen.h:134
static const PlanetType planet_translate[N_HOME_PLANET_TYPES]
Definition: GB_racegen.cc:31
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
void PermuteSects(const Planet &planet)
Definition: perm.cc:16
void warn(const player_t, const governor_t, const std::string &)
Definition: GB_racegen.cc:42
#define PODS
Definition: racegen.h:52
void putsector(const Sector &s, const Planet &p, const int x, const int y)
Definition: files_shl.cc:1076
#define setbit(a, i)
Definition: vars.h:310
bool notify(const player_t, const governor_t, const std::string &)
Definition: GB_racegen.cc:37
shipnum_t Numships()
Definition: files_shl.cc:1516
#define FIRST_SECTOR_TYPE
Definition: racegen.h:144
#define PRIMARY
Definition: ships.h:15
#define COL_IQ
Definition: racegen.h:48
#define A_IQ
Definition: racegen.h:50
#define OTHER
Definition: tweakables.h:38
#define SEXES
Definition: racegen.h:54
#define LAST_SECTOR_TYPE
Definition: racegen.h:153
#define STATUS_ENROLLED
Definition: racegen.h:167
void putstar(startype *s, starnum_t snum)
Definition: files_shl.cc:813
#define P_GOD
Definition: racegen.h:133
void getsdata(struct stardata *S)
Definition: files_shl.cc:272
void putplanet(const Planet &p, startype *star, const int pnum)
Definition: files_shl.cc:934
#define STATUS_UNENROLLABLE
Definition: racegen.h:168
void getstar(startype **s, int star)
Definition: files_shl.cc:281
#define N_HOME_PLANET_TYPES
Definition: racegen.h:112
#define ABSORB
Definition: racegen.h:46
void putship(Ship *s)
Definition: files_shl.cc:1317
#define METAB
Definition: racegen.h:55
SectorMap getsmap(const Planet &p)
Definition: files_shl.cc:522
int Getxysect(const Planet &p, int *x, int *y, int r)
Definition: perm.cc:39
#define RTEMP
Definition: tweakables.h:29
#define R_METAMORPH
Definition: racegen.h:122
#define FERT
Definition: racegen.h:49
int maxsupport(const Race *r, const Sector &s, const double c, const int toxic)
Definition: max.cc:26
#define NUMSTARS
Definition: tweakables.h:71
int Numraces()
Definition: files_shl.cc:1509
void init_enroll()
Definition: GB_racegen.cc:44
int enroll_valid_race()
Definition: GB_racegen.cc:48
#define BIRTH
Definition: racegen.h:47
#define MAXPLAYERS
Definition: vars.h:45
#define FIGHT
Definition: racegen.h:51
void putrace(Race *r)
Definition: files_shl.cc:808