Freeciv-3.2
Loading...
Searching...
No Matches
gamehand.c
Go to the documentation of this file.
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 "modpack.h"
38#include "movement.h"
39#include "nation.h"
40#include "packets.h"
41
42/* server */
43#include "citytools.h"
44#include "connecthand.h"
45#include "maphand.h"
46#include "notify.h"
47#include "plrhand.h"
48#include "srv_main.h"
49#include "stdinhand.h"
50#include "unittools.h"
51
52/* server/advisors */
53#include "advdata.h"
54
55#include "gamehand.h"
56
57#define CHALLENGE_ROOT "challenge"
58
59#define SPECLIST_TAG startpos
60#define SPECLIST_TYPE struct startpos
61#include "speclist.h"
62#define startpos_list_iterate(list, plink, psp) \
63 TYPED_LIST_BOTH_ITERATE(struct startpos_list_link, struct startpos, \
64 list, plink, psp)
65#define startpos_list_iterate_end LIST_BOTH_ITERATE_END
66
73
76 long score;
77};
78
79#define SPECPQ_TAG team_placement
80#define SPECPQ_DATA_TYPE struct team_placement_state *
81#define SPECPQ_PRIORITY_TYPE long
82#include "specpq.h"
83
84/************************************************************************/
88{
89 switch (crole) {
90 case 'c':
91 return L_START_CITIES;
92 case 'w':
93 return L_START_WORKER;
94 case 'x':
95 return L_START_EXPLORER;
96 case 'k':
97 return L_START_KING;
98 case 's':
99 return L_START_DIPLOMAT;
100 case 'f':
101 return L_START_FERRY;
102 case 'd':
103 return L_START_DEFEND_OK;
104 case 'D':
105 return L_START_DEFEND_GOOD;
106 case 'a':
107 return L_START_ATTACK_FAST;
108 case 'A':
110 default:
111 return 0;
112 }
113}
114
115/************************************************************************/
120struct unit_type *crole_to_unit_type(char crole, struct player *pplayer)
121{
122 struct unit_type *utype = NULL;
124 int num;
125
126 if (role == 0) {
128 return NULL;
129 }
130
131 /* Create the unit of an appropriate type, if it exists */
132 num = num_role_units(role);
133 if (num > 0) {
134 if (pplayer != NULL) {
135 int i;
136
137 utype = first_role_unit_for_player(pplayer, role);
138 for (i = 0; utype == NULL && i < num; i++) {
139 struct unit_type *ntype = get_role_unit(role, i);
140
142 utype = ntype;
143 }
144 }
145 } else {
146 utype = get_role_unit(role, 0);
147 }
148 }
149
150 return utype;
151}
152
153/************************************************************************/
158static struct tile *place_starting_unit(struct tile *starttile,
159 struct player *pplayer,
160 struct unit_type *ptype, char crole)
161{
162 struct tile *ptile = NULL;
163 struct unit_type *utype;
164 bool hut_present = FALSE;
165
166 if (ptype != NULL) {
167 utype = ptype;
168 } else {
169 utype = crole_to_unit_type(crole, pplayer);
170 }
171
172 if (utype != NULL) {
175 if (!is_non_allied_unit_tile(itertile, pplayer)
176 && is_native_tile(utype, itertile)) {
177 ptile = itertile;
178 break;
179 }
181 }
182
183 if (ptile == NULL) {
184 /* No place where unit may exist. */
185 return NULL;
186 }
187
189
190 /* For scenarios or dispersion, huts may coincide with player starts (in
191 * other cases, huts are avoided as start positions). Remove any such hut,
192 * and make sure to tell the client, since we may have already sent this
193 * tile (with the hut) earlier: */
194 /* FIXME: don't remove under a unit that can't enter or frighten hut */
196 if (tile_has_extra(ptile, pextra)) {
197 tile_extra_rm_apply(ptile, pextra);
199 }
201
202 if (hut_present) {
204 log_verbose("Removed hut on start position for %s",
205 player_name(pplayer));
206 }
207
208 /* Expose visible area. */
210
211 if (utype != NULL) {
212 (void) create_unit(pplayer, ptile, utype, FALSE, 0, 0);
213 return ptile;
214 }
215
216 return NULL;
217}
218
219/************************************************************************/
222static struct tile *find_dispersed_position(struct player *pplayer,
223 struct tile *pcenter)
224{
225 struct tile *ptile;
226 int x, y;
227 int bailout;
228
229 if (game.server.dispersion == 0) {
230 bailout = 1; /* One attempt is guaranteed to cover single tile */
231 } else {
232 bailout = game.server.dispersion * 2 + 1; /* Side of the area */
233 bailout *= bailout; /* Area */
234 bailout *= 5; /* Likely to hit each tile at least once */
235 }
236
237 do {
238 if (!bailout--) {
239 return NULL;
240 }
244 } while (!((ptile = map_pos_to_tile(&(wld.map), x, y))
246 && !is_ocean_tile(ptile)
248 + 1
249 && !is_non_allied_unit_tile(ptile, pplayer)));
250
251 return ptile;
252}
253
254/* Calculate the distance between tiles, according to the 'teamplacement'
255 * setting set to 'CLOSEST'. */
256#define team_placement_closest sq_map_distance
257
258/************************************************************************/
262static int team_placement_continent(const struct tile *ptile1,
263 const struct tile *ptile2)
264{
265 return (ptile1->continent == ptile2->continent
268}
269
270/************************************************************************/
274static int team_placement_horizontal(const struct tile *ptile1,
275 const struct tile *ptile2)
276{
277 int dx, dy;
278
280 /* Map vector to natural vector (Y axis). */
281 return abs(MAP_IS_ISOMETRIC ? dx + dy : dy);
282}
283
284/************************************************************************/
288static int team_placement_vertical(const struct tile *ptile1,
289 const struct tile *ptile2)
290{
291 int dx, dy;
292
294 /* Map vector to natural vector (X axis). */
295 return abs(MAP_IS_ISOMETRIC ? dx - dy : dy);
296}
297
298/************************************************************************/
302{
303 free(pstate->startpos);
304 free(pstate);
305}
306
307/************************************************************************/
312 int iter_max)
313{
314 const size_t state_array_size = (sizeof(*pbest_state->startpos)
315 * pconfig->total_startpos_num);
316 struct team_placement_pq *pqueue =
317 team_placement_pq_new(pconfig->total_startpos_num * 4);
318 int (*distance)(const struct tile *, const struct tile *) = NULL;
320 const struct tile *ptile1, *ptile2;
321 long base_delta, delta;
323 int iter = 0;
324 bool repeat;
325 int i, j, k, t1, t2;
326
327 switch (wld.map.server.team_placement) {
329 distance = team_placement_closest;
330 break;
332 distance = team_placement_continent;
333 break;
335 distance = team_placement_horizontal;
336 break;
338 distance = team_placement_vertical;
339 break;
341 break;
342 }
343 fc_assert_ret_msg(distance != NULL, "Wrong team_placement variant (%d)",
345
346 /* Initialize starting state. */
347 pstate = fc_malloc(sizeof(*pstate));
348 pstate->startpos = fc_malloc(state_array_size);
349 memcpy(pstate->startpos, pbest_state->startpos, state_array_size);
350 pstate->score = pbest_state->score;
351
352 do {
353 repeat = FALSE;
354 for (i = 0; i < pconfig->usable_startpos_num; i++) {
355 t1 = pstate->startpos[i];
356 if (t1 == -1) {
357 continue; /* Not used. */
358 }
359 ptile1 = pconfig->startpos[i];
361 for (j = i + 1; j < (i >= pconfig->flexible_startpos_num
362 ? pconfig->usable_startpos_num
363 : pconfig->flexible_startpos_num); j++) {
364 t2 = pstate->startpos[j];
365 if (t2 == -1) {
366 /* Not assigned yet. */
367 ptile2 = pconfig->startpos[j];
369 delta = base_delta;
370 for (k = 0; k < pconfig->total_startpos_num; k++) {
371 if (k != i && t1 == pstate->startpos[k]) {
372 delta += distance(ptile2, pconfig->startpos[k]);
373 }
374 }
375 } else {
376 delta = 0;
377 base_delta = 0;
378 for (k = 0; k < pconfig->total_startpos_num; k++) {
379 if (k != i && t1 == pstate->startpos[k]) {
380 base_delta -= distance(ptile1, pconfig->startpos[k]);
381 delta += distance(ptile2, pconfig->startpos[k]);
382 }
383 }
384 delta += base_delta;
386 }
387 } else if (t1 < t2) {
388 ptile2 = pconfig->startpos[j];
390 delta = base_delta;
391 for (k = 0; k < pconfig->total_startpos_num; k++) {
392 if (k != i && t1 == pstate->startpos[k]) {
393 delta += distance(ptile2, pconfig->startpos[k]);
394 } else if (k != j && t2 == pstate->startpos[k]) {
395 delta -= distance(ptile2, pconfig->startpos[k]);
396 delta += distance(ptile1, pconfig->startpos[k]);
397 }
398 }
399 } else {
400 delta = 0;
401 base_delta = 0;
402 for (k = 0; k < pconfig->total_startpos_num; k++) {
403 if (k != i && t1 == pstate->startpos[k]) {
404 base_delta -= distance(ptile1, pconfig->startpos[k]);
405 delta += distance(ptile2, pconfig->startpos[k]);
406 } else if (k != j && t2 == pstate->startpos[k]) {
407 delta -= distance(ptile2, pconfig->startpos[k]);
408 delta += distance(ptile1, pconfig->startpos[k]);
409 }
410 }
411 delta += base_delta;
413 }
414 } else {
415 continue;
416 }
417
418 if (delta <= 0) {
419 repeat = TRUE;
420 pnew = fc_malloc(sizeof(*pnew));
421 pnew->startpos = fc_malloc(state_array_size);
422 memcpy(pnew->startpos, pstate->startpos, state_array_size);
423 pnew->startpos[i] = t2;
424 pnew->startpos[j] = t1;
425 pnew->score = pstate->score + delta;
427
428 if (pnew->score < pbest_state->score) {
429 memcpy(pbest_state->startpos, pnew->startpos, state_array_size);
430 pbest_state->score = pnew->score;
431 }
432 }
433 }
434 }
435
437 if (iter++ >= iter_max) {
438 log_normal(_("Didn't find optimal solution for team placement "
439 "in %d iterations."), iter);
440 break;
441 }
442
443 } while (repeat && team_placement_pq_remove(pqueue, &pstate));
444
446}
447
448/************************************************************************/
452{
457 int sulen;
458
459 randomize_base64url_string(server.game_identifier,
460 sizeof(server.game_identifier));
461
462 /* Assign players to starting positions on the map.
463 * (In scenarios with restrictions on which nations can use which predefined
464 * start positions, this process tries to satisfy those restrictions, but
465 * does not guarantee to. Even if there is a solution to the matching
466 * problem, this algorithm may not find it.) */
467
469
470 /* Convert the startposition hash table in a linked lists, as we mostly
471 * need now to iterate it now. And then, we will be able to remove the
472 * assigned start positions one by one. */
476
478 if (startpos_allows_all(psp)) {
480 } else {
482 }
484
487
489 log_verbose("Placing players at start positions.");
490
491 /* First assign start positions which have restrictions on which nations
492 * can use them. */
494 log_verbose("Assigning matching nations.");
495
496 startpos_list_shuffle(targeted_list); /* Randomize. */
497 do {
498 struct nation_type *pnation;
499 struct startpos_list_link *choice;
500 bool removed = FALSE;
501
502 /* Assign first players which can pick only one start position. */
503 players_iterate(pplayer) {
504 if (NULL != player_startpos[player_index(pplayer)]) {
505 /* Already assigned. */
506 continue;
507 }
508
509 pnation = nation_of_player(pplayer);
510 choice = NULL;
512 if (startpos_nation_allowed(psp, pnation)) {
513 if (NULL != choice) {
514 choice = NULL;
515 break; /* Many choices. */
516 } else {
517 choice = plink;
518 }
519 }
521
522 if (NULL != choice) {
523 /* Assign this start position to this player and remove
524 * both from consideration. */
525 struct tile *ptile =
527
528 player_startpos[player_index(pplayer)] = ptile;
531 removed = TRUE;
532 log_verbose("Start position (%d, %d) exactly matches player %s (%s).",
533 TILE_XY(ptile), player_name(pplayer),
534 nation_rule_name(pnation));
535 }
537
538 if (!removed) {
539 /* Didn't find any 1:1 matches. For the next restricted start
540 * position, assign a random matching player. (This may create
541 * restrictions such that more 1:1 matches are possible.) */
543 struct tile *ptile = startpos_tile(psp);
544 struct player *rand_plr = NULL;
545 int i = 0;
546
547 startpos_list_pop_back(targeted_list); /* Detach 'psp'. */
548 players_iterate(pplayer) {
549 if (NULL != player_startpos[player_index(pplayer)]) {
550 /* Already assigned. */
551 continue;
552 }
553
554 pnation = nation_of_player(pplayer);
555 if (startpos_nation_allowed(psp, pnation) && 0 == fc_rand(++i)) {
556 rand_plr = pplayer;
557 }
559
560 if (NULL != rand_plr) {
563 log_verbose("Start position (%d, %d) matches player %s (%s).",
566 } else {
567 /* This start position cannot be assigned, given the assignments
568 * made so far. We may have to fall back to mismatched
569 * assignments. */
570 log_verbose("Start position (%d, %d) cannot be assigned for "
571 "any player, keeping for the moment...",
572 TILE_XY(ptile));
573 /* Keep it for later, we may need it. */
575 }
576 }
578 }
579
580 /* Now try to assign with regard to the 'teamplacement' setting. */
581 if (players_to_place > 0
583 && player_count() > team_count()) {
584 const struct player_list *members;
586 int real_team_count = 0;
587
592 if (player_list_size(members) == 1) {
593 /* Single player teams, doesn't count for team placement. */
594 continue;
595 }
596 player_list_iterate(members, pplayer) {
597 if (player_startpos[player_index(pplayer)] == NULL) {
599 }
602
604 /* We really can do something to improve team placement. */
606 struct team_placement_state state;
607 int i, j, t;
608
609 log_verbose("Do team placement for %d players, using %s variant.",
612
613 /* Initialize configuration. */
614 config.flexible_startpos_num = startpos_list_size(flexible_list);
615 config.usable_startpos_num = config.flexible_startpos_num;
616 if (config.flexible_startpos_num < team_placement_players_to_place) {
617 config.usable_startpos_num += startpos_list_size(impossible_list);
618 }
619 config.total_startpos_num = (config.usable_startpos_num
621 config.startpos = fc_malloc(sizeof(*config.startpos)
622 * config.total_startpos_num);
623 i = 0;
625 config.startpos[i++] = startpos_tile(psp);
627 fc_assert(i == config.flexible_startpos_num);
628 if (i < config.usable_startpos_num) {
630 config.startpos[i++] = startpos_tile(psp);
632 }
633 fc_assert(i == config.usable_startpos_num);
634 while (i < config.total_startpos_num) {
635 config.startpos[i++] = NULL;
636 }
637 fc_assert(i == config.total_startpos_num);
638
639 /* Initialize state. */
640 state.startpos = fc_malloc(sizeof(*state.startpos)
641 * config.total_startpos_num);
642 state.score = 0;
643 i = 0;
644 j = config.usable_startpos_num;
647 if (player_list_size(members) <= 1) {
648 /* Single player teams, doesn't count for team placement. */
649 continue;
650 }
651 t = team_number(pteam);
652 player_list_iterate(members, pplayer) {
653 struct tile *ptile = player_startpos[player_index(pplayer)];
654
655 if (ptile == NULL) {
656 state.startpos[i++] = t;
657 } else {
658 state.startpos[j] = t;
659 config.startpos[j] = ptile;
660 j++;
661 }
664 while (i < config.usable_startpos_num) {
665 state.startpos[i++] = -1;
666 }
667 fc_assert(i == config.usable_startpos_num);
668 while (j < config.total_startpos_num) {
669 state.startpos[j++] = -1;
670 }
671 fc_assert(j == config.total_startpos_num);
672
673 /* Look for best team placement. */
675
676 /* Apply result. */
677 for (i = 0; i < config.usable_startpos_num; i++) {
678 t = state.startpos[i];
679 if (t != -1) {
680 const struct team *pteam = team_by_number(t);
681 int candidate_index = -1;
682 int candidate_num = 0;
683
684 log_verbose("Start position (%d, %d) assigned to team %d (%s)",
685 TILE_XY(config.startpos[i]),
687
690 && fc_rand(++candidate_num) == 0) {
692 }
698 }
699 }
701
702 /* Free data. */
703 if (players_to_place > 0) {
704 /* We need to remove used startpos from the lists. */
705 i = 0;
707 (void)psp; /* To avoid 'set but unused' compiler warning */
708 fc_assert(config.startpos[i] == startpos_tile(psp));
709 if (state.startpos[i] != -1) {
711 }
712 i++;
714 fc_assert(i == config.flexible_startpos_num);
715 if (i < config.usable_startpos_num) {
717 (void)psp; /* To avoid 'set but unused' compiler warning */
718 fc_assert(config.startpos[i] == startpos_tile(psp));
719 if (state.startpos[i] != -1) {
721 }
722 i++;
724 }
725 fc_assert(i == config.usable_startpos_num);
726 }
727
728 free(state.startpos);
729 free(config.startpos);
730 }
731 }
732
733 /* Now assign unrestricted start positions to any remaining players. */
735 struct tile *ptile;
736
737 log_verbose("Assigning unrestricted start positions.");
738
739 startpos_list_shuffle(flexible_list); /* Randomize. */
740 players_iterate(pplayer) {
741 if (NULL != player_startpos[player_index(pplayer)]) {
742 /* Already assigned. */
743 continue;
744 }
745
747 player_startpos[player_index(pplayer)] = ptile;
750 log_verbose("Start position (%d, %d) assigned randomly "
751 "to player %s (%s).", TILE_XY(ptile), player_name(pplayer),
754 break;
755 }
757 }
758
760 /* We still have players to place, and we have some restricted start
761 * positions whose nation requirements can't be satisfied given existing
762 * assignments. Fall back to making assignments ignoring the positions'
763 * nation requirements. */
764
765 struct tile *ptile;
766
767 log_verbose("Ignoring nation restrictions on remaining start positions.");
768
769 startpos_list_shuffle(impossible_list); /* Randomize. */
770 players_iterate(pplayer) {
771 if (NULL != player_startpos[player_index(pplayer)]) {
772 /* Already assigned. */
773 continue;
774 }
775
777 player_startpos[player_index(pplayer)] = ptile;
780 log_verbose("Start position (%d, %d) assigned to mismatched "
781 "player %s (%s).", TILE_XY(ptile), player_name(pplayer),
784 break;
785 }
787 }
788
790
794
796
797 /* Loop over all players, creating their initial units... */
798 shuffled_players_iterate(pplayer) {
799 struct tile *ptile;
800
801 /* We have to initialise the advisor and ai here as we could make contact
802 * to other nations at this point. */
803 adv_data_phase_init(pplayer, FALSE);
804 CALL_PLR_AI_FUNC(phase_begin, pplayer, pplayer, FALSE);
805
806 ptile = player_startpos[player_index(pplayer)];
807
808 fc_assert_action(NULL != ptile, continue);
809
810 /* Place first city */
811 if (game.server.start_city) {
812 create_city(pplayer, ptile, city_name_suggestion(pplayer, ptile),
813 NULL);
814
815 /* Expose visible area. */
817 }
818
819 if (sulen > 0) {
820 /* Place the first unit. */
821 if (place_starting_unit(ptile, pplayer, NULL,
822 game.server.start_units[0]) != NULL) {
823 placed_units[player_index(pplayer)] = 1;
824 } else {
825 placed_units[player_index(pplayer)] = 0;
826 }
827 } else {
828 placed_units[player_index(pplayer)] = 0;
829 }
831
832 /* Place all other units. */
833 shuffled_players_iterate(pplayer) {
834 int i;
835 struct tile *const ptile = player_startpos[player_index(pplayer)];
836 struct nation_type *nation = nation_of_player(pplayer);
837
838 fc_assert_action(NULL != ptile, continue);
839
840 /* Place global start units */
841 for (i = 1; i < sulen; i++) {
842 struct tile *rand_tile = find_dispersed_position(pplayer, ptile);
843
844 /* Create the unit of an appropriate type. */
845 if (rand_tile != NULL
848 placed_units[player_index(pplayer)]++;
849 }
850 }
851
852 /* Place nation specific start units (not role based!) */
853 i = 0;
854 while (NULL != nation->init_units[i] && MAX_NUM_UNIT_LIST > i) {
855 struct tile *rand_tile = find_dispersed_position(pplayer, ptile);
856
857 if (rand_tile != NULL
858 && place_starting_unit(rand_tile, pplayer,
859 nation->init_units[i], '\0') != NULL) {
860 placed_units[player_index(pplayer)]++;
861 }
862 i++;
863 }
865
866 players_iterate(pplayer) {
867 /* Close the active phase for advisor and ai for all players; it was
868 * opened in the first loop above. */
869 adv_data_phase_done(pplayer);
870 CALL_PLR_AI_FUNC(phase_finished, pplayer, pplayer);
871
873 _("No units placed for %s!"), player_name(pplayer));
875}
876
877/************************************************************************/
882{
884
885 players_iterate(pplayer) {
886 pplayer->nturns_idle++;
888
890 apacket.fragments = game.info.fragment_count;
891 apacket.turn = game.info.turn;
893
894 /* Hmm, clients could add this themselves based on above packet? */
896 _("Year: %s"), calendar_text());
897}
898
899/************************************************************************/
907void send_game_info(struct conn_list *dest)
908{
909 struct packet_timeout_info tinfo;
910
911 if (!dest) {
912 dest = game.est_connections;
913 }
914
915 tinfo = game.tinfo;
916
917 /* the following values are computed every
918 time a packet_game_info packet is created */
919
920 /* Sometimes this function is called before the phase_timer is
921 * initialized. In that case we want to send the dummy value. */
923 /* Whenever the client sees this packet, it starts a new timer at 0;
924 * but the server's timer is only ever reset at the start of a phase
925 * (and game.tinfo.seconds_to_phasedone is relative to this).
926 * Account for the difference. */
930 } else {
931 /* unused but at least initialized */
932 tinfo.seconds_to_phasedone = -1.0;
933 }
934
935 conn_list_iterate(dest, pconn) {
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. */
943 }
945}
946
947/************************************************************************/
951{
952 if (!dest) {
953 dest = game.est_connections;
954 }
955
956 conn_list_iterate(dest, pconn) {
959}
960
961/************************************************************************/
965{
966 if (!dest) {
967 dest = game.est_connections;
968 }
969
970 conn_list_iterate(dest, pconn) {
973}
974
975/************************************************************************/
986{
987 /* if there's no timer or we're doing autogame, do nothing */
988 if (game.info.timeout < 1 || game.server.timeoutint == 0) {
989 return game.info.timeout;
990 }
991
995
998
1001 _("The turn timeout has exceeded its maximum value, "
1002 "fixing at its maximum."));
1003 log_debug("game.info.timeout exceeded maximum value");
1007 } else if (game.info.timeout < 0) {
1009 _("The turn timeout is smaller than zero, "
1010 "fixing at zero."));
1011 log_debug("game.info.timeout less than zero");
1012 game.info.timeout = 0;
1013 }
1014 } else {
1016 }
1017
1018 log_debug("timeout=%d, inc=%d incmult=%d\n "
1019 "int=%d, intinc=%d, turns till next=%d",
1024
1025 return game.info.timeout;
1026}
1027
1028/************************************************************************/
1048
1049/************************************************************************/
1053{
1054}
1055
1056/************************************************************************/
1059static const char *get_challenge_filename(struct connection *pc)
1060{
1061 static char filename[MAX_LEN_PATH];
1062
1063 fc_snprintf(filename, sizeof(filename), "%s_%d_%d",
1065
1066 return filename;
1067}
1068
1069/************************************************************************/
1072static const char *get_challenge_fullname(struct connection *pc)
1073{
1074 static char fullname[MAX_LEN_PATH];
1075 const char *sdir = freeciv_storage_dir();
1076 const char *cname;
1077
1078 if (sdir == NULL) {
1079 return NULL;
1080 }
1081
1083
1084 if (cname == NULL) {
1085 return NULL;
1086 }
1087
1088 fc_snprintf(fullname, sizeof(fullname), "%s" DIR_SEPARATOR "%s", sdir, cname);
1089
1090 return fullname;
1091}
1092
1093/************************************************************************/
1097{
1099 return get_challenge_filename(pc);
1100}
1101
1106
1107/************************************************************************/
1110static void ruleset_cache_sendclient_cb(const char *mp_name,
1111 const char *filename, void *data_in)
1112{
1113 struct mrc_sendclient_data *data = (struct mrc_sendclient_data *)data_in;
1114 const int maxlen = sizeof(data->packet->rulesets[data->count]);
1115
1116 if (data->count >= MAX_NUM_RULESETS) {
1117 log_verbose("Can't send more than %d ruleset names to client, "
1118 "skipping some", MAX_NUM_RULESETS);
1119 return;
1120 }
1121
1122 if (fc_strlcpy(data->packet->rulesets[data->count], mp_name, maxlen) < maxlen) {
1123 data->count++;
1124 } else {
1125 log_verbose("Modpack name '%s' too long to send to client, skipped",
1126 mp_name);
1127 }
1128}
1129
1130/************************************************************************/
1134{
1135 static bool rulesets_cached = FALSE;
1136
1137 if (!rulesets_cached) {
1139
1141
1143 struct section_file *sf;
1144
1145 sf = secfile_load(pfile->fullname, FALSE);
1146
1147 if (sf != NULL) {
1149 secfile_destroy(sf);
1150 }
1152
1154
1156 }
1157}
1158
1159/************************************************************************/
1165{
1166 struct packet_ruleset_choices packet;
1167 struct mrc_sendclient_data data;
1168
1170
1171 data.count = 0;
1172 data.packet = &packet;
1174
1175 packet.ruleset_count = data.count;
1176
1178}
1179
1180/************************************************************************/
1184 const struct packet_ruleset_select *packet)
1185{
1186 struct section_file *sf;
1187 const char *name;
1188
1189 if (server_state() != S_S_INITIAL) {
1190 log_warn("Unexpected ruleset selection packet from client");
1191 return;
1192 }
1193
1194 if (pc->access_level < ALLOW_HACK) {
1195 log_verbose("Attempt to set ruleset from non-hack level connection");
1196 }
1197
1199
1200 if (name == NULL) {
1201 log_error("Modpack \"%s\" not in ruleset cache", packet->modpack);
1202 return;
1203 }
1204
1205 sf = secfile_load(name, FALSE);
1206
1207 if (sf == NULL) {
1208 log_error("Failed to load modpack file \"%s\"", name);
1209 return;
1210 }
1211
1212 name = modpack_serv_file(sf);
1213
1214 if (name != NULL) {
1216 } else {
1218
1219 if (name != NULL) {
1221 } else {
1222 log_error("Modpack \"%s\" does not contain ruleset at all",
1223 packet->modpack);
1224 }
1225 }
1226
1227 secfile_destroy(sf);
1228}
1229
1230/************************************************************************/
1235 const struct packet_single_want_hack_req *
1236 packet)
1237{
1238 struct section_file *secfile;
1239 const char *token = NULL;
1240 bool you_have_hack = FALSE;
1241
1242 if ((secfile = secfile_load(get_challenge_fullname(pc), FALSE))) {
1243 token = secfile_lookup_str(secfile, "challenge.token");
1244 you_have_hack = (token && strcmp(token, packet->token) == 0);
1245 secfile_destroy(secfile);
1246 } else {
1247 log_debug("Error reading '%s':\n%s", get_challenge_fullname(pc),
1248 secfile_error());
1249 }
1250
1251 if (!token) {
1252 log_debug("Failed to read authentication token");
1253 }
1254
1255 if (you_have_hack) {
1257 }
1258
1260
1262 send_conn_info(pc->self, NULL);
1263}
bool adv_data_phase_init(struct player *pplayer, bool is_new_phase)
Definition advdata.c:263
void adv_data_phase_done(struct player *pplayer)
Definition advdata.c:565
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:377
const char * calendar_text(void)
Definition calendar.c:141
const char * city_name_suggestion(struct player *pplayer, struct tile *ptile)
Definition citytools.c:458
void create_city(struct player *pplayer, struct tile *ptile, const char *name, struct player *nationality)
Definition citytools.c:1519
char * incite_cost
Definition comments.c:75
void send_conn_info(struct conn_list *src, struct conn_list *dest)
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Definition connecthand.c:72
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
#define conn_list_iterate_end
Definition connection.h:110
#define extra_type_by_rmcause_iterate_end
Definition extras.h:358
#define extra_type_by_rmcause_iterate(_rmcause, _extra)
Definition extras.h:353
#define MAX_NUM_RULESETS
Definition fc_types.h:412
#define MAX_NUM_UNIT_LIST
Definition fc_types.h:45
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_server
const struct ft_color ftc_any
struct civ_game game
Definition game.c:62
int current_turn_timeout(void)
Definition game.c:848
struct world wld
Definition game.c:63
#define GAME_MAX_TIMEOUT
Definition game.h:609
static void gen_challenge_filename(struct connection *pc)
Definition gamehand.c:1052
static const char * get_challenge_fullname(struct connection *pc)
Definition gamehand.c:1072
void send_scenario_description(struct conn_list *dest)
Definition gamehand.c:964
void send_year_to_clients(void)
Definition gamehand.c:881
void send_scenario_info(struct conn_list *dest)
Definition gamehand.c:950
static struct tile * place_starting_unit(struct tile *starttile, struct player *pplayer, struct unit_type *ptype, char crole)
Definition gamehand.c:158
#define team_placement_closest
Definition gamehand.c:256
static int team_placement_vertical(const struct tile *ptile1, const struct tile *ptile2)
Definition gamehand.c:288
int update_timeout(void)
Definition gamehand.c:985
void handle_single_want_hack_req(struct connection *pc, const struct packet_single_want_hack_req *packet)
Definition gamehand.c:1234
void send_game_info(struct conn_list *dest)
Definition gamehand.c:907
#define CHALLENGE_ROOT
Definition gamehand.c:57
static void send_ruleset_choices(struct connection *pc)
Definition gamehand.c:1164
static struct tile * find_dispersed_position(struct player *pplayer, struct tile *pcenter)
Definition gamehand.c:222
#define startpos_list_iterate_end
Definition gamehand.c:65
static void do_team_placement(const struct team_placement_config *pconfig, struct team_placement_state *pbest_state, int iter_max)
Definition gamehand.c:310
static int team_placement_continent(const struct tile *ptile1, const struct tile *ptile2)
Definition gamehand.c:262
static void ruleset_cache_sendclient_cb(const char *mp_name, const char *filename, void *data_in)
Definition gamehand.c:1110
#define startpos_list_iterate(list, plink, psp)
Definition gamehand.c:62
enum unit_role_id crole_to_role_id(char crole)
Definition gamehand.c:87
static const char * get_challenge_filename(struct connection *pc)
Definition gamehand.c:1059
void increase_timeout_because_unit_moved(void)
Definition gamehand.c:1036
void handle_ruleset_select(struct connection *pc, const struct packet_ruleset_select *packet)
Definition gamehand.c:1183
void init_new_game(void)
Definition gamehand.c:451
struct unit_type * crole_to_unit_type(char crole, struct player *pplayer)
Definition gamehand.c:120
static void team_placement_state_destroy(struct team_placement_state *pstate)
Definition gamehand.c:301
const char * new_challenge_filename(struct connection *pc)
Definition gamehand.c:1096
static int team_placement_horizontal(const struct tile *ptile1, const struct tile *ptile2)
Definition gamehand.c:274
void cache_rulesets(void)
Definition gamehand.c:1133
const char * name
Definition inputfile.c:127
#define fc_assert_msg(condition, message,...)
Definition log.h:181
#define log_warn(message,...)
Definition log.h:105
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_msg(condition, message,...)
Definition log.h:205
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_normal(message,...)
Definition log.h:107
#define log_error(message,...)
Definition log.h:103
int sq_map_distance(const struct tile *tile0, const struct tile *tile1)
Definition map.c:641
bool startpos_nation_allowed(const struct startpos *psp, const struct nation_type *pnation)
Definition map.c:1685
struct tile * startpos_tile(const struct startpos *psp)
Definition map.c:1676
bool startpos_allows_all(const struct startpos *psp)
Definition map.c:1696
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:419
int map_startpos_count(void)
Definition map.c:1853
int real_map_distance(const struct tile *tile0, const struct tile *tile1)
Definition map.c:630
void map_distance_vector(int *dx, int *dy, const struct tile *tile0, const struct tile *tile1)
Definition map.c:1073
#define iterate_outward(nmap, start_tile, max_dist, itr_tile)
Definition map.h:367
#define iterate_outward_end
Definition map.h:371
#define map_startpos_iterate(NAME_psp)
Definition map.h:130
#define MAP_INDEX_SIZE
Definition map.h:137
#define MAP_IS_ISOMETRIC
Definition map.h:42
#define map_startpos_iterate_end
Definition map.h:133
#define index_to_map_pos(pmap_x, pmap_y, mindex)
Definition map.h:233
void map_show_circle(struct player *pplayer, struct tile *ptile, int radius_sq)
Definition maphand.c:864
void update_tile_knowledge(struct tile *ptile)
Definition maphand.c:1439
#define fc_malloc(sz)
Definition mem.h:34
void modpack_ruleset_cache_iterate(mrc_cb cb, void *data)
Definition modpack.c:202
const char * modpack_file_from_ruleset_cache(const char *name)
Definition modpack.c:188
const char * modpack_serv_file(struct section_file *sf)
Definition modpack.c:140
const char * modpack_rulesetdir(struct section_file *sf)
Definition modpack.c:152
struct fileinfo_list * get_modpacks_list(void)
Definition modpack.c:107
const char * modpack_cache_ruleset(struct section_file *sf)
Definition modpack.c:165
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
Definition movement.c:331
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:138
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:444
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:238
void lsend_packet_new_year(struct conn_list *dest, const struct packet_new_year *packet)
int send_packet_scenario_info(struct connection *pc, const struct packet_scenario_info *packet)
int send_packet_ruleset_choices(struct connection *pc, const struct packet_ruleset_choices *packet)
int send_packet_game_info(struct connection *pc, const struct packet_game_info *packet)
int send_packet_calendar_info(struct connection *pc, const struct packet_calendar_info *packet)
int dsend_packet_single_want_hack_reply(struct connection *pc, bool you_have_hack)
int send_packet_scenario_description(struct connection *pc, const struct packet_scenario_description *packet)
int send_packet_timeout_info(struct connection *pc, const struct packet_timeout_info *packet)
int player_count(void)
Definition player.c:817
int player_slot_count(void)
Definition player.c:418
const char * player_name(const struct player *pplayer)
Definition player.c:895
int player_index(const struct player *pplayer)
Definition player.c:829
#define players_iterate_end
Definition player.h:537
#define players_iterate(_pplayer)
Definition player.h:532
#define player_list_iterate(playerlist, pplayer)
Definition player.h:555
#define player_list_iterate_end
Definition player.h:557
#define shuffled_players_iterate_end
Definition plrhand.h:108
#define shuffled_players_iterate(NAME_pplayer)
Definition plrhand.h:98
#define fc_rand(_size)
Definition rand.h:56
struct section_file * secfile_load(const char *filename, bool allow_duplicates)
Definition registry.c:50
const char * secfile_error(void)
void secfile_destroy(struct section_file *secfile)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
void randomize_base64url_string(char *s, size_t n)
Definition shared.c:339
char * freeciv_storage_dir(void)
Definition shared.c:678
#define DIR_SEPARATOR
Definition shared.h:127
#define fileinfo_list_iterate(list, pnode)
Definition shared.h:176
#define MAX_LEN_PATH
Definition shared.h:32
#define fileinfo_list_iterate_end
Definition shared.h:178
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
struct server_arguments srvarg
Definition srv_main.c:176
enum server_states server_state(void)
Definition srv_main.c:333
bool read_init_script(struct connection *caller, const char *script_filename, bool from_cmdline, bool check)
Definition stdinhand.c:1169
bool set_rulesetdir(struct connection *caller, const char *str, bool check, int read_recursion)
Definition stdinhand.c:3978
int dispersion
Definition game.h:147
int init_vis_radius_sq
Definition game.h:156
char start_units[MAX_LEN_STARTUNIT]
Definition game.h:193
struct packet_scenario_description scenario_desc
Definition game.h:88
struct conn_list * est_connections
Definition game.h:97
struct packet_game_info info
Definition game.h:89
int timeoutcounter
Definition game.h:211
int additional_phase_seconds
Definition game.h:216
struct packet_scenario_info scenario
Definition game.h:87
int timeoutint
Definition game.h:207
struct timer * phase_timer
Definition game.h:215
struct civ_game::@31::@35 server
int timeoutincmult
Definition game.h:209
struct packet_timeout_info tinfo
Definition game.h:91
int timeoutinc
Definition game.h:208
bool start_city
Definition game.h:194
struct packet_calendar_info calendar
Definition game.h:90
int timeoutintinc
Definition game.h:210
int timeoutaddenemymove
Definition game.h:212
int xsize
Definition map_types.h:78
int ysize
Definition map_types.h:78
struct civ_map::@42::@44 server
enum team_placement team_placement
Definition map_types.h:109
struct packet_ruleset_choices * packet
Definition gamehand.c:1104
struct unit_type * init_units[MAX_NUM_UNIT_LIST]
Definition nation.h:125
char rulesets[MAX_NUM_RULESETS][MAX_RULESET_NAME_LENGTH]
char modpack[MAX_RULESET_NAME_LENGTH]
char token[MAX_LEN_NAME]
Definition map.c:41
struct tile ** startpos
Definition gamehand.c:68
Definition team.c:40
Definition tile.h:50
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int team_count(void)
Definition team.c:375
struct team * team_by_number(const int team_id)
Definition team.c:400
const char * team_rule_name(const struct team *pteam)
Definition team.c:410
int team_number(const struct team *pteam)
Definition team.c:391
const struct player_list * team_members(const struct team *pteam)
Definition team.c:456
#define teams_iterate_end
Definition team.h:87
#define teams_iterate(_pteam)
Definition team.h:82
#define is_ocean_tile(ptile)
Definition terrain.h:303
bool tile_extra_rm_apply(struct tile *ptile, struct extra_type *tgt)
Definition tile.c:601
#define tile_index(_pt_)
Definition tile.h:88
#define TILE_XY(ptile)
Definition tile.h:43
#define tile_continent(_tile)
Definition tile.h:92
#define tile_has_extra(ptile, pextra)
Definition tile.h:147
double timer_read_seconds(struct timer *t)
Definition timing.c:384
static bool is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Definition unit.h:432
struct unit * create_unit(struct player *pplayer, struct tile *ptile, const struct unit_type *type, int veteran_level, int homecity_id, int moves_left)
Definition unittools.c:1597
struct unit_type * first_role_unit_for_player(const struct player *pplayer, int role)
Definition unittype.c:2323
struct unit_type * get_role_unit(int role, int role_index)
Definition unittype.c:2253
int num_role_units(int role)
Definition unittype.c:2203
bool utype_player_already_has_this_unique(const struct player *pplayer, const struct unit_type *putype)
Definition unittype.c:1927