Freeciv21
Develop your civilization from humble roots to a global empire
gamehand.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <QtWidgets/QtWidgets>
15 #include <cstdio> // for remove()
16 
17 // utility
18 #include "fcintl.h"
19 #include "log.h"
20 #include "rand.h"
21 #include "section_file.h"
22 #include "shared.h"
23 #include "support.h"
24 
25 // common
26 #include "ai.h"
27 #include "calendar.h"
28 #include "events.h"
29 #include "game.h"
30 #include "movement.h"
31 #include "nation.h"
32 
33 // server
34 #include "citytools.h"
35 #include "connecthand.h"
36 #include "maphand.h"
37 #include "notify.h"
38 #include "srv_main.h"
39 #include "stdinhand.h"
40 #include "unittools.h"
41 
42 /* server/advisors */
43 #include "advdata.h"
44 
45 #include "gamehand.h"
46 
47 #define CHALLENGE_ROOT "challenge"
48 
49 #define SPECLIST_TAG startpos
50 #define SPECLIST_TYPE struct startpos
51 #include "speclist.h"
52 #define startpos_list_iterate(list, plink, psp) \
53  TYPED_LIST_BOTH_ITERATE(struct startpos_list_link, struct startpos, list, \
54  plink, psp)
55 #define startpos_list_iterate_end LIST_BOTH_ITERATE_END
56 
58  struct tile **startpos;
62 };
63 
65  int *startpos;
66  long score;
67 };
68 
69 #define SPECPQ_TAG team_placement
70 #define SPECPQ_DATA_TYPE struct team_placement_state *
71 #define SPECPQ_PRIORITY_TYPE long
72 #include "specpq.h"
73 
77 enum unit_role_id crole_to_role_id(char crole)
78 {
79  switch (crole) {
80  case 'c':
81  return L_START_CITIES;
82  case 'w':
83  return L_START_WORKER;
84  case 'x':
85  return L_START_EXPLORER;
86  case 'k':
87  return L_START_KING;
88  case 's':
89  return L_START_DIPLOMAT;
90  case 'f':
91  return L_START_FERRY;
92  case 'd':
93  return L_START_DEFEND_OK;
94  case 'D':
95  return L_START_DEFEND_GOOD;
96  case 'a':
97  return L_START_ATTACK_FAST;
98  case 'A':
99  return L_START_ATTACK_STRONG;
100  default:
101  return unit_role_id(0);
102  }
103 }
104 
108 struct unit_type *crole_to_unit_type(char crole, struct player *pplayer)
109 {
110  struct unit_type *utype = nullptr;
111  enum unit_role_id role = crole_to_role_id(crole);
112 
113  if (role == 0) {
114  fc_assert_ret_val(false, nullptr);
115  return nullptr;
116  }
117 
118  // Create the unit of an appropriate type, if it exists
119  if (num_role_units(role) > 0) {
120  if (pplayer != nullptr) {
121  utype = first_role_unit_for_player(pplayer, role);
122  }
123  if (utype == nullptr) {
124  utype = get_role_unit(role, 0);
125  }
126  }
127 
128  return utype;
129 }
130 
136 static struct tile *place_starting_unit(struct tile *starttile,
137  struct player *pplayer,
138  struct unit_type *ptype, char crole)
139 {
140  struct tile *ptile = nullptr;
141  struct unit_type *utype;
142  bool hut_present = false;
143 
144  if (ptype != nullptr) {
145  utype = ptype;
146  } else {
147  utype = crole_to_unit_type(crole, pplayer);
148  }
149 
150  if (utype != nullptr) {
151  iterate_outward(&(wld.map), starttile, wld.map.xsize + wld.map.ysize,
152  itertile)
153  {
154  if (!is_non_allied_unit_tile(itertile, pplayer)
155  && is_native_tile(utype, itertile)) {
156  ptile = itertile;
157  break;
158  }
159  }
161  }
162 
163  if (ptile == nullptr) {
164  // No place where unit may exist.
165  return nullptr;
166  }
167 
168  fc_assert_ret_val(!is_non_allied_unit_tile(ptile, pplayer), nullptr);
169 
170  /* For scenarios or dispersion, huts may coincide with player starts (in
171  * other cases, huts are avoided as start positions). Remove any such hut,
172  * and make sure to tell the client, since we may have already sent this
173  * tile (with the hut) earlier: */
174  // FIXME: don't remove under a HUT_NOTHING unit
175  extra_type_by_rmcause_iterate(ERM_ENTER, pextra)
176  {
177  if (tile_has_extra(ptile, pextra)) {
178  tile_extra_rm_apply(ptile, pextra);
179  hut_present = true;
180  }
181  }
183 
184  if (hut_present) {
185  update_tile_knowledge(ptile);
186  qDebug("Removed hut on start position for %s", player_name(pplayer));
187  }
188 
189  // Expose visible area.
190  map_show_circle(pplayer, ptile, game.server.init_vis_radius_sq);
191 
192  (void) create_unit(pplayer, ptile, utype, false, 0, 0);
193  return ptile;
194 }
195 
199 static struct tile *find_dispersed_position(struct player *pplayer,
200  struct tile *pcenter)
201 {
202  struct tile *ptile;
203  int x, y;
204 
205  do {
206  index_to_map_pos(&x, &y, tile_index(pcenter));
207  x += fc_rand(2 * game.server.dispersion + 1) - game.server.dispersion;
208  y += fc_rand(2 * game.server.dispersion + 1) - game.server.dispersion;
209  } while (
210  !((ptile = map_pos_to_tile(&(wld.map), x, y))
211  && tile_continent(pcenter) == tile_continent(ptile)
212  && !is_ocean_tile(ptile)
213  && real_map_distance(pcenter, ptile) < game.server.dispersion + 1
214  && !is_non_allied_unit_tile(ptile, pplayer)));
215 
216  return ptile;
217 }
218 
219 /* Calculate the distance between tiles, according to the 'teamplacement'
220  * setting set to 'CLOSEST'. */
221 #define team_placement_closest sq_map_distance
222 
227 static int team_placement_continent(const struct tile *ptile1,
228  const struct tile *ptile2)
229 {
230  return (ptile1->continent == ptile2->continent
231  ? sq_map_distance(ptile1, ptile2)
232  : sq_map_distance(ptile1, ptile2) + MAP_INDEX_SIZE);
233 }
234 
239 static int team_placement_horizontal(const struct tile *ptile1,
240  const struct tile *ptile2)
241 {
242  int dx, dy;
243 
244  map_distance_vector(&dx, &dy, ptile1, ptile2);
245  // Map vector to natural vector (Y axis).
246  return abs(MAP_IS_ISOMETRIC ? dx + dy : dy);
247 }
248 
253 static int team_placement_vertical(const struct tile *ptile1,
254  const struct tile *ptile2)
255 {
256  int dx, dy;
257 
258  map_distance_vector(&dx, &dy, ptile1, ptile2);
259  // Map vector to natural vector (X axis).
260  return abs(MAP_IS_ISOMETRIC ? dx - dy : dy);
261 }
262 
267 {
268  delete[] pstate->startpos;
269  delete pstate;
270 }
271 
275 static void do_team_placement(const struct team_placement_config *pconfig,
276  struct team_placement_state *pbest_state,
277  int iter_max)
278 {
279  const size_t state_array_size =
280  (sizeof(*pbest_state->startpos) * pconfig->total_startpos_num);
281  int (*distance)(const struct tile *, const struct tile *) = nullptr;
282  const struct tile *ptile1, *ptile2;
283  long base_delta, delta;
284  bool base_delta_calculated;
285  int iter = 0;
286  bool repeat;
287  int i, j, k, t1, t2;
288 
289  switch (wld.map.server.team_placement) {
290  case TEAM_PLACEMENT_CLOSEST:
291  distance = team_placement_closest;
292  break;
293  case TEAM_PLACEMENT_CONTINENT:
294  distance = team_placement_continent;
295  break;
296  case TEAM_PLACEMENT_HORIZONTAL:
297  distance = team_placement_horizontal;
298  break;
299  case TEAM_PLACEMENT_VERTICAL:
300  distance = team_placement_vertical;
301  break;
302  case TEAM_PLACEMENT_DISABLED:
303  break;
304  }
305  fc_assert_ret_msg(distance != nullptr, "Wrong team_placement variant (%d)",
306  wld.map.server.team_placement);
307 
308  struct team_placement_pq *pqueue =
309  team_placement_pq_new(pconfig->total_startpos_num * 4);
310  // Initialize starting state.
311  auto *pstate = new team_placement_state;
312  pstate->startpos = new int[pconfig->total_startpos_num];
313  memcpy(pstate->startpos, pbest_state->startpos, state_array_size);
314  pstate->score = pbest_state->score;
315 
316  do {
317  repeat = false;
318  for (i = 0; i < pconfig->usable_startpos_num; i++) {
319  t1 = pstate->startpos[i];
320  if (t1 == -1) {
321  continue; // Not used.
322  }
323  ptile1 = pconfig->startpos[i];
324  base_delta_calculated = false;
325  for (j = i + 1; j < (i >= pconfig->flexible_startpos_num
326  ? pconfig->usable_startpos_num
327  : pconfig->flexible_startpos_num);
328  j++) {
329  t2 = pstate->startpos[j];
330  if (t2 == -1) {
331  // Not assigned yet.
332  ptile2 = pconfig->startpos[j];
333  if (base_delta_calculated) {
334  delta = base_delta;
335  for (k = 0; k < pconfig->total_startpos_num; k++) {
336  if (k != i && t1 == pstate->startpos[k]) {
337  delta += distance(ptile2, pconfig->startpos[k]);
338  }
339  }
340  } else {
341  delta = 0;
342  base_delta = 0;
343  for (k = 0; k < pconfig->total_startpos_num; k++) {
344  if (k != i && t1 == pstate->startpos[k]) {
345  base_delta -= distance(ptile1, pconfig->startpos[k]);
346  delta += distance(ptile2, pconfig->startpos[k]);
347  }
348  }
349  delta += base_delta;
350  base_delta_calculated = true;
351  }
352  } else if (t1 < t2) {
353  ptile2 = pconfig->startpos[j];
354  if (base_delta_calculated) {
355  delta = base_delta;
356  for (k = 0; k < pconfig->total_startpos_num; k++) {
357  if (k != i && t1 == pstate->startpos[k]) {
358  delta += distance(ptile2, pconfig->startpos[k]);
359  } else if (k != j && t2 == pstate->startpos[k]) {
360  delta -= distance(ptile2, pconfig->startpos[k]);
361  delta += distance(ptile1, pconfig->startpos[k]);
362  }
363  }
364  } else {
365  delta = 0;
366  base_delta = 0;
367  for (k = 0; k < pconfig->total_startpos_num; k++) {
368  if (k != i && t1 == pstate->startpos[k]) {
369  base_delta -= distance(ptile1, pconfig->startpos[k]);
370  delta += distance(ptile2, pconfig->startpos[k]);
371  } else if (k != j && t2 == pstate->startpos[k]) {
372  delta -= distance(ptile2, pconfig->startpos[k]);
373  delta += distance(ptile1, pconfig->startpos[k]);
374  }
375  }
376  delta += base_delta;
377  base_delta_calculated = true;
378  }
379  } else {
380  continue;
381  }
382 
383  if (delta <= 0) {
384  repeat = true;
385  auto *pnew = new team_placement_state;
386  pnew->startpos = new int[pconfig->total_startpos_num];
387  memcpy(pnew->startpos, pstate->startpos, state_array_size);
388  pnew->startpos[i] = t2;
389  pnew->startpos[j] = t1;
390  pnew->score = pstate->score + delta;
391  team_placement_pq_insert(pqueue, pnew, -pnew->score);
392 
393  if (pnew->score < pbest_state->score) {
394  memcpy(pbest_state->startpos, pnew->startpos, state_array_size);
395  pbest_state->score = pnew->score;
396  }
397  }
398  }
399  }
400 
402  if (iter++ >= iter_max) {
403  qInfo(_("Didn't find optimal solution for team placement "
404  "in %d iterations."),
405  iter);
406  break;
407  }
408  } while (repeat && team_placement_pq_remove(pqueue, &pstate));
409 
410  team_placement_pq_destroy_full(pqueue, team_placement_state_destroy);
411 }
412 
417 {
418  struct startpos_list *impossible_list, *targeted_list, *flexible_list;
419  struct tile *player_startpos[MAX_NUM_PLAYER_SLOTS];
420  int placed_units[MAX_NUM_PLAYER_SLOTS];
421  int players_to_place = player_count();
422  int sulen;
423 
424  randomize_base64url_string(server.game_identifier,
425  sizeof(server.game_identifier));
426 
427  /* Assign players to starting positions on the map.
428  * (In scenarios with restrictions on which nations can use which
429  * predefined start positions, this process tries to satisfy those
430  * restrictions, but does not guarantee to. Even if there is a solution to
431  * the matching problem, this algorithm may not find it.) */
432 
434 
435  /* Convert the startposition hash table in a linked lists, as we mostly
436  * need now to iterate it now. And then, we will be able to remove the
437  * assigned start postions one by one. */
438  impossible_list = startpos_list_new();
439  targeted_list = startpos_list_new();
440  flexible_list = startpos_list_new();
441 
442  for (auto *psp : qAsConst(*wld.map.startpos_table)) {
443  if (psp->exclude) {
444  continue;
445  }
446  if (startpos_allows_all(psp)) {
447  startpos_list_append(flexible_list, psp);
448  } else {
449  startpos_list_append(targeted_list, psp);
450  }
451  }
452 
453  fc_assert(startpos_list_size(targeted_list)
454  + startpos_list_size(flexible_list)
455  == map_startpos_count());
456 
457  memset(player_startpos, 0, sizeof(player_startpos));
458  qDebug("Placing players at start positions.");
459 
460  /* First assign start positions which have restrictions on which nations
461  * can use them. */
462  if (0 < startpos_list_size(targeted_list)) {
463  qDebug("Assigning matching nations.");
464 
465  startpos_list_shuffle(targeted_list); // Randomize.
466  do {
467  struct nation_type *pnation;
468  struct startpos_list_link *choice;
469  bool removed = false;
470 
471  // Assign first players which can pick only one start position.
472  players_iterate(pplayer)
473  {
474  if (nullptr != player_startpos[player_index(pplayer)]) {
475  // Already assigned.
476  continue;
477  }
478 
479  pnation = nation_of_player(pplayer);
480  choice = nullptr;
481  startpos_list_iterate(targeted_list, plink, psp)
482  {
483  if (startpos_nation_allowed(psp, pnation)) {
484  if (nullptr != choice) {
485  choice = nullptr;
486  break; // Many choices.
487  } else {
488  choice = plink;
489  }
490  }
491  }
493 
494  if (nullptr != choice) {
495  /* Assign this start position to this player and remove
496  * both from consideration. */
497  struct tile *ptile =
498  startpos_tile(startpos_list_link_data(choice));
499 
500  player_startpos[player_index(pplayer)] = ptile;
501  startpos_list_erase(targeted_list, choice);
502  players_to_place--;
503  removed = true;
504  qDebug("Start position (%d, %d) exactly matches player %s (%s).",
505  TILE_XY(ptile), player_name(pplayer),
506  nation_rule_name(pnation));
507  }
508  }
510 
511  if (!removed) {
512  /* Didn't find any 1:1 matches. For the next restricted start
513  * position, assign a random matching player. (This may create
514  * restrictions such that more 1:1 matches are possible.) */
515  struct startpos *psp = startpos_list_back(targeted_list);
516  struct tile *ptile = startpos_tile(psp);
517  struct player *rand_plr = nullptr;
518  int i = 0;
519 
520  startpos_list_pop_back(targeted_list); // Detach 'psp'.
521  players_iterate(pplayer)
522  {
523  if (nullptr != player_startpos[player_index(pplayer)]) {
524  // Already assigned.
525  continue;
526  }
527 
528  pnation = nation_of_player(pplayer);
529  if (startpos_nation_allowed(psp, pnation) && 0 == fc_rand(++i)) {
530  rand_plr = pplayer;
531  }
532  }
534 
535  if (nullptr != rand_plr) {
536  player_startpos[player_index(rand_plr)] = ptile;
537  players_to_place--;
538  qDebug("Start position (%d, %d) matches player %s (%s).",
539  TILE_XY(ptile), player_name(rand_plr),
541  } else {
542  /* This start position cannot be assigned, given the assignments
543  * made so far. We may have to fall back to mismatched
544  * assignments. */
545  qDebug("Start position (%d, %d) cannot be assigned for "
546  "any player, keeping for the moment...",
547  TILE_XY(ptile));
548  // Keep it for later, we may need it.
549  startpos_list_append(impossible_list, psp);
550  }
551  }
552  } while (0 < players_to_place && 0 < startpos_list_size(targeted_list));
553  }
554 
555  // Now try to assign with regard to the 'teamplacement' setting.
556  if (players_to_place > 0
557  && wld.map.server.team_placement != TEAM_PLACEMENT_DISABLED
558  && player_count() > team_count()) {
559  const struct player_list *members;
560  int team_placement_players_to_place = 0;
561  int real_team_count = 0;
562 
563  teams_iterate(pteam)
564  {
565  members = team_members(pteam);
566  fc_assert(0 < player_list_size(members));
567  real_team_count++;
568  if (player_list_size(members) == 1) {
569  // Single player teams, doesn't count for team placement.
570  continue;
571  }
572  player_list_iterate(members, pplayer)
573  {
574  if (player_startpos[player_index(pplayer)] == nullptr) {
575  team_placement_players_to_place++;
576  }
577  }
579  }
581 
582  if (real_team_count > 1 && team_placement_players_to_place > 0) {
583  // We really can do something to improve team placement.
584  struct team_placement_config config;
585  struct team_placement_state state;
586  int i, j, t;
587 
588  qDebug("Do team placement for %d players, using %s variant.",
589  team_placement_players_to_place,
590  team_placement_name(wld.map.server.team_placement));
591 
592  // Initialize configuration.
593  config.flexible_startpos_num = startpos_list_size(flexible_list);
595  if (config.flexible_startpos_num < team_placement_players_to_place) {
596  config.usable_startpos_num += startpos_list_size(impossible_list);
597  }
598  config.total_startpos_num =
599  (config.usable_startpos_num + player_count() - players_to_place);
600  config.startpos = new tile *[config.total_startpos_num];
601  i = 0;
602  startpos_list_iterate(flexible_list, plink, psp)
603  {
604  config.startpos[i++] = startpos_tile(psp);
605  }
607  fc_assert(i == config.flexible_startpos_num);
608  if (i < config.usable_startpos_num) {
609  startpos_list_iterate(impossible_list, plink, psp)
610  {
611  config.startpos[i++] = startpos_tile(psp);
612  }
614  }
615  fc_assert(i == config.usable_startpos_num);
616  while (i < config.total_startpos_num) {
617  config.startpos[i++] = nullptr;
618  }
619  fc_assert(i == config.total_startpos_num);
620 
621  // Initialize state.
622  state.startpos = new int[config.total_startpos_num];
623  state.score = 0;
624  i = 0;
625  j = config.usable_startpos_num;
626  teams_iterate(pteam)
627  {
628  members = team_members(pteam);
629  if (player_list_size(members) <= 1) {
630  // Single player teams, doesn't count for team placement.
631  continue;
632  }
633  t = team_number(pteam);
634  player_list_iterate(members, pplayer)
635  {
636  struct tile *ptile = player_startpos[player_index(pplayer)];
637 
638  if (ptile == nullptr) {
639  state.startpos[i++] = t;
640  } else {
641  state.startpos[j] = t;
642  config.startpos[j] = ptile;
643  j++;
644  }
645  }
647  }
649  while (i < config.usable_startpos_num) {
650  state.startpos[i++] = -1;
651  }
652  fc_assert(i == config.usable_startpos_num);
653  while (j < config.total_startpos_num) {
654  state.startpos[j++] = -1;
655  }
656  fc_assert(j == config.total_startpos_num);
657 
658  // Look for best team placement.
659  do_team_placement(&config, &state, team_placement_players_to_place);
660 
661  // Apply result.
662  for (i = 0; i < config.usable_startpos_num; i++) {
663  t = state.startpos[i];
664  if (t != -1) {
665  const struct team *pteam = team_by_number(t);
666  int candidate_index = -1;
667  int candidate_num = 0;
668 
669  qDebug("Start position (%d, %d) assigned to team %d (%s)",
670  TILE_XY(config.startpos[i]), t, team_rule_name(pteam));
671 
672  player_list_iterate(team_members(pteam), member)
673  {
674  if (player_startpos[player_index(member)] == nullptr
675  && fc_rand(++candidate_num) == 0) {
676  candidate_index = player_index(member);
677  }
678  }
680  fc_assert(candidate_index >= 0);
681  player_startpos[candidate_index] = config.startpos[i];
682  team_placement_players_to_place--;
683  players_to_place--;
684  }
685  }
686  fc_assert(team_placement_players_to_place == 0);
687 
688  // Free data.
689  if (players_to_place > 0) {
690  // We need to remove used startpos from the lists.
691  i = 0;
692  startpos_list_iterate(flexible_list, plink, psp)
693  {
694  fc_assert(config.startpos[i] == startpos_tile(psp));
695  if (state.startpos[i] != -1) {
696  startpos_list_erase(flexible_list, plink);
697  }
698  i++;
699  }
701  fc_assert(i == config.flexible_startpos_num);
702  if (i < config.usable_startpos_num) {
703  startpos_list_iterate(impossible_list, plink, psp)
704  {
705  fc_assert(config.startpos[i] == startpos_tile(psp));
706  if (state.startpos[i] != -1) {
707  startpos_list_erase(impossible_list, plink);
708  }
709  i++;
710  }
712  }
713  fc_assert(i == config.usable_startpos_num);
714  }
715 
716  delete[] config.startpos;
717  config.startpos = nullptr;
718  }
719  }
720 
721  // Now assign unrestricted start positions to any remaining players.
722  if (0 < players_to_place && 0 < startpos_list_size(flexible_list)) {
723  struct tile *ptile;
724 
725  qDebug("Assigning unrestricted start positions.");
726 
727  startpos_list_shuffle(flexible_list); // Randomize.
728  players_iterate(pplayer)
729  {
730  if (nullptr != player_startpos[player_index(pplayer)]) {
731  // Already assigned.
732  continue;
733  }
734 
735  ptile = startpos_tile(startpos_list_front(flexible_list));
736  player_startpos[player_index(pplayer)] = ptile;
737  players_to_place--;
738  startpos_list_pop_front(flexible_list);
739  qDebug("Start position (%d, %d) assigned randomly "
740  "to player %s (%s).",
741  TILE_XY(ptile), player_name(pplayer),
743  if (0 == startpos_list_size(flexible_list)) {
744  break;
745  }
746  }
748  }
749 
750  if (0 < players_to_place && 0 < startpos_list_size(impossible_list)) {
751  /* We still have players to place, and we have some restricted start
752  * positions whose nation requirements can't be satisfied given existing
753  * assignments. Fall back to making assignments ignoring the positions'
754  * nation requirements. */
755 
756  struct tile *ptile;
757 
758  qDebug("Ignoring nation restrictions on remaining start positions.");
759 
760  startpos_list_shuffle(impossible_list); // Randomize.
761  players_iterate(pplayer)
762  {
763  if (nullptr != player_startpos[player_index(pplayer)]) {
764  // Already assigned.
765  continue;
766  }
767 
768  ptile = startpos_tile(startpos_list_front(impossible_list));
769  player_startpos[player_index(pplayer)] = ptile;
770  players_to_place--;
771  startpos_list_pop_front(impossible_list);
772  qDebug("Start position (%d, %d) assigned to mismatched "
773  "player %s (%s).",
774  TILE_XY(ptile), player_name(pplayer),
776  if (0 == startpos_list_size(impossible_list)) {
777  break;
778  }
779  }
781  }
782 
783  fc_assert(0 == players_to_place);
784 
785  startpos_list_destroy(impossible_list);
786  startpos_list_destroy(targeted_list);
787  startpos_list_destroy(flexible_list);
788 
789  sulen = qstrlen(game.server.start_units);
790 
791  // Loop over all players, creating their initial units...
792  players_iterate(pplayer)
793  {
794  struct tile *ptile;
795 
796  /* We have to initialise the advisor and ai here as we could make contact
797  * to other nations at this point. */
798  adv_data_phase_init(pplayer, false);
799  CALL_PLR_AI_FUNC(phase_begin, pplayer, pplayer, false);
800 
801  ptile = player_startpos[player_index(pplayer)];
802 
803  fc_assert_action(nullptr != ptile, continue);
804 
805  // Place first city
806  if (game.server.start_city) {
807  create_city(pplayer, ptile, city_name_suggestion(pplayer, ptile),
808  nullptr);
809  }
810 
811  if (sulen > 0) {
812  // Place the first unit.
813  if (place_starting_unit(ptile, pplayer, nullptr,
814  game.server.start_units[0])
815  != nullptr) {
816  placed_units[player_index(pplayer)] = 1;
817  } else {
818  placed_units[player_index(pplayer)] = 0;
819  }
820  } else {
821  placed_units[player_index(pplayer)] = 0;
822  }
823  }
825 
826  // Place all other units.
827  players_iterate(pplayer)
828  {
829  int i;
830  struct tile *const ptile = player_startpos[player_index(pplayer)];
831  struct nation_type *nation = nation_of_player(pplayer);
832 
833  fc_assert_action(nullptr != ptile, continue);
834 
835  // Place global start units
836  for (i = 1; i < sulen; i++) {
837  struct tile *rand_tile = find_dispersed_position(pplayer, ptile);
838 
839  // Create the unit of an appropriate type.
840  if (place_starting_unit(rand_tile, pplayer, nullptr,
841  game.server.start_units[i])
842  != nullptr) {
843  placed_units[player_index(pplayer)]++;
844  }
845  }
846 
847  // Place nation specific start units (not role based!)
848  i = 0;
849  while (i < MAX_NUM_UNIT_LIST && nullptr != nation->init_units[i]) {
850  struct tile *rand_tile = find_dispersed_position(pplayer, ptile);
851 
852  if (place_starting_unit(rand_tile, pplayer, nation->init_units[i],
853  '\0')
854  != nullptr) {
855  placed_units[player_index(pplayer)]++;
856  }
857  i++;
858  }
859  }
861 
862  players_iterate(pplayer)
863  {
864  /* Close the active phase for advisor and ai for all players; it was
865  * opened in the first loop above. */
866  adv_data_phase_done(pplayer);
867  CALL_PLR_AI_FUNC(phase_finished, pplayer, pplayer);
868 
869  fc_assert_msg(game.server.start_city
870  || 0 < placed_units[player_index(pplayer)],
871  _("No units placed for %s!"), player_name(pplayer));
872  }
874 }
875 
881 {
882  struct packet_new_year apacket;
883 
884  players_iterate(pplayer) { pplayer->nturns_idle++; }
886 
887  apacket.year = game.info.year;
888  apacket.fragments = game.info.fragment_count;
889  apacket.turn = game.info.turn;
890  lsend_packet_new_year(game.est_connections, &apacket);
891 
892  // Hmm, clients could add this themselves based on above packet?
893  notify_conn(game.est_connections, nullptr, E_NEXT_YEAR, ftc_any,
894  _("Year: %s"), calendar_text());
895 }
896 
905 void send_game_info(struct conn_list *dest)
906 {
907  struct packet_timeout_info tinfo;
908 
909  if (!dest) {
910  dest = game.est_connections;
911  }
912 
913  tinfo = game.tinfo;
914 
915  /* the following values are computed every
916  time a packet_game_info packet is created */
917 
918  /* Sometimes this function is called before the phase_timer is
919  * initialized. In that case we want to send the dummy value. */
920  if (current_turn_timeout() > 0 && game.server.phase_timer) {
921  /* Whenever the client sees this packet, it starts a new timer at 0;
922  * but the server's timer is only ever reset at the start of a phase
923  * (and game.tinfo.seconds_to_phasedone is relative to this).
924  * Account for the difference. */
925  tinfo.seconds_to_phasedone =
926  game.tinfo.seconds_to_phasedone
927  - timer_read_seconds(game.server.phase_timer)
928  - game.server.additional_phase_seconds;
929  } else {
930  // unused but at least initialized
931  tinfo.seconds_to_phasedone = -1.0;
932  }
933 
934  conn_list_iterate(dest, pconn)
935  {
936  /* Timeout info is separate from other packets since it has to
937  * be sent always (it's not 'is-info') while the others are 'is-info'
938  * Calendar info has been split from Game info packet to make packet
939  * size more tolerable when json protocol is in use. */
940  send_packet_game_info(pconn, &(game.info));
941  send_packet_calendar_info(pconn, &(game.calendar));
942  send_packet_timeout_info(pconn, &tinfo);
943  }
945 }
946 
950 void send_scenario_info(struct conn_list *dest)
951 {
952  if (!dest) {
953  dest = game.est_connections;
954  }
955 
956  conn_list_iterate(dest, pconn)
957  {
958  send_packet_scenario_info(pconn, &(game.scenario));
959  }
961 }
962 
967 void send_scenario_description(struct conn_list *dest)
968 {
969  if (!dest) {
970  dest = game.est_connections;
971  }
972 
973  conn_list_iterate(dest, pconn)
974  {
975  send_packet_scenario_description(pconn, &(game.scenario_desc));
976  }
978 }
979 
990 {
991  // if there's no timer or we're doing autogame, do nothing
992  if (game.info.timeout < 1 || game.server.timeoutint == 0) {
993  return game.info.timeout;
994  }
995 
996  if (game.server.timeoutcounter >= game.server.timeoutint) {
997  game.info.timeout += game.server.timeoutinc;
998  game.server.timeoutinc *= game.server.timeoutincmult;
999 
1000  game.server.timeoutcounter = 1;
1001  game.server.timeoutint += game.server.timeoutintinc;
1002 
1003  if (game.info.timeout > GAME_MAX_TIMEOUT) {
1004  notify_conn(game.est_connections, nullptr, E_SETTING, ftc_server,
1005  _("The turn timeout has exceeded its maximum value, "
1006  "fixing at its maximum."));
1007  log_debug("game.info.timeout exceeded maximum value");
1008  game.info.timeout = GAME_MAX_TIMEOUT;
1009  game.server.timeoutint = 0;
1010  game.server.timeoutinc = 0;
1011  } else if (game.info.timeout < 0) {
1012  notify_conn(game.est_connections, nullptr, E_SETTING, ftc_server,
1013  _("The turn timeout is smaller than zero, "
1014  "fixing at zero."));
1015  log_debug("game.info.timeout less than zero");
1016  game.info.timeout = 0;
1017  }
1018  } else {
1019  game.server.timeoutcounter++;
1020  }
1021 
1022  log_debug("timeout=%d, inc=%d incmult=%d\n "
1023  "int=%d, intinc=%d, turns till next=%d",
1024  game.info.timeout, game.server.timeoutinc,
1025  game.server.timeoutincmult, game.server.timeoutint,
1026  game.server.timeoutintinc,
1027  game.server.timeoutint - game.server.timeoutcounter);
1028 
1029  return game.info.timeout;
1030 }
1031 
1041 {
1042  if (current_turn_timeout() > 0 && game.server.timeoutaddenemymove > 0) {
1043  double maxsec = (timer_read_seconds(game.server.phase_timer)
1044  + static_cast<double>(game.server.timeoutaddenemymove));
1045 
1046  if (maxsec > game.tinfo.seconds_to_phasedone) {
1047  game.tinfo.seconds_to_phasedone = maxsec;
1048  send_game_info(nullptr);
1049  }
1050  }
1051 }
1052 
1056 static void gen_challenge_filename(struct connection *pc) {}
1057 
1061 static const char *get_challenge_filename(struct connection *pc)
1062 {
1063  static char filename[MAX_LEN_PATH];
1064 
1065  fc_snprintf(filename, sizeof(filename), "%s_%d_%d", CHALLENGE_ROOT,
1066  srvarg.port, pc->id);
1067 
1068  return filename;
1069 }
1070 
1074 static const char *get_challenge_fullname(struct connection *pc)
1075 {
1076  static char fullname[MAX_LEN_PATH];
1077  auto sdir = freeciv_storage_dir();
1078  const char *cname;
1079 
1080  if (sdir == nullptr) {
1081  return nullptr;
1082  }
1083 
1084  cname = get_challenge_filename(pc);
1085 
1086  if (cname == nullptr) {
1087  return nullptr;
1088  }
1089 
1090  fc_snprintf(fullname, sizeof(fullname), "%s/%s", qUtf8Printable(sdir),
1091  cname);
1092 
1093  return fullname;
1094 }
1095 
1099 const char *new_challenge_filename(struct connection *pc)
1100 {
1102  return get_challenge_filename(pc);
1103 }
1104 
1110 static void send_ruleset_choices(struct connection *pc)
1111 {
1112  QVector<QString> *ruleset_choices;
1113  struct packet_ruleset_choices packet;
1114  size_t i = 0;
1115 
1116  ruleset_choices = get_init_script_choices();
1117 
1118  for (const auto &s : qAsConst(*ruleset_choices)) {
1119  const int maxlen = sizeof packet.rulesets[i];
1120  if (i >= MAX_NUM_RULESETS) {
1121  qDebug("Can't send more than %d ruleset names to client, "
1122  "skipping some",
1124  break;
1125  }
1126  if (fc_strlcpy(packet.rulesets[i], qUtf8Printable(s), maxlen) < maxlen) {
1127  i++;
1128  } else {
1129  qDebug("Ruleset name '%s' too long to send to client, skipped",
1130  qUtf8Printable(s));
1131  }
1132  }
1133  packet.ruleset_count = i;
1134 
1135  send_packet_ruleset_choices(pc, &packet);
1136 
1137  delete ruleset_choices;
1138 }
1139 
1145  struct connection *pc, const struct packet_single_want_hack_req *packet)
1146 {
1147  struct section_file *secfile;
1148  const char *token = nullptr;
1149  bool you_have_hack = false;
1150 
1151  if ((secfile = secfile_load(get_challenge_fullname(pc), false))) {
1152  token = secfile_lookup_str(secfile, "challenge.token");
1153  you_have_hack = (token && strcmp(token, packet->token) == 0);
1154  secfile_destroy(secfile);
1155  } else {
1156  log_debug("Error reading '%s':\n%s", get_challenge_fullname(pc),
1157  secfile_error());
1158  }
1159 
1160  if (!token) {
1161  log_debug("Failed to read authentication token");
1162  }
1163 
1164  if (you_have_hack) {
1165  conn_set_access(pc, ALLOW_HACK, true);
1166  }
1167 
1168  dsend_packet_single_want_hack_reply(pc, you_have_hack);
1169 
1171  send_conn_info(pc->self, nullptr);
1172 }
bool adv_data_phase_init(struct player *pplayer, bool is_new_phase)
Make and cache lots of calculations needed for other functions.
Definition: advdata.cpp:250
void adv_data_phase_done(struct player *pplayer)
Clean up our mess.
Definition: advdata.cpp:556
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition: ai.h:383
const char * calendar_text()
Produce a statically allocated textual representation of the current calendar time.
Definition: calendar.cpp:137
const char * city_name_suggestion(struct player *pplayer, struct tile *ptile)
Come up with a default name when a new city is about to be built.
Definition: citytools.cpp:451
void create_city(struct player *pplayer, struct tile *ptile, const char *name, struct player *nationality)
Creates real city.
Definition: citytools.cpp:1512
void send_conn_info(struct conn_list *src, struct conn_list *dest)
Send conn_info packets to tell 'dest' connections all about 'src' connections.
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Set the access level of a connection, and re-send some needed info.
Definition: connecthand.cpp:67
#define conn_list_iterate(connlist, pconn)
Definition: connection.h:99
#define conn_list_iterate_end
Definition: connection.h:101
#define extra_type_by_rmcause_iterate_end
Definition: extras.h:330
#define extra_type_by_rmcause_iterate(_rmcause, _extra)
Definition: extras.h:324
#define MAX_NUM_RULESETS
Definition: fc_types.h:327
#define MAX_NUM_PLAYER_SLOTS
Definition: fc_types.h:24
#define _(String)
Definition: fcintl.h:50
const struct ft_color ftc_server
const struct ft_color ftc_any
struct civ_game game
Definition: game.cpp:47
struct world wld
Definition: game.cpp:48
int current_turn_timeout()
Return timeout value for the current turn.
Definition: game.cpp:808
#define GAME_MAX_TIMEOUT
Definition: game.h:569
static void gen_challenge_filename(struct connection *pc)
Generate challenge filename for this connection, cannot fail.
Definition: gamehand.cpp:1056
const char * new_challenge_filename(struct connection *pc)
Find a file that we can write too, and return it's name.
Definition: gamehand.cpp:1099
static const char * get_challenge_fullname(struct connection *pc)
Get challenge full filename for this connection.
Definition: gamehand.cpp:1074
void init_new_game()
Initialize a new game: place the players' units onto the map, etc.
Definition: gamehand.cpp:416
void send_scenario_description(struct conn_list *dest)
Send description of the current scenario.
Definition: gamehand.cpp:967
void send_scenario_info(struct conn_list *dest)
Send current scenario info.
Definition: gamehand.cpp:950
struct unit_type * crole_to_unit_type(char crole, struct player *pplayer)
Get unit_type for given role character.
Definition: gamehand.cpp:108
#define team_placement_closest
Definition: gamehand.cpp:221
static const char * get_challenge_filename(struct connection *pc)
Get challenge filename for this connection.
Definition: gamehand.cpp:1061
static int team_placement_vertical(const struct tile *ptile1, const struct tile *ptile2)
Calculate the distance between tiles, according to the 'teamplacement' setting set to 'VERTICAL'.
Definition: gamehand.cpp:253
void handle_single_want_hack_req(struct connection *pc, const struct packet_single_want_hack_req *packet)
Opens a file specified by the packet and compares the packet values with the file values.
Definition: gamehand.cpp:1144
void send_game_info(struct conn_list *dest)
Send game_info packet; some server options and various stuff...
Definition: gamehand.cpp:905
#define CHALLENGE_ROOT
Definition: gamehand.cpp:47
static void send_ruleset_choices(struct connection *pc)
Call this on a connection with HACK access to send it a set of ruleset choices.
Definition: gamehand.cpp:1110
static struct tile * place_starting_unit(struct tile *starttile, struct player *pplayer, struct unit_type *ptype, char crole)
Place a starting unit for the player.
Definition: gamehand.cpp:136
#define startpos_list_iterate_end
Definition: gamehand.cpp:55
void increase_timeout_because_unit_moved()
adjusts game.seconds_to_turn_done when enemy moves a unit, we see it and the remaining timeout is sma...
Definition: gamehand.cpp:1040
void send_year_to_clients()
Tell clients the year, and also update turn_done and nturns_idle fields for all players.
Definition: gamehand.cpp:880
static void do_team_placement(const struct team_placement_config *pconfig, struct team_placement_state *pbest_state, int iter_max)
Find the best team placement, according to the 'team_placement' setting.
Definition: gamehand.cpp:275
static int team_placement_continent(const struct tile *ptile1, const struct tile *ptile2)
Calculate the distance between tiles, according to the 'teamplacement' setting set to 'CONTINENT'.
Definition: gamehand.cpp:227
#define startpos_list_iterate(list, plink, psp)
Definition: gamehand.cpp:52
enum unit_role_id crole_to_role_id(char crole)
Get role_id for given role character.
Definition: gamehand.cpp:77
static struct tile * find_dispersed_position(struct player *pplayer, struct tile *pcenter)
Find a valid position not far from our starting position.
Definition: gamehand.cpp:199
static void team_placement_state_destroy(struct team_placement_state *pstate)
Destroys a team_placement_state structure.
Definition: gamehand.cpp:266
static int team_placement_horizontal(const struct tile *ptile1, const struct tile *ptile2)
Calculate the distance between tiles, according to the 'teamplacement' setting set to 'HORIZONTAL'.
Definition: gamehand.cpp:239
int update_timeout()
adjusts game.info.timeout based on various server options
Definition: gamehand.cpp:989
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_msg(condition, message,...)
Definition: log.h:129
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define fc_assert_action(condition, action)
Definition: log.h:104
#define log_debug(message,...)
Definition: log.h:65
int sq_map_distance(const struct tile *tile0, const struct tile *tile1)
Return squared distance between two tiles.
Definition: map.cpp:610
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Return the tile for the given cartesian (map) position.
Definition: map.cpp:391
bool startpos_nation_allowed(const struct startpos *psp, const struct nation_type *pnation)
Returns TRUE if the given nation can start here.
Definition: map.cpp:1428
bool startpos_allows_all(const struct startpos *psp)
Returns TRUE if any nation can start here.
Definition: map.cpp:1439
int map_startpos_count()
Is there start positions set for map.
Definition: map.cpp:1518
struct tile * startpos_tile(const struct startpos *psp)
Returns the tile where this start position is located.
Definition: map.cpp:1419
int real_map_distance(const struct tile *tile0, const struct tile *tile1)
Return real distance between two tiles.
Definition: map.cpp:599
void map_distance_vector(int *dx, int *dy, const struct tile *tile0, const struct tile *tile1)
Topology function to find the vector which has the minimum "real" distance between the map positions ...
Definition: map.cpp:1012
#define iterate_outward(nmap, start_tile, max_dist, itr_tile)
Definition: map.h:288
#define iterate_outward_end
Definition: map.h:291
#define MAP_INDEX_SIZE
Definition: map.h:91
#define MAP_IS_ISOMETRIC
Definition: map.h:32
#define index_to_map_pos(pmap_x, pmap_y, mindex)
Definition: map.h:164
void map_show_circle(struct player *pplayer, struct tile *ptile, int radius_sq)
Shows the area to the player.
Definition: maphand.cpp:852
void update_tile_knowledge(struct tile *ptile)
Update playermap knowledge for everybody who sees the tile, and send a packet to everyone whose info ...
Definition: maphand.cpp:1395
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
This tile is native to unit.
Definition: movement.cpp:279
const char * nation_rule_name(const struct nation_type *pnation)
Return the (untranslated) rule name of the nation (adjective form).
Definition: nation.cpp:115
struct nation_type * nation_of_player(const struct player *pplayer)
Return the nation of a player.
Definition: nation.cpp:419
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
See notify_conn_packet - this is just the "non-v" version, with varargs.
Definition: notify.cpp:235
int player_count()
Return the number of players.
Definition: player.cpp:739
int player_index(const struct player *pplayer)
Return the player index.
Definition: player.cpp:748
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
Definition: player.cpp:816
#define players_iterate_end
Definition: player.h:520
#define players_iterate(_pplayer)
Definition: player.h:514
#define player_list_iterate(playerlist, pplayer)
Definition: player.h:541
#define player_list_iterate_end
Definition: player.h:543
#define fc_rand(_size)
Definition: rand.h:16
struct section_file * secfile_load(const QString &filename, bool allow_duplicates)
Create a section file from a file.
Definition: registry.cpp:21
const char * secfile_error()
Returns the last error which occurred in a string.
void secfile_destroy(struct section_file *secfile)
Free a section file.
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Lookup a string value in the secfile.
void randomize_base64url_string(char *s, size_t n)
generate a random string meeting criteria such as is_ascii_name(), is_base64url(),...
Definition: shared.cpp:279
QString freeciv_storage_dir()
Returns string which gives freeciv storage dir.
Definition: shared.cpp:419
#define MAX_LEN_PATH
Definition: shared.h:28
struct server_arguments srvarg
Definition: srv_main.cpp:118
QVector< QString > * get_init_script_choices()
Return a list of init scripts found on the data path.
Definition: stdinhand.cpp:1218
struct civ_game::@28::@32 server
struct packet_scenario_description scenario_desc
Definition: game.h:79
struct conn_list * est_connections
Definition: game.h:88
struct packet_game_info info
Definition: game.h:80
struct packet_scenario_info scenario
Definition: game.h:78
struct packet_timeout_info tinfo
Definition: game.h:82
struct packet_calendar_info calendar
Definition: game.h:81
int xsize
Definition: map_types.h:73
int ysize
Definition: map_types.h:73
QHash< struct tile *, struct startpos * > * startpos_table
Definition: map_types.h:77
struct civ_map::@39::@41 server
struct conn_list * self
Definition: connection.h:150
std::array< unit_type *, MAX_NUM_UNIT_LIST > init_units
Definition: nation.h:105
Definition: player.h:231
Definition: servers.h:55
struct tile ** startpos
Definition: gamehand.cpp:58
Definition: team.cpp:35
Definition: tile.h:42
Continent_id continent
Definition: tile.h:46
struct civ_map map
Definition: world_object.h:21
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
size_t fc_strlcpy(char *dest, const char *src, size_t n)
fc_strlcpy() provides utf-8 version of (non-standard) function strlcpy() It is intended as more user-...
Definition: support.cpp:412
struct team * team_by_number(const int team_id)
Return struct team pointer for the given team index.
Definition: team.cpp:373
const char * team_rule_name(const struct team *pteam)
Returns the name (untranslated) of the team.
Definition: team.cpp:383
int team_count()
Return the current number of teams.
Definition: team.cpp:354
int team_number(const struct team *pteam)
Return the team index/number/id.
Definition: team.cpp:364
const struct player_list * team_members(const struct team *pteam)
Returns the member list of the team.
Definition: team.cpp:427
#define teams_iterate_end
Definition: team.h:76
#define teams_iterate(_pteam)
Definition: team.h:71
#define is_ocean_tile(ptile)
Definition: terrain.h:279
bool tile_extra_rm_apply(struct tile *ptile, struct extra_type *tgt)
Remove extra and adjust other extras accordingly.
Definition: tile.cpp:605
#define tile_index(_pt_)
Definition: tile.h:70
#define TILE_XY(ptile)
Definition: tile.h:36
#define tile_continent(_tile)
Definition: tile.h:74
#define tile_has_extra(ptile, pextra)
Definition: tile.h:130
double timer_read_seconds(civtimer *t)
Read value from timer.
Definition: timing.cpp:137
struct unit * is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Is there an non-allied unit on this tile?
Definition: unit.cpp:1252
struct unit * create_unit(struct player *pplayer, struct tile *ptile, const struct unit_type *type, int veteran_level, int homecity_id, int moves_left)
Wrapper of the below.
Definition: unittools.cpp:1762
int num_role_units(int role)
How many unit types have specified role/flag.
Definition: unittype.cpp:1866
struct unit_type * get_role_unit(int role, int role_index)
Return index-th unit with specified role/flag.
Definition: unittype.cpp:1900
struct unit_type * first_role_unit_for_player(const struct player *pplayer, int role)
Return first unit the player can build, with given role/flag.
Definition: unittype.cpp:1976