1 /**********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdio.h> /* for remove() */
19 
20 /* utility */
21 #include "capability.h"
22 #include "fcintl.h"
23 #include "log.h"
24 #include "mem.h"
25 #include "rand.h"
26 #include "registry.h"
27 #include "shared.h"
28 #include "string_vector.h"
29 #include "support.h"
30 
31 /* common */
32 #include "ai.h"
33 #include "calendar.h"
34 #include "events.h"
35 #include "game.h"
36 #include "improvement.h"
37 #include "movement.h"
38 #include "packets.h"
39 
40 /* server */
41 #include "citytools.h"
42 #include "connecthand.h"
43 #include "maphand.h"
44 #include "notify.h"
45 #include "plrhand.h"
46 #include "srv_main.h"
47 #include "stdinhand.h"
48 #include "unittools.h"
49 
50 /* server/advisors */
51 #include "advdata.h"
52 
53 #include "gamehand.h"
54 
55 #define CHALLENGE_ROOT "challenge"
56 
57 #define SPECLIST_TAG startpos
58 #define SPECLIST_TYPE struct startpos
59 #include "speclist.h"
60 #define startpos_list_iterate(list, plink, psp)                             \
61   TYPED_LIST_BOTH_ITERATE(struct startpos_list_link, struct startpos,       \
62                           list, plink, psp)
63 #define startpos_list_iterate_end LIST_BOTH_ITERATE_END
64 
65 struct team_placement_config {
66   struct tile **startpos;
67   int flexible_startpos_num;
68   int usable_startpos_num;
69   int total_startpos_num;
70 };
71 
72 struct team_placement_state {
73   int *startpos;
74   long score;
75 };
76 
77 #define SPECPQ_TAG team_placement
78 #define SPECPQ_DATA_TYPE struct team_placement_state *
79 #define SPECPQ_PRIORITY_TYPE long
80 #include "specpq.h"
81 
82 /****************************************************************************
83   Get role_id for given role character
84 ****************************************************************************/
crole_to_role_id(char crole)85 enum unit_role_id crole_to_role_id(char crole)
86 {
87   switch (crole) {
88   case 'c':
89     return L_START_CITIES;
90   case 'w':
91     return L_START_WORKER;
92   case 'x':
93     return L_START_EXPLORER;
94   case 'k':
95     return L_START_KING;
96   case 's':
97     return L_START_DIPLOMAT;
98   case 'f':
99     return L_START_FERRY;
100   case 'd':
101     return L_START_DEFEND_OK;
102   case 'D':
103     return L_START_DEFEND_GOOD;
104   case 'a':
105     return L_START_ATTACK_FAST;
106   case 'A':
107     return L_START_ATTACK_STRONG;
108   default:
109     return 0;
110   }
111 }
112 
113 /****************************************************************************
114   Get unit_type for given role character
115 ****************************************************************************/
crole_to_unit_type(char crole,struct player * pplayer)116 struct unit_type *crole_to_unit_type(char crole, struct player *pplayer)
117 {
118   struct unit_type *utype = NULL;
119   enum unit_role_id role = crole_to_role_id(crole);
120 
121   if (role == 0) {
122     fc_assert_ret_val(FALSE, NULL);
123     return NULL;
124   }
125 
126   /* Create the unit of an appropriate type, if it exists */
127   if (num_role_units(role) > 0) {
128     if (pplayer != NULL) {
129       utype = first_role_unit_for_player(pplayer, role);
130     }
131     if (utype == NULL) {
132       utype = get_role_unit(role, 0);
133     }
134   }
135 
136   return utype;
137 }
138 
139 /****************************************************************************
140   Place a starting unit for the player. Returns tile where unit was really
141   placed. By default the ptype is used and crole does not matter, but if
142   former is NULL, crole will be used instead.
143 ****************************************************************************/
place_starting_unit(struct tile * starttile,struct player * pplayer,struct unit_type * ptype,char crole)144 static struct tile *place_starting_unit(struct tile *starttile,
145                                         struct player *pplayer,
146                                         struct unit_type *ptype, char crole)
147 {
148   struct tile *ptile = NULL;
149   struct unit_type *utype;
150   bool hut_present = FALSE;
151 
152   if (ptype != NULL) {
153     utype = ptype;
154   } else {
155     utype = crole_to_unit_type(crole, pplayer);
156   }
157 
158   if (utype != NULL) {
159     iterate_outward(starttile, game.map.xsize + game.map.ysize, itertile) {
160       if (!is_non_allied_unit_tile(itertile, pplayer)
161           && is_native_tile(utype, itertile)) {
162         ptile = itertile;
163         break;
164       }
165     } iterate_outward_end;
166   }
167 
168   if (ptile == NULL) {
169     /* No place where unit may exist. */
170     return NULL;
171   }
172 
173   fc_assert_ret_val(!is_non_allied_unit_tile(ptile, pplayer), NULL);
174 
175   /* For scenarios or dispersion, huts may coincide with player starts (in
176    * other cases, huts are avoided as start positions).  Remove any such hut,
177    * and make sure to tell the client, since we may have already sent this
178    * tile (with the hut) earlier: */
179   extra_type_by_cause_iterate(EC_HUT, pextra) {
180     if (tile_has_extra(ptile, pextra)) {
181       tile_extra_rm_apply(ptile, pextra);
182       hut_present = TRUE;
183     }
184   } extra_type_by_cause_iterate_end;
185 
186   if (hut_present) {
187     update_tile_knowledge(ptile);
188     log_verbose("Removed hut on start position for %s",
189                 player_name(pplayer));
190   }
191 
192   /* Expose visible area. */
193   map_show_circle(pplayer, ptile, game.server.init_vis_radius_sq);
194 
195   if (utype != NULL) {
196     (void) create_unit(pplayer, ptile, utype, FALSE, 0, 0);
197     return ptile;
198   }
199 
200   return NULL;
201 }
202 
203 /****************************************************************************
204   Find a valid position not far from our starting position.
205 ****************************************************************************/
find_dispersed_position(struct player * pplayer,struct tile * pcenter)206 static struct tile *find_dispersed_position(struct player *pplayer,
207                                             struct tile *pcenter)
208 {
209   struct tile *ptile;
210   int x, y;
211   int bailout;
212 
213   if (game.server.dispersion == 0) {
214     bailout = 1; /* One attempt is guaranteed to cover single tile */
215   } else {
216     bailout = game.server.dispersion * 2 + 1; /* Side of the area */
217     bailout *= bailout;                       /* Area */
218     bailout *= 5;                             /* Likely to hit each tile at least once */
219   }
220 
221   do {
222     if (!bailout--) {
223       return NULL;
224     }
225     index_to_map_pos(&x, &y, tile_index(pcenter));
226     x += fc_rand(2 * game.server.dispersion + 1) - game.server.dispersion;
227     y += fc_rand(2 * game.server.dispersion + 1) - game.server.dispersion;
228   } while (!((ptile = map_pos_to_tile(x, y))
229              && tile_continent(pcenter) == tile_continent(ptile)
230              && !is_ocean_tile(ptile)
231              && real_map_distance(pcenter, ptile) < game.server.dispersion
232                 + 1
233              && !is_non_allied_unit_tile(ptile, pplayer)));
234 
235   return ptile;
236 }
237 
238 /* Calculate the distance between tiles, according to the 'teamplacement'
239  * setting set to 'CLOSEST'. */
240 #define team_placement_closest sq_map_distance
241 
242 /****************************************************************************
243   Calculate the distance between tiles, according to the 'teamplacement'
244   setting set to 'CONTINENT'.
245 ****************************************************************************/
team_placement_continent(const struct tile * ptile1,const struct tile * ptile2)246 static int team_placement_continent(const struct tile *ptile1,
247                                     const struct tile *ptile2)
248 {
249   return (ptile1->continent == ptile2->continent
250           ? sq_map_distance(ptile1, ptile2)
251           : sq_map_distance(ptile1, ptile2) + MAP_INDEX_SIZE);
252 }
253 
254 /****************************************************************************
255   Calculate the distance between tiles, according to the 'teamplacement'
256   setting set to 'HORIZONTAL'.
257 ****************************************************************************/
team_placement_horizontal(const struct tile * ptile1,const struct tile * ptile2)258 static int team_placement_horizontal(const struct tile *ptile1,
259                                      const struct tile *ptile2)
260 {
261   int dx, dy;
262 
263   map_distance_vector(&dx, &dy, ptile1, ptile2);
264   /* Map vector to natural vector (Y axis). */
265   return abs(MAP_IS_ISOMETRIC ? dx + dy : dy);
266 }
267 
268 /****************************************************************************
269   Calculate the distance between tiles, according to the 'teamplacement'
270   setting set to 'VERTICAL'.
271 ****************************************************************************/
team_placement_vertical(const struct tile * ptile1,const struct tile * ptile2)272 static int team_placement_vertical(const struct tile *ptile1,
273                                    const struct tile *ptile2)
274 {
275   int dx, dy;
276 
277   map_distance_vector(&dx, &dy, ptile1, ptile2);
278   /* Map vector to natural vector (X axis). */
279   return abs(MAP_IS_ISOMETRIC ? dx - dy : dy);
280 }
281 
282 /****************************************************************************
283   Destroys a team_placement_state structure.
284 ****************************************************************************/
team_placement_state_destroy(struct team_placement_state * pstate)285 static void team_placement_state_destroy(struct team_placement_state *pstate)
286 {
287   free(pstate->startpos);
288   free(pstate);
289 }
290 
291 /****************************************************************************
292   Find the best team placement, according to the 'team_placement' setting.
293 ****************************************************************************/
do_team_placement(const struct team_placement_config * pconfig,struct team_placement_state * pbest_state,int iter_max)294 static void do_team_placement(const struct team_placement_config *pconfig,
295                               struct team_placement_state *pbest_state,
296                               int iter_max)
297 {
298   const size_t state_array_size = (sizeof(*pbest_state->startpos)
299                                    * pconfig->total_startpos_num);
300   struct team_placement_pq *pqueue =
301       team_placement_pq_new(pconfig->total_startpos_num * 4);
302   int (*distance)(const struct tile *, const struct tile *) = NULL;
303   struct team_placement_state *pstate, *pnew;
304   const struct tile *ptile1, *ptile2;
305   long base_delta, delta;
306   bool base_delta_calculated;
307   int iter = 0;
308   bool repeat;
309   int i, j, k, t1, t2;
310 
311   switch (game.map.server.team_placement) {
312   case TEAM_PLACEMENT_CLOSEST:
313     distance = team_placement_closest;
314     break;
315   case TEAM_PLACEMENT_CONTINENT:
316     distance = team_placement_continent;
317     break;
318   case TEAM_PLACEMENT_HORIZONTAL:
319     distance = team_placement_horizontal;
320     break;
321   case TEAM_PLACEMENT_VERTICAL:
322     distance = team_placement_vertical;
323     break;
324   case TEAM_PLACEMENT_DISABLED:
325     break;
326   }
327   fc_assert_ret_msg(distance != NULL, "Wrong team_placement variant (%d)",
328                     game.map.server.team_placement);
329 
330   /* Initialize starting state. */
331   pstate = fc_malloc(sizeof(*pstate));
332   pstate->startpos = fc_malloc(state_array_size);
333   memcpy(pstate->startpos, pbest_state->startpos, state_array_size);
334   pstate->score = pbest_state->score;
335 
336   do {
337     repeat = FALSE;
338     for (i = 0; i < pconfig->usable_startpos_num; i++) {
339       t1 = pstate->startpos[i];
340       if (t1 == -1) {
341         continue; /* Not used. */
342       }
343       ptile1 = pconfig->startpos[i];
344       base_delta_calculated = FALSE;
345       for (j = i + 1; j < (i >= pconfig->flexible_startpos_num
346                            ? pconfig->usable_startpos_num
347                            : pconfig->flexible_startpos_num); j++) {
348         t2 = pstate->startpos[j];
349         if (t2 == -1) {
350           /* Not assigned yet. */
351           ptile2 = pconfig->startpos[j];
352           if (base_delta_calculated) {
353             delta = base_delta;
354             for (k = 0; k < pconfig->total_startpos_num; k++) {
355               if (k != i && t1 == pstate->startpos[k]) {
356                 delta += distance(ptile2, pconfig->startpos[k]);
357               }
358             }
359           } else {
360             delta = 0;
361             base_delta = 0;
362             for (k = 0; k < pconfig->total_startpos_num; k++) {
363               if (k != i && t1 == pstate->startpos[k]) {
364                 base_delta -= distance(ptile1, pconfig->startpos[k]);
365                 delta += distance(ptile2, pconfig->startpos[k]);
366               }
367             }
368             delta += base_delta;
369             base_delta_calculated = TRUE;
370           }
371         } else if (t1 < t2) {
372           ptile2 = pconfig->startpos[j];
373           if (base_delta_calculated) {
374             delta = base_delta;
375             for (k = 0; k < pconfig->total_startpos_num; k++) {
376               if (k != i && t1 == pstate->startpos[k]) {
377                 delta += distance(ptile2, pconfig->startpos[k]);
378               } else if (k != j && t2 == pstate->startpos[k]) {
379                 delta -= distance(ptile2, pconfig->startpos[k]);
380                 delta += distance(ptile1, pconfig->startpos[k]);
381               }
382             }
383           } else {
384             delta = 0;
385             base_delta = 0;
386             for (k = 0; k < pconfig->total_startpos_num; k++) {
387               if (k != i && t1 == pstate->startpos[k]) {
388                 base_delta -= distance(ptile1, pconfig->startpos[k]);
389                 delta += distance(ptile2, pconfig->startpos[k]);
390               } else if (k != j && t2 == pstate->startpos[k]) {
391                 delta -= distance(ptile2, pconfig->startpos[k]);
392                 delta += distance(ptile1, pconfig->startpos[k]);
393               }
394             }
395             delta += base_delta;
396             base_delta_calculated = TRUE;
397           }
398         } else {
399           continue;
400         }
401 
402         if (delta <= 0) {
403           repeat = TRUE;
404           pnew = fc_malloc(sizeof(*pnew));
405           pnew->startpos = fc_malloc(state_array_size);
406           memcpy(pnew->startpos, pstate->startpos, state_array_size);
407           pnew->startpos[i] = t2;
408           pnew->startpos[j] = t1;
409           pnew->score = pstate->score + delta;
410           team_placement_pq_insert(pqueue, pnew, -pnew->score);
411 
412           if (pnew->score < pbest_state->score) {
413             memcpy(pbest_state->startpos, pnew->startpos, state_array_size);
414             pbest_state->score = pnew->score;
415           }
416         }
417       }
418     }
419 
420     team_placement_state_destroy(pstate);
421     if (iter++ >= iter_max) {
422       log_normal(_("Didn't find optimal solution for team placement "
423                    "in %d iterations."), iter);
424       break;
425     }
426 
427   } while (repeat && team_placement_pq_remove(pqueue, &pstate));
428 
429   team_placement_pq_destroy_full(pqueue, team_placement_state_destroy);
430 }
431 
432 /****************************************************************************
433   Initialize a new game: place the players' units onto the map, etc.
434 ****************************************************************************/
init_new_game(void)435 void init_new_game(void)
436 {
437   struct startpos_list *impossible_list, *targeted_list, *flexible_list;
438   struct tile *player_startpos[player_slot_count()];
439   int placed_units[player_slot_count()];
440   int players_to_place = player_count();
441   int sulen;
442 
443   randomize_base64url_string(server.game_identifier,
444                              sizeof(server.game_identifier));
445 
446   /* Assign players to starting positions on the map.
447    * (In scenarios with restrictions on which nations can use which predefined
448    * start positions, this process tries to satisfy those restrictions, but
449    * does not guarantee to. Even if there is a solution to the matching
450    * problem, this algorithm may not find it.) */
451 
452   fc_assert(player_count() <= map_startpos_count());
453 
454   /* Convert the startposition hash table in a linked lists, as we mostly
455    * need now to iterate it now. And then, we will be able to remove the
456    * assigned start postions one by one. */
457   impossible_list = startpos_list_new();
458   targeted_list = startpos_list_new();
459   flexible_list = startpos_list_new();
460 
461   map_startpos_iterate(psp) {
462     if (startpos_allows_all(psp)) {
463       startpos_list_append(flexible_list, psp);
464     } else {
465       startpos_list_append(targeted_list, psp);
466     }
467   } map_startpos_iterate_end;
468 
469   fc_assert(startpos_list_size(targeted_list)
470             + startpos_list_size(flexible_list) == map_startpos_count());
471 
472   memset(player_startpos, 0, sizeof(player_startpos));
473   log_verbose("Placing players at start positions.");
474 
475   /* First assign start positions which have restrictions on which nations
476    * can use them. */
477   if (0 < startpos_list_size(targeted_list)) {
478     log_verbose("Assigning matching nations.");
479 
480     startpos_list_shuffle(targeted_list); /* Randomize. */
481     do {
482       struct nation_type *pnation;
483       struct startpos_list_link *choice;
484       bool removed = FALSE;
485 
486       /* Assign first players which can pick only one start position. */
487       players_iterate(pplayer) {
488         if (NULL != player_startpos[player_index(pplayer)]) {
489           /* Already assigned. */
490           continue;
491         }
492 
493         pnation = nation_of_player(pplayer);
494         choice = NULL;
495         startpos_list_iterate(targeted_list, plink, psp) {
496           if (startpos_nation_allowed(psp, pnation)) {
497             if (NULL != choice) {
498               choice = NULL;
499               break; /* Many choices. */
500             } else {
501               choice = plink;
502             }
503           }
504         } startpos_list_iterate_end;
505 
506         if (NULL != choice) {
507           /* Assign this start position to this player and remove
508            * both from consideration. */
509           struct tile *ptile =
510               startpos_tile(startpos_list_link_data(choice));
511 
512           player_startpos[player_index(pplayer)] = ptile;
513           startpos_list_erase(targeted_list, choice);
514           players_to_place--;
515           removed = TRUE;
516           log_verbose("Start position (%d, %d) exactly matches player %s (%s).",
517                       TILE_XY(ptile), player_name(pplayer),
518                       nation_rule_name(pnation));
519         }
520       } players_iterate_end;
521 
522       if (!removed) {
523         /* Didn't find any 1:1 matches. For the next restricted start
524          * position, assign a random matching player. (This may create
525          * restrictions such that more 1:1 matches are possible.) */
526         struct startpos *psp = startpos_list_back(targeted_list);
527         struct tile *ptile = startpos_tile(psp);
528         struct player *rand_plr = NULL;
529         int i = 0;
530 
531         startpos_list_pop_back(targeted_list); /* Detach 'psp'. */
532         players_iterate(pplayer) {
533           if (NULL != player_startpos[player_index(pplayer)]) {
534             /* Already assigned. */
535             continue;
536           }
537 
538           pnation = nation_of_player(pplayer);
539           if (startpos_nation_allowed(psp, pnation) && 0 == fc_rand(++i)) {
540             rand_plr = pplayer;
541           }
542         } players_iterate_end;
543 
544         if (NULL != rand_plr) {
545           player_startpos[player_index(rand_plr)] = ptile;
546           players_to_place--;
547           log_verbose("Start position (%d, %d) matches player %s (%s).",
548                       TILE_XY(ptile), player_name(rand_plr),
549                       nation_rule_name(nation_of_player(rand_plr)));
550         } else {
551           /* This start position cannot be assigned, given the assignments
552            * made so far. We may have to fall back to mismatched
553            * assignments. */
554           log_verbose("Start position (%d, %d) cannot be assigned for "
555                       "any player, keeping for the moment...",
556                       TILE_XY(ptile));
557           /* Keep it for later, we may need it. */
558           startpos_list_append(impossible_list, psp);
559         }
560       }
561     } while (0 < players_to_place && 0 < startpos_list_size(targeted_list));
562   }
563 
564   /* Now try to assign with regard to the 'teamplacement' setting. */
565   if (players_to_place > 0
566       && game.map.server.team_placement != TEAM_PLACEMENT_DISABLED
567       && player_count() > team_count()) {
568     const struct player_list *members;
569     int team_placement_players_to_place = 0;
570     int real_team_count = 0;
571 
572     teams_iterate(pteam) {
573       members = team_members(pteam);
574       fc_assert(0 < player_list_size(members));
575       real_team_count++;
576       if (player_list_size(members) == 1) {
577         /* Single player teams, doesn't count for team placement. */
578         continue;
579       }
580       player_list_iterate(members, pplayer) {
581         if (player_startpos[player_index(pplayer)] == NULL) {
582           team_placement_players_to_place++;
583         }
584       } player_list_iterate_end;
585     } teams_iterate_end;
586 
587     if (real_team_count > 1 && team_placement_players_to_place > 0) {
588       /* We really can do something to improve team placement. */
589       struct team_placement_config config;
590       struct team_placement_state state;
591       int i, j, t;
592 
593       log_verbose("Do team placement for %d players, using %s variant.",
594                   team_placement_players_to_place,
595                   team_placement_name(game.map.server.team_placement));
596 
597       /* Initialize configuration. */
598       config.flexible_startpos_num = startpos_list_size(flexible_list);
599       config.usable_startpos_num = config.flexible_startpos_num;
600       if (config.flexible_startpos_num < team_placement_players_to_place) {
601         config.usable_startpos_num += startpos_list_size(impossible_list);
602       }
603       config.total_startpos_num = (config.usable_startpos_num
604                                    + player_count() - players_to_place);
605       config.startpos = fc_malloc(sizeof(*config.startpos)
606                                   * config.total_startpos_num);
607       i = 0;
608       startpos_list_iterate(flexible_list, plink, psp) {
609         config.startpos[i++] = startpos_tile(psp);
610       } startpos_list_iterate_end;
611       fc_assert(i == config.flexible_startpos_num);
612       if (i < config.usable_startpos_num) {
613         startpos_list_iterate(impossible_list, plink, psp) {
614           config.startpos[i++] = startpos_tile(psp);
615         } startpos_list_iterate_end;
616       }
617       fc_assert(i == config.usable_startpos_num);
618       while (i < config.total_startpos_num) {
619         config.startpos[i++] = NULL;
620       }
621       fc_assert(i == config.total_startpos_num);
622 
623       /* Initialize state. */
624       state.startpos = fc_malloc(sizeof(*state.startpos)
625                                  * config.total_startpos_num);
626       state.score = 0;
627       i = 0;
628       j = config.usable_startpos_num;
629       teams_iterate(pteam) {
630         members = team_members(pteam);
631         if (player_list_size(members) <= 1) {
632           /* Single player teams, doesn't count for team placement. */
633           continue;
634         }
635         t = team_number(pteam);
636         player_list_iterate(members, pplayer) {
637           struct tile *ptile = player_startpos[player_index(pplayer)];
638 
639           if (ptile == NULL) {
640             state.startpos[i++] = t;
641           } else {
642             state.startpos[j] = t;
643             config.startpos[j] = ptile;
644             j++;
645           }
646         } player_list_iterate_end;
647       } teams_iterate_end;
648       while (i < config.usable_startpos_num) {
649         state.startpos[i++] = -1;
650       }
651       fc_assert(i == config.usable_startpos_num);
652       while (j < config.total_startpos_num) {
653         state.startpos[j++] = -1;
654       }
655       fc_assert(j == config.total_startpos_num);
656 
657       /* Look for best team placement. */
658       do_team_placement(&config, &state, team_placement_players_to_place);
659 
660       /* Apply result. */
661       for (i = 0; i < config.usable_startpos_num; i++) {
662         t = state.startpos[i];
663         if (t != -1) {
664           const struct team *pteam = team_by_number(t);
665           int candidate_index = -1;
666           int candidate_num = 0;
667 
668           log_verbose("Start position (%d, %d) assigned to team %d (%s)",
669                       TILE_XY(config.startpos[i]),
670                       t, team_rule_name(pteam));
671 
672           player_list_iterate(team_members(pteam), member) {
673             if (player_startpos[player_index(member)] == NULL
674                 && fc_rand(++candidate_num) == 0) {
675               candidate_index = player_index(member);
676             }
677           } player_list_iterate_end;
678           fc_assert(candidate_index >= 0);
679           player_startpos[candidate_index] = config.startpos[i];
680           team_placement_players_to_place--;
681           players_to_place--;
682         }
683       }
684       fc_assert(team_placement_players_to_place == 0);
685 
686       /* Free data. */
687       if (players_to_place > 0) {
688         /* We need to remove used startpos from the lists. */
689         i = 0;
690         startpos_list_iterate(flexible_list, plink, psp) {
691           fc_assert(config.startpos[i] == startpos_tile(psp));
692           if (state.startpos[i] != -1) {
693             startpos_list_erase(flexible_list, plink);
694           }
695           i++;
696         } startpos_list_iterate_end;
697         fc_assert(i == config.flexible_startpos_num);
698         if (i < config.usable_startpos_num) {
699           startpos_list_iterate(impossible_list, plink, psp) {
700             fc_assert(config.startpos[i] == startpos_tile(psp));
701             if (state.startpos[i] != -1) {
702               startpos_list_erase(impossible_list, plink);
703             }
704             i++;
705           } startpos_list_iterate_end;
706         }
707         fc_assert(i == config.usable_startpos_num);
708       }
709 
710       free(config.startpos);
711     }
712   }
713 
714   /* Now assign unrestricted start positions to any remaining players. */
715   if (0 < players_to_place && 0 < startpos_list_size(flexible_list)) {
716     struct tile *ptile;
717 
718     log_verbose("Assigning unrestricted start positions.");
719 
720     startpos_list_shuffle(flexible_list); /* Randomize. */
721     players_iterate(pplayer) {
722       if (NULL != player_startpos[player_index(pplayer)]) {
723         /* Already assigned. */
724         continue;
725       }
726 
727       ptile = startpos_tile(startpos_list_front(flexible_list));
728       player_startpos[player_index(pplayer)] = ptile;
729       players_to_place--;
730       startpos_list_pop_front(flexible_list);
731       log_verbose("Start position (%d, %d) assigned randomly "
732                   "to player %s (%s).", TILE_XY(ptile), player_name(pplayer),
733                   nation_rule_name(nation_of_player(pplayer)));
734       if (0 == startpos_list_size(flexible_list)) {
735         break;
736       }
737     } players_iterate_end;
738   }
739 
740   if (0 < players_to_place && 0 < startpos_list_size(impossible_list)) {
741     /* We still have players to place, and we have some restricted start
742      * positions whose nation requirements can't be satisfied given existing
743      * assignments. Fall back to making assignments ignoring the positions'
744      * nation requirements. */
745 
746     struct tile *ptile;
747 
748     log_verbose("Ignoring nation restrictions on remaining start positions.");
749 
750     startpos_list_shuffle(impossible_list); /* Randomize. */
751     players_iterate(pplayer) {
752       if (NULL != player_startpos[player_index(pplayer)]) {
753         /* Already assigned. */
754         continue;
755       }
756 
757       ptile = startpos_tile(startpos_list_front(impossible_list));
758       player_startpos[player_index(pplayer)] = ptile;
759       players_to_place--;
760       startpos_list_pop_front(impossible_list);
761       log_verbose("Start position (%d, %d) assigned to mismatched "
762                   "player %s (%s).", TILE_XY(ptile), player_name(pplayer),
763                   nation_rule_name(nation_of_player(pplayer)));
764       if (0 == startpos_list_size(impossible_list)) {
765         break;
766       }
767     } players_iterate_end;
768   }
769 
770   fc_assert(0 == players_to_place);
771 
772   startpos_list_destroy(impossible_list);
773   startpos_list_destroy(targeted_list);
774   startpos_list_destroy(flexible_list);
775 
776   sulen = strlen(game.server.start_units);
777 
778   /* Loop over all players, creating their initial units... */
779   shuffled_players_iterate(pplayer) {
780     struct tile *ptile;
781 
782     /* We have to initialise the advisor and ai here as we could make contact
783      * to other nations at this point. */
784     adv_data_phase_init(pplayer, FALSE);
785     CALL_PLR_AI_FUNC(phase_begin, pplayer, pplayer, FALSE);
786 
787     ptile = player_startpos[player_index(pplayer)];
788 
789     fc_assert_action(NULL != ptile, continue);
790 
791     /* Place first city */
792     if (game.server.start_city) {
793       create_city(pplayer, ptile, city_name_suggestion(pplayer, ptile),
794                   NULL);
795     }
796 
797     if (sulen > 0) {
798       /* Place the first unit. */
799       if (place_starting_unit(ptile, pplayer, NULL,
800                               game.server.start_units[0]) != NULL) {
801         placed_units[player_index(pplayer)] = 1;
802       } else {
803         placed_units[player_index(pplayer)] = 0;
804       }
805     } else {
806       placed_units[player_index(pplayer)] = 0;
807     }
808   } shuffled_players_iterate_end;
809 
810   /* Place all other units. */
811   shuffled_players_iterate(pplayer) {
812     int i;
813     struct tile *const ptile = player_startpos[player_index(pplayer)];
814     struct nation_type *nation = nation_of_player(pplayer);
815 
816     fc_assert_action(NULL != ptile, continue);
817 
818     /* Place global start units */
819     for (i = 1; i < sulen; i++) {
820       struct tile *rand_tile = find_dispersed_position(pplayer, ptile);
821 
822       /* Create the unit of an appropriate type. */
823       if (rand_tile != NULL
824           && place_starting_unit(rand_tile, pplayer, NULL,
825                                  game.server.start_units[i]) != NULL) {
826         placed_units[player_index(pplayer)]++;
827       }
828     }
829 
830     /* Place nation specific start units (not role based!) */
831     i = 0;
832     while (NULL != nation->init_units[i] && MAX_NUM_UNIT_LIST > i) {
833       struct tile *rand_tile = find_dispersed_position(pplayer, ptile);
834 
835       if (rand_tile != NULL
836           && place_starting_unit(rand_tile, pplayer,
837                                  nation->init_units[i], '\0') != NULL) {
838         placed_units[player_index(pplayer)]++;
839       }
840       i++;
841     }
842   } shuffled_players_iterate_end;
843 
844   players_iterate(pplayer) {
845     /* Close the active phase for advisor and ai for all players; it was
846      * opened in the first loop above. */
847     adv_data_phase_done(pplayer);
848     CALL_PLR_AI_FUNC(phase_finished, pplayer, pplayer);
849 
850     fc_assert_msg(game.server.start_city || 0 < placed_units[player_index(pplayer)],
851                   _("No units placed for %s!"), player_name(pplayer));
852   } players_iterate_end;
853 }
854 
855 /**************************************************************************
856   Tell clients the year, and also update turn_done and nturns_idle fields
857   for all players.
858 **************************************************************************/
send_year_to_clients(void)859 void send_year_to_clients(void)
860 {
861   struct packet_new_year apacket;
862 
863   players_iterate(pplayer) {
864     pplayer->nturns_idle++;
865   } players_iterate_end;
866 
867   apacket.year32 = game.info.year32;
868   apacket.year16 = game.info.year32;
869   apacket.fragments = game.info.fragment_count;
870   apacket.turn = game.info.turn;
871   lsend_packet_new_year(game.est_connections, &apacket);
872 
873   /* Hmm, clients could add this themselves based on above packet? */
874   notify_conn(game.est_connections, NULL, E_NEXT_YEAR, ftc_any,
875               _("Year: %s"), calendar_text());
876 }
877 
878 /**************************************************************************
879   Send game_info packet; some server options and various stuff...
880   dest==NULL means game.est_connections
881 
882   It may be sent at any time. It MUST be sent before any player info,
883   as it contains the number of players.  To avoid inconsistency, it
884   SHOULD be sent after rulesets and any other server settings.
885 **************************************************************************/
send_game_info(struct conn_list * dest)886 void send_game_info(struct conn_list *dest)
887 {
888   struct packet_timeout_info tinfo;
889 
890   if (!dest) {
891     dest = game.est_connections;
892   }
893 
894   tinfo = game.tinfo;
895 
896   /* the following values are computed every
897      time a packet_game_info packet is created */
898 
899   /* Sometimes this function is called before the phase_timer is
900    * initialized.  In that case we want to send the dummy value. */
901   if (current_turn_timeout() > 0 && game.server.phase_timer) {
902     /* Whenever the client sees this packet, it starts a new timer at 0;
903      * but the server's timer is only ever reset at the start of a phase
904      * (and game.tinfo.seconds_to_phasedone is relative to this).
905      * Account for the difference. */
906     tinfo.seconds_to_phasedone = game.tinfo.seconds_to_phasedone
907         - timer_read_seconds(game.server.phase_timer);
908   } else {
909     /* unused but at least initialized */
910     tinfo.seconds_to_phasedone = -1.0;
911   }
912 
913   conn_list_iterate(dest, pconn) {
914     /* These are separate packets as first one may not get sent at all
915      * if there's no changes in it */
916     send_packet_game_info(pconn, &(game.info));
917     send_packet_timeout_info(pconn, &tinfo);
918   }
919   conn_list_iterate_end;
920 }
921 
922 /**************************************************************************
923   Send current scenario info. dest NULL causes send to everyone
924 **************************************************************************/
send_scenario_info(struct conn_list * dest)925 void send_scenario_info(struct conn_list *dest)
926 {
927   if (!dest) {
928     dest = game.est_connections;
929   }
930 
931   conn_list_iterate(dest, pconn) {
932     send_packet_scenario_info(pconn, &(game.scenario));
933   } conn_list_iterate_end;
934 }
935 
936 /**************************************************************************
937   Send description of the current scenario. dest NULL causes send to everyone
938 **************************************************************************/
send_scenario_description(struct conn_list * dest)939 void send_scenario_description(struct conn_list *dest)
940 {
941   if (!dest) {
942     dest = game.est_connections;
943   }
944 
945   conn_list_iterate(dest, pconn) {
946     send_packet_scenario_description(pconn, &(game.scenario_desc));
947   } conn_list_iterate_end;
948 }
949 
950 /**************************************************************************
951   adjusts game.info.timeout based on various server options
952 
953   timeoutint: adjust game.info.timeout every timeoutint turns
954   timeoutinc: adjust game.info.timeout by adding timeoutinc to it.
955   timeoutintinc: every time we adjust game.info.timeout, we add timeoutintinc
956                  to timeoutint.
957   timeoutincmult: every time we adjust game.info.timeout, we multiply timeoutinc
958                   by timeoutincmult
959 **************************************************************************/
update_timeout(void)960 int update_timeout(void)
961 {
962   /* if there's no timer or we're doing autogame, do nothing */
963   if (game.info.timeout < 1 || game.server.timeoutint == 0) {
964     return game.info.timeout;
965   }
966 
967   if (game.server.timeoutcounter >= game.server.timeoutint) {
968     game.info.timeout += game.server.timeoutinc;
969     game.server.timeoutinc *= game.server.timeoutincmult;
970 
971     game.server.timeoutcounter = 1;
972     game.server.timeoutint += game.server.timeoutintinc;
973 
974     if (game.info.timeout > GAME_MAX_TIMEOUT) {
975       notify_conn(game.est_connections, NULL, E_SETTING, ftc_server,
976                   _("The turn timeout has exceeded its maximum value, "
977                     "fixing at its maximum."));
978       log_debug("game.info.timeout exceeded maximum value");
979       game.info.timeout = GAME_MAX_TIMEOUT;
980       game.server.timeoutint = 0;
981       game.server.timeoutinc = 0;
982     } else if (game.info.timeout < 0) {
983       notify_conn(game.est_connections, NULL, E_SETTING, ftc_server,
984                   _("The turn timeout is smaller than zero, "
985                     "fixing at zero."));
986       log_debug("game.info.timeout less than zero");
987       game.info.timeout = 0;
988     }
989   } else {
990     game.server.timeoutcounter++;
991   }
992 
993   log_debug("timeout=%d, inc=%d incmult=%d\n   "
994             "int=%d, intinc=%d, turns till next=%d",
995             game.info.timeout, game.server.timeoutinc,
996             game.server.timeoutincmult, game.server.timeoutint,
997             game.server.timeoutintinc,
998             game.server.timeoutint - game.server.timeoutcounter);
999 
1000   return game.info.timeout;
1001 }
1002 
1003 /**************************************************************************
1004   adjusts game.seconds_to_turn_done when enemy moves a unit, we see it and
1005   the remaining timeout is smaller than the timeoutaddenemymove option.
1006 
1007   It's possible to use a similar function to do that per-player.  In
1008   theory there should be a separate timeout for each player and the
1009   added time should only go onto the victim's timer.
1010 **************************************************************************/
increase_timeout_because_unit_moved(void)1011 void increase_timeout_because_unit_moved(void)
1012 {
1013   if (current_turn_timeout() > 0 && game.server.timeoutaddenemymove > 0) {
1014     double maxsec = (timer_read_seconds(game.server.phase_timer)
1015 		     + (double) game.server.timeoutaddenemymove);
1016 
1017     if (maxsec > game.tinfo.seconds_to_phasedone) {
1018       game.tinfo.seconds_to_phasedone = maxsec;
1019       send_game_info(NULL);
1020     }
1021   }
1022 }
1023 
1024 /**************************************************************************
1025   generate challenge filename for this connection, cannot fail.
1026 **************************************************************************/
gen_challenge_filename(struct connection * pc)1027 static void gen_challenge_filename(struct connection *pc)
1028 {
1029 }
1030 
1031 /**************************************************************************
1032   get challenge filename for this connection.
1033 **************************************************************************/
get_challenge_filename(struct connection * pc)1034 static const char *get_challenge_filename(struct connection *pc)
1035 {
1036   static char filename[MAX_LEN_PATH];
1037 
1038   fc_snprintf(filename, sizeof(filename), "%s_%d_%d",
1039       CHALLENGE_ROOT, srvarg.port, pc->id);
1040 
1041   return filename;
1042 }
1043 
1044 /**************************************************************************
1045   get challenge full filename for this connection.
1046 **************************************************************************/
get_challenge_fullname(struct connection * pc)1047 static const char *get_challenge_fullname(struct connection *pc)
1048 {
1049   static char fullname[MAX_LEN_PATH];
1050 
1051 #ifdef HAIKU
1052   interpret_tilde(fullname, sizeof(fullname), "~" DIR_SEPARATOR "config" DIR_SEPARATOR "settings"
1053                      DIR_SEPARATOR "freeciv" DIR_SEPARATOR);
1054 #else  /* HAIKU */
1055   interpret_tilde(fullname, sizeof(fullname), "~" DIR_SEPARATOR ".freeciv" DIR_SEPARATOR);
1056 #endif  /* HAIKU */
1057   sz_strlcat(fullname, get_challenge_filename(pc));
1058 
1059   return fullname;
1060 }
1061 
1062 /**************************************************************************
1063   find a file that we can write too, and return it's name.
1064 **************************************************************************/
new_challenge_filename(struct connection * pc)1065 const char *new_challenge_filename(struct connection *pc)
1066 {
1067   gen_challenge_filename(pc);
1068   return get_challenge_filename(pc);
1069 }
1070 
1071 
1072 /**************************************************************************
1073   Call this on a connection with HACK access to send it a set of ruleset
1074   choices.  Probably this should be called immediately when granting
1075   HACK access to a connection.
1076 **************************************************************************/
send_ruleset_choices(struct connection * pc)1077 static void send_ruleset_choices(struct connection *pc)
1078 {
1079   struct strvec *ruleset_choices;
1080   struct packet_ruleset_choices packet;
1081   size_t i = 0;
1082 
1083   ruleset_choices = get_init_script_choices();
1084 
1085   strvec_iterate(ruleset_choices, s) {
1086     const int maxlen = sizeof packet.rulesets[i];
1087     if (i >= MAX_NUM_RULESETS) {
1088       log_verbose("Can't send more than %d ruleset names to client, "
1089                   "skipping some", MAX_NUM_RULESETS);
1090       break;
1091     }
1092     if (fc_strlcpy(packet.rulesets[i], s, maxlen) < maxlen) {
1093       i++;
1094     } else {
1095       log_verbose("Ruleset name '%s' too long to send to client, skipped", s);
1096     }
1097   } strvec_iterate_end;
1098   packet.ruleset_count = i;
1099 
1100   send_packet_ruleset_choices(pc, &packet);
1101 
1102   strvec_destroy(ruleset_choices);
1103 }
1104 
1105 /****************************************************************************
1106   Opens a file specified by the packet and compares the packet values with
1107   the file values. Sends an answer to the client once it's done.
1108 ****************************************************************************/
handle_single_want_hack_req(struct connection * pc,const struct packet_single_want_hack_req * packet)1109 void handle_single_want_hack_req(struct connection *pc,
1110                                  const struct packet_single_want_hack_req *
1111                                  packet)
1112 {
1113   struct section_file *secfile;
1114   const char *token = NULL;
1115   bool you_have_hack = FALSE;
1116 
1117   if ((secfile = secfile_load(get_challenge_fullname(pc), FALSE))) {
1118     token = secfile_lookup_str(secfile, "challenge.token");
1119     you_have_hack = (token && strcmp(token, packet->token) == 0);
1120     secfile_destroy(secfile);
1121   } else {
1122     log_debug("Error reading '%s':\n%s", get_challenge_fullname(pc),
1123               secfile_error());
1124   }
1125 
1126   if (!token) {
1127     log_debug("Failed to read authentication token");
1128   }
1129 
1130   if (you_have_hack) {
1131     conn_set_access(pc, ALLOW_HACK, TRUE);
1132   }
1133 
1134   dsend_packet_single_want_hack_reply(pc, you_have_hack);
1135 
1136   send_ruleset_choices(pc);
1137   send_conn_info(pc->self, NULL);
1138 }
1139