Galactic Bloodshed
enrol.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 /* enrol.c -- initializes to owner one sector and planet. */
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/races.h"
23 #include "gb/shipdata.h"
24 #include "gb/ships.h"
25 #include "gb/sql/sql.h"
26 #include "gb/tweakables.h"
27 #include "gb/utils/rand.h"
28 #include "gb/vars.h"
29 
30 struct stype {
31  char here;
32  char x, y;
33  int count;
34 };
35 
36 #define RACIAL_TYPES 10
37 
38 // TODO(jeffbailey): Copied from map.c, but they've diverged
39 static char desshow(const int x, const int y, SectorMap &);
40 
41 /* racial types (10 racial types ) */
42 static int Thing[RACIAL_TYPES] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
43 
44 static double db_Mass[RACIAL_TYPES] = {.1, .15, .2, .125, .125,
45  .125, .125, .125, .125, .125};
46 static double db_Birthrate[RACIAL_TYPES] = {0.9, 0.85, 0.8, 0.5, 0.55,
47  0.6, 0.65, 0.7, 0.75, 0.8};
48 static int db_Fighters[RACIAL_TYPES] = {9, 10, 11, 2, 3, 4, 5, 6, 7, 8};
49 static int db_Intelligence[RACIAL_TYPES] = {0, 0, 0, 190, 180,
50  170, 160, 150, 140, 130};
51 
52 static double db_Adventurism[RACIAL_TYPES] = {0.89, 0.89, 0.89, .6, .65,
53  .7, .7, .75, .75, .8};
54 
55 static int Min_Sexes[RACIAL_TYPES] = {1, 1, 1, 2, 2, 2, 2, 2, 2, 2};
56 static int Max_Sexes[RACIAL_TYPES] = {1, 1, 1, 2, 2, 4, 4, 4, 4, 4};
57 static double db_Metabolism[RACIAL_TYPES] = {3.0, 2.7, 2.4, 1.0, 1.15,
58  1.30, 1.45, 1.6, 1.75, 1.9};
59 
60 #define RMass(x) (db_Mass[(x)] + .001 * (double)int_rand(-25, 25))
61 #define Birthrate(x) (db_Birthrate[(x)] + .01 * (double)int_rand(-10, 10))
62 #define Fighters(x) (db_Fighters[(x)] + int_rand(-1, 1))
63 #define Intelligence(x) (db_Intelligence[(x)] + int_rand(-10, 10))
64 #define Adventurism(x) (db_Adventurism[(x)] + 0.01 * (double)int_rand(-10, 10))
65 #define Sexes(x)
66  (int_rand(Min_Sexes[(x)], int_rand(Min_Sexes[(x)], Max_Sexes[(x)])))
67 #define Metabolism(x) (db_Metabolism[(x)] + .01 * (double)int_rand(-15, 15))
68 
69 int main() {
70  int x;
71  int y;
72  int pnum;
73  int star = 0;
74  int found = 0;
75  int check;
76  int vacant;
77  int count;
78  int i;
79  int j;
80  int Playernum;
81  PlanetType ppref;
82  sigset_t mask;
83  sigset_t block;
84  int idx;
85  int k;
86 #define STRSIZE 100
87  char str[STRSIZE];
88  char c;
89  struct stype secttypes[SectorType::SEC_WASTED + 1] = {};
90  Planet planet;
91  unsigned char not_found[PlanetType::DESERT + 1];
92  startype *star_arena;
93 
94  Sql db{};
95 
96  srandom(getpid());
97 
98  if ((Playernum = Numraces() + 1) >= MAXPLAYERS) {
99  printf("There are already %d players; No more allowed.\n", MAXPLAYERS - 1);
100  exit(-1);
101  }
102 
103  printf("Enter racial type to be created (1-%d):", RACIAL_TYPES);
104  scanf("%d", &idx);
105  getchr();
106 
107  if (idx <= 0 || idx > RACIAL_TYPES) {
108  printf("Bad racial index.\n");
109  exit(1);
110  }
111  idx = idx - 1;
112 
113  getsdata(&Sdata);
114 
115  star_arena = (startype *)malloc(Sdata.numstars * sizeof(startype));
116  for (int s = 0; s < Sdata.numstars; s++) {
117  Stars[s] = &star_arena[s];
118  getstar(&(Stars[s]), s);
119  }
120  printf("There is still space for player %d.\n", Playernum);
121 
122  bzero((char *)not_found, sizeof(not_found));
123  do {
124  printf(
125  "\nLive on what type planet:\n (e)arth, (g)asgiant, (m)ars, "
126  "(i)ce, (w)ater, (d)esert, (f)orest? ");
127  c = getchr();
128  getchr();
129 
130  switch (c) {
131  case 'w':
132  ppref = PlanetType::WATER;
133  break;
134  case 'e':
135  ppref = PlanetType::EARTH;
136  break;
137  case 'm':
138  ppref = PlanetType::MARS;
139  break;
140  case 'g':
141  ppref = PlanetType::GASGIANT;
142  break;
143  case 'i':
144  ppref = PlanetType::ICEBALL;
145  break;
146  case 'd':
147  ppref = PlanetType::DESERT;
148  break;
149  case 'f':
150  ppref = PlanetType::FOREST;
151  break;
152  default:
153  printf("Oh well.\n");
154  exit(-1);
155  }
156 
157  printf("Looking for type %d planet...\n", ppref);
158 
159  /* find first planet of right type */
160  count = 0;
161  found = 0;
162 
163  for (star = 0; star < Sdata.numstars && !found && count < 100;) {
164  check = 1;
165  /* skip over inhabited stars - or stars with just one planet! */
166  if (Stars[star]->inhabited[0] + Stars[star]->inhabited[1] ||
167  Stars[star]->numplanets < 2)
168  check = 0;
169 
170  /* look for uninhabited planets */
171  if (check) {
172  pnum = 0;
173  while (!found && pnum < Stars[star]->numplanets) {
174  planet = getplanet(star, pnum);
175 
176  if (planet.type == ppref && Stars[star]->numplanets != 1) {
177  vacant = 1;
178  for (i = 1; i <= Playernum; i++)
179  if (planet.info[i - 1].numsectsowned) vacant = 0;
180  if (vacant && planet.conditions[RTEMP] >= -50 &&
181  planet.conditions[RTEMP] <= 50) {
182  found = 1;
183  }
184  }
185  if (!found) {
186  pnum++;
187  }
188  }
189  }
190 
191  if (!found) {
192  count++;
193  star = int_rand(0, Sdata.numstars - 1);
194  }
195  }
196 
197  if (!found) {
198  printf("planet type not found in any free systems.\n");
199  not_found[ppref] = 1;
200  for (found = 1, i = PlanetType::EARTH; i <= PlanetType::DESERT; i++)
201  found &= not_found[i];
202  if (found) {
203  printf("Looks like there aren't any free planets left. bye..\n");
204  exit(-1);
205  } else
206  printf(" Try a different one...\n");
207  found = 0;
208  }
209 
210  } while (!found);
211 
212  auto race = new Race;
213  bzero(race, sizeof(Race));
214 
215  printf("\n\tDeity/Guest/Normal (d/g/n) ?");
216  c = getchr();
217  getchr();
218 
219  race->God = (c == 'd');
220  race->Guest = (c == 'g');
221  strcpy(race->name, "Unknown");
222 
223  // TODO(jeffbailey): What initializes the rest of the governors?
224  race->governor[0].money = 0;
225  race->governor[0].homelevel = race->governor[0].deflevel =
226  ScopeLevel::LEVEL_PLAN;
227  race->governor[0].homesystem = race->governor[0].defsystem = star;
228  race->governor[0].homeplanetnum = race->governor[0].defplanetnum = pnum;
229  /* display options */
230  race->governor[0].toggle.highlight = Playernum;
231  race->governor[0].toggle.inverse = 1;
232  race->governor[0].toggle.color = 0;
233  race->governor[0].active = 1;
234  printf("Enter the password for this race:");
235  scanf("%s", race->password);
236  getchr();
237  printf("Enter the password for this leader:");
238  scanf("%s", race->governor[0].password);
239  getchr();
240 
241  /* make conditions preferred by your people set to (more or less)
242  those of the planet : higher the concentration of gas, the higher
243  percentage difference between planet and race (commented out) */
244  for (j = 0; j <= OTHER; j++) race->conditions[j] = planet.conditions[j];
245  /*+ int_rand( round_rand(-planet->conditions[j]*2.0),
246  * round_rand(planet->conditions[j]*2.0) )*/
247 
248  for (i = 0; i < MAXPLAYERS; i++) {
249  /* messages from autoreport, player #1 are decodable */
250  if ((i == (Playernum - 1) || Playernum == 1) || race->God)
251  race->translate[i] = 100; /* you can talk to own race */
252  else
253  race->translate[i] = 1;
254  }
255 
256  /* assign racial characteristics */
257  for (i = 0; i < NUM_DISCOVERIES; i++) race->discoveries[i] = 0;
258  race->tech = 0.0;
259  race->morale = 0;
260  race->turn = 0;
261  race->allied[0] = race->allied[1] = 0;
262  race->atwar[0] = race->atwar[1] = 0;
263  do {
264  race->mass = RMass(idx);
265  race->birthrate = Birthrate(idx);
266  race->fighters = Fighters(idx);
267  if (Thing[idx]) {
268  race->IQ = 0;
269  race->Metamorph = race->absorb = race->collective_iq = race->pods = 1;
270  } else {
271  race->IQ = Intelligence(idx);
272  race->Metamorph = race->absorb = race->collective_iq = race->pods = 0;
273  }
274  race->adventurism = Adventurism(idx);
275  race->number_sexes = Sexes(idx);
276  race->metabolism = Metabolism(idx);
277 
278  printf("%s\n", race->Metamorph ? "METAMORPHIC" : "");
279  printf(" Birthrate: %.3f\n", race->birthrate);
280  printf("Fighting ability: %d\n", race->fighters);
281  printf(" IQ: %d\n", race->IQ);
282  printf(" Metabolism: %.2f\n", race->metabolism);
283  printf(" Adventurism: %.2f\n", race->adventurism);
284  printf(" Mass: %.2f\n", race->mass);
285  printf(" Number of sexes: %d (min req'd for colonization)\n",
286  race->number_sexes);
287 
288  printf("\n\nLook OK(y/n)\?");
289  if (fgets(str, STRSIZE, stdin) == nullptr) exit(1);
290  } while (str[0] != 'y');
291 
292  auto smap = getsmap(planet);
293 
294  printf(
295  "\nChoose a primary sector preference. This race will prefer to "
296  "live\non this type of sector.\n");
297 
298  PermuteSects(planet);
299  Getxysect(planet, nullptr, nullptr, 1);
300  while (Getxysect(planet, &x, &y, 0)) {
301  secttypes[smap.get(x, y).condition].count++;
302  if (!secttypes[smap.get(x, y).condition].here) {
303  secttypes[smap.get(x, y).condition].here = 1;
304  secttypes[smap.get(x, y).condition].x = x;
305  secttypes[smap.get(x, y).condition].y = y;
306  }
307  }
308  planet.explored = 1;
309  for (i = SectorType::SEC_SEA; i <= SectorType::SEC_WASTED; i++)
310  if (secttypes[i].here) {
311  printf("(%2d): %c (%d, %d) (%s, %d sectors)\n", i,
312  desshow(secttypes[i].x, secttypes[i].y, smap), secttypes[i].x,
313  secttypes[i].y, Desnames[i], secttypes[i].count);
314  }
315  planet.explored = 0;
316 
317  found = 0;
318  do {
319  printf("\nchoice (enter the number): ");
320  scanf("%d", &i);
321  getchr();
322  if (i < SectorType::SEC_SEA || i > SectorType::SEC_WASTED ||
323  !secttypes[i].here) {
324  printf("There are none of that type here..\n");
325  } else
326  found = 1;
327  } while (!found);
328 
329  auto &sect = smap.get(secttypes[i].x, secttypes[i].y);
330  race->likesbest = i;
331  race->likes[i] = 1.0;
332  race->likes[SectorType::SEC_PLATED] = 1.0;
333  race->likes[SectorType::SEC_WASTED] = 0.0;
334  printf("\nEnter compatibilities of other sectors -\n");
335  for (j = SectorType::SEC_SEA; j < SectorType::SEC_PLATED; j++)
336  if (i != j) {
337  printf("%6s (%3d sectors) :", Desnames[j], secttypes[j].count);
338  scanf("%d", &k);
339  race->likes[j] = (double)k / 100.0;
340  }
341  printf("Numraces = %d\n", Numraces());
342  Playernum = race->Playernum = Numraces() + 1;
343 
344  sigemptyset(&block);
345  sigaddset(&block, SIGHUP);
346  sigaddset(&block, SIGTERM);
347  sigaddset(&block, SIGINT);
348  sigaddset(&block, SIGQUIT);
349  sigaddset(&block, SIGSTOP);
350  sigaddset(&block, SIGTSTP);
351  sigprocmask(SIG_BLOCK, &block, &mask);
352  /* build a capital ship to run the government */
353  {
354  Ship s;
355  int shipno;
356 
357  bzero(&s, sizeof(s));
358  shipno = Numships() + 1;
359  printf("Creating government ship %d...\n", shipno);
360  race->Gov_ship = shipno;
361  planet.ships = shipno;
362  s.nextship = 0;
363 
364  s.type = ShipType::OTYPE_GOV;
365  s.xpos = Stars[star]->xpos + planet.xpos;
366  s.ypos = Stars[star]->ypos + planet.ypos;
367  s.land_x = (char)secttypes[i].x;
368  s.land_y = (char)secttypes[i].y;
369 
370  s.speed = 0;
371  s.owner = Playernum;
372  s.race = Playernum;
373  s.governor = 0;
374 
375  s.tech = 100.0;
376 
377  s.build_type = ShipType::OTYPE_GOV;
378  s.armor = Shipdata[ShipType::OTYPE_GOV][ABIL_ARMOR];
379  s.guns = PRIMARY;
380  s.primary = Shipdata[ShipType::OTYPE_GOV][ABIL_GUNS];
381  s.primtype = Shipdata[ShipType::OTYPE_GOV][ABIL_PRIMARY];
382  s.secondary = Shipdata[ShipType::OTYPE_GOV][ABIL_GUNS];
383  s.sectype = Shipdata[ShipType::OTYPE_GOV][ABIL_SECONDARY];
384  s.max_crew = Shipdata[ShipType::OTYPE_GOV][ABIL_MAXCREW];
385  s.max_destruct = Shipdata[ShipType::OTYPE_GOV][ABIL_DESTCAP];
386  s.max_resource = Shipdata[ShipType::OTYPE_GOV][ABIL_CARGO];
387  s.max_fuel = Shipdata[ShipType::OTYPE_GOV][ABIL_FUELCAP];
388  s.max_speed = Shipdata[ShipType::OTYPE_GOV][ABIL_SPEED];
389  s.build_cost = Shipdata[ShipType::OTYPE_GOV][ABIL_COST];
390  s.size = 100;
391  s.base_mass = 100.0;
392  sprintf(s.shipclass, "Standard");
393 
394  s.fuel = 0.0;
395  s.popn = Shipdata[s.type][ABIL_MAXCREW];
396  s.troops = 0;
397  s.mass = s.base_mass + Shipdata[s.type][ABIL_MAXCREW] * race->mass;
398  s.destruct = s.resource = 0;
399 
400  s.alive = 1;
401  s.active = 1;
402  s.protect.self = 1;
403 
404  s.docked = 1;
405  /* docked on the planet */
406  s.whatorbits = ScopeLevel::LEVEL_PLAN;
407  s.whatdest = ScopeLevel::LEVEL_PLAN;
408  s.deststar = star;
409  s.destpnum = pnum;
410  s.storbits = star;
411  s.pnumorbits = pnum;
412  s.rad = 0;
413  s.damage = 0; /*Shipdata[s.type][ABIL_DAMAGE];*/
414  /* (first capital is 100% efficient */
415  s.retaliate = 0;
416 
417  s.ships = 0;
418 
419  s.on = 1;
420 
421  s.name[0] = '\0';
422  s.number = shipno;
423  printf("Created on sector %d,%d on /%s/%s\n", s.land_x, s.land_y,
424  Stars[s.storbits]->name, Stars[s.storbits]->pnames[s.pnumorbits]);
425  putship(&s);
426  }
427 
428  for (j = 0; j < MAXPLAYERS; j++) race->points[j] = 0;
429 
430  putrace(race);
431 
432  planet.info[Playernum - 1].numsectsowned = 1;
433  planet.explored = 0;
434  planet.info[Playernum - 1].explored = 1;
435  /*planet->info[Playernum-1].autorep = 1;*/
436 
437  sect.owner = Playernum;
438  sect.race = Playernum;
439  sect.popn = planet.popn = race->number_sexes;
440  sect.fert = 100;
441  sect.eff = 10;
442  sect.troops = planet.troops = 0;
443  planet.maxpopn =
444  maxsupport(race, sect, 100.0, 0) * planet.Maxx * planet.Maxy / 2;
445  /* (approximate) */
446 
447  putsector(sect, planet, secttypes[i].x, secttypes[i].y);
448  putplanet(planet, Stars[star], pnum);
449 
450  /* make star explored and stuff */
451  getstar(&Stars[star], star);
452  setbit(Stars[star]->explored, Playernum);
453  setbit(Stars[star]->inhabited, Playernum);
454  Stars[star]->AP[Playernum - 1] = 5;
455  putstar(Stars[star], star);
456 
457  sigprocmask(SIG_SETMASK, &mask, nullptr);
458 
459  printf("\nYou are player %d.\n\n", Playernum);
460  printf("Your race has been created on sector %d,%d on\n", secttypes[i].x,
461  secttypes[i].y);
462  printf("%s/%s.\n\n", Stars[star]->name, Stars[star]->pnames[pnum]);
463  return 0;
464 }
465 
466 static char desshow(const int x, const int y,
467  SectorMap &smap) /* copied from map.c */
468 {
469  const auto &s = smap.get(x, y);
470 
471  switch (s.condition) {
472  case SectorType::SEC_WASTED:
473  return CHAR_WASTED;
474  case SectorType::SEC_SEA:
475  return CHAR_SEA;
476  case SectorType::SEC_LAND:
477  return CHAR_LAND;
478  case SectorType::SEC_MOUNT:
479  return CHAR_MOUNT;
480  case SectorType::SEC_GAS:
481  return CHAR_GAS;
482  case SectorType::SEC_PLATED:
483  return CHAR_PLATED;
484  case SectorType::SEC_DESERT:
485  return CHAR_DESERT;
486  case SectorType::SEC_FOREST:
487  return CHAR_FOREST;
488  case SectorType::SEC_ICE:
489  return CHAR_ICE;
490  default:
491  return ('!');
492  }
493 }
494 
495 // TODO(jeffbailey): We shouldn't need to be providing this function.
496 /* this is a dummy routine */
497 bool notify(const player_t, const governor_t, const std::string &) {
498  return false;
499 }
500 
501 // TODO(jeffbailey): We shouldn't need to be providing this function.
502 /* this is a dummy routine */
503 void warn(const player_t, const governor_t, const std::string &){};
#define Sexes(x)
Definition: enrol.cc:65
static int db_Intelligence[RACIAL_TYPES]
Definition: enrol.cc:49
Planet getplanet(const starnum_t star, const planetnum_t pnum)
Definition: files_shl.cc:335
#define STRSIZE
static double db_Metabolism[RACIAL_TYPES]
Definition: enrol.cc:57
void PermuteSects(const Planet &planet)
Definition: perm.cc:16
static double db_Mass[RACIAL_TYPES]
Definition: enrol.cc:44
#define getchr()
Definition: tweakables.h:210
void warn(const player_t, const governor_t, const std::string &)
Definition: GB_racegen.cc:42
static double db_Adventurism[RACIAL_TYPES]
Definition: enrol.cc: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
Definition: enrol.cc:30
static char desshow(const int x, const int y, SectorMap &)
Definition: enrol.cc:466
#define Intelligence(x)
Definition: enrol.cc:63
#define Metabolism(x)
Definition: enrol.cc:67
shipnum_t Numships()
Definition: files_shl.cc:1516
#define PRIMARY
Definition: ships.h:15
char here
Definition: enrol.cc:31
#define Adventurism(x)
Definition: enrol.cc:64
#define Birthrate(x)
Definition: enrol.cc:61
char y
Definition: enrol.cc:32
int main()
Definition: shlmisc_test.cc:27
int count
Definition: enrol.cc:33
static int db_Fighters[RACIAL_TYPES]
Definition: enrol.cc:48
#define RMass(x)
Definition: enrol.cc:60
#define OTHER
Definition: tweakables.h:38
#define NUM_DISCOVERIES
Definition: races.h:69
void putstar(startype *s, starnum_t snum)
Definition: files_shl.cc:813
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
char x
Definition: enrol.cc:32
#define RACIAL_TYPES
Definition: enrol.cc:36
void getstar(startype **s, int star)
Definition: files_shl.cc:281
#define Fighters(x)
Definition: enrol.cc:62
static int Max_Sexes[RACIAL_TYPES]
Definition: enrol.cc:56
void putship(Ship *s)
Definition: files_shl.cc:1317
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
static int Min_Sexes[RACIAL_TYPES]
Definition: enrol.cc:55
int maxsupport(const Race *r, const Sector &s, const double c, const int toxic)
Definition: max.cc:26
int Numraces()
Definition: files_shl.cc:1509
static int Thing[RACIAL_TYPES]
Definition: enrol.cc:42
static double db_Birthrate[RACIAL_TYPES]
Definition: enrol.cc:46
#define MAXPLAYERS
Definition: vars.h:45
void putrace(Race *r)
Definition: files_shl.cc:808