14 #include <QtWidgets/QtWidgets>
47 #define CHALLENGE_ROOT "challenge"
49 #define SPECLIST_TAG startpos
50 #define SPECLIST_TYPE struct startpos
52 #define startpos_list_iterate(list, plink, psp) \
53 TYPED_LIST_BOTH_ITERATE(struct startpos_list_link, struct startpos, list, \
55 #define startpos_list_iterate_end LIST_BOTH_ITERATE_END
69 #define SPECPQ_TAG team_placement
70 #define SPECPQ_DATA_TYPE struct team_placement_state *
71 #define SPECPQ_PRIORITY_TYPE long
81 return L_START_CITIES;
83 return L_START_WORKER;
85 return L_START_EXPLORER;
89 return L_START_DIPLOMAT;
93 return L_START_DEFEND_OK;
95 return L_START_DEFEND_GOOD;
97 return L_START_ATTACK_FAST;
99 return L_START_ATTACK_STRONG;
101 return unit_role_id(0);
120 if (pplayer !=
nullptr) {
123 if (utype ==
nullptr) {
140 struct tile *ptile =
nullptr;
142 bool hut_present =
false;
144 if (ptype !=
nullptr) {
150 if (utype !=
nullptr) {
163 if (ptile ==
nullptr) {
186 qDebug(
"Removed hut on start position for %s",
player_name(pplayer));
192 (void)
create_unit(pplayer, ptile, utype,
false, 0, 0);
200 struct tile *pcenter)
221 #define team_placement_closest sq_map_distance
228 const struct tile *ptile2)
240 const struct tile *ptile2)
254 const struct tile *ptile2)
279 const size_t state_array_size =
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;
290 case TEAM_PLACEMENT_CLOSEST:
293 case TEAM_PLACEMENT_CONTINENT:
296 case TEAM_PLACEMENT_HORIZONTAL:
299 case TEAM_PLACEMENT_VERTICAL:
302 case TEAM_PLACEMENT_DISABLED:
308 struct team_placement_pq *pqueue =
313 memcpy(pstate->startpos, pbest_state->
startpos, state_array_size);
314 pstate->score = pbest_state->
score;
319 t1 = pstate->startpos[i];
324 base_delta_calculated =
false;
329 t2 = pstate->startpos[j];
333 if (base_delta_calculated) {
336 if (k != i && t1 == pstate->startpos[k]) {
337 delta += distance(ptile2, pconfig->
startpos[k]);
344 if (k != i && t1 == pstate->startpos[k]) {
345 base_delta -= distance(ptile1, pconfig->
startpos[k]);
346 delta += distance(ptile2, pconfig->
startpos[k]);
350 base_delta_calculated =
true;
352 }
else if (t1 < t2) {
354 if (base_delta_calculated) {
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]);
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]);
377 base_delta_calculated =
true;
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);
393 if (pnew->score < pbest_state->
score) {
394 memcpy(pbest_state->
startpos, pnew->startpos, state_array_size);
395 pbest_state->
score = pnew->score;
402 if (iter++ >= iter_max) {
403 qInfo(
_(
"Didn't find optimal solution for team placement "
404 "in %d iterations."),
408 }
while (repeat && team_placement_pq_remove(pqueue, &pstate));
418 struct startpos_list *impossible_list, *targeted_list, *flexible_list;
425 sizeof(
server.game_identifier));
438 impossible_list = startpos_list_new();
439 targeted_list = startpos_list_new();
440 flexible_list = startpos_list_new();
447 startpos_list_append(flexible_list, psp);
449 startpos_list_append(targeted_list, psp);
453 fc_assert(startpos_list_size(targeted_list)
454 + startpos_list_size(flexible_list)
457 memset(player_startpos, 0,
sizeof(player_startpos));
458 qDebug(
"Placing players at start positions.");
462 if (0 < startpos_list_size(targeted_list)) {
463 qDebug(
"Assigning matching nations.");
465 startpos_list_shuffle(targeted_list);
468 struct startpos_list_link *choice;
469 bool removed =
false;
474 if (
nullptr != player_startpos[
player_index(pplayer)]) {
484 if (
nullptr != choice) {
494 if (
nullptr != choice) {
501 startpos_list_erase(targeted_list, choice);
504 qDebug(
"Start position (%d, %d) exactly matches player %s (%s).",
515 struct startpos *psp = startpos_list_back(targeted_list);
517 struct player *rand_plr =
nullptr;
520 startpos_list_pop_back(targeted_list);
523 if (
nullptr != player_startpos[
player_index(pplayer)]) {
535 if (
nullptr != rand_plr) {
538 qDebug(
"Start position (%d, %d) matches player %s (%s).",
545 qDebug(
"Start position (%d, %d) cannot be assigned for "
546 "any player, keeping for the moment...",
549 startpos_list_append(impossible_list, psp);
552 }
while (0 < players_to_place && 0 < startpos_list_size(targeted_list));
556 if (players_to_place > 0
557 &&
wld.
map.
server.team_placement != TEAM_PLACEMENT_DISABLED
559 const struct player_list *members;
560 int team_placement_players_to_place = 0;
561 int real_team_count = 0;
566 fc_assert(0 < player_list_size(members));
568 if (player_list_size(members) == 1) {
574 if (player_startpos[
player_index(pplayer)] ==
nullptr) {
575 team_placement_players_to_place++;
582 if (real_team_count > 1 && team_placement_players_to_place > 0) {
588 qDebug(
"Do team placement for %d players, using %s variant.",
589 team_placement_players_to_place,
629 if (player_list_size(members) <= 1) {
638 if (ptile ==
nullptr) {
666 int candidate_index = -1;
667 int candidate_num = 0;
669 qDebug(
"Start position (%d, %d) assigned to team %d (%s)",
675 &&
fc_rand(++candidate_num) == 0) {
681 player_startpos[candidate_index] = config.
startpos[i];
682 team_placement_players_to_place--;
686 fc_assert(team_placement_players_to_place == 0);
689 if (players_to_place > 0) {
696 startpos_list_erase(flexible_list, plink);
707 startpos_list_erase(impossible_list, plink);
722 if (0 < players_to_place && 0 < startpos_list_size(flexible_list)) {
725 qDebug(
"Assigning unrestricted start positions.");
727 startpos_list_shuffle(flexible_list);
730 if (
nullptr != player_startpos[
player_index(pplayer)]) {
738 startpos_list_pop_front(flexible_list);
739 qDebug(
"Start position (%d, %d) assigned randomly "
740 "to player %s (%s).",
743 if (0 == startpos_list_size(flexible_list)) {
750 if (0 < players_to_place && 0 < startpos_list_size(impossible_list)) {
758 qDebug(
"Ignoring nation restrictions on remaining start positions.");
760 startpos_list_shuffle(impossible_list);
763 if (
nullptr != player_startpos[
player_index(pplayer)]) {
771 startpos_list_pop_front(impossible_list);
772 qDebug(
"Start position (%d, %d) assigned to mismatched "
776 if (0 == startpos_list_size(impossible_list)) {
785 startpos_list_destroy(impossible_list);
786 startpos_list_destroy(targeted_list);
787 startpos_list_destroy(flexible_list);
836 for (i = 1; i < sulen; i++) {
849 while (i < MAX_NUM_UNIT_LIST && nullptr != nation->init_units[i]) {
882 struct packet_new_year apacket;
888 apacket.fragments =
game.
info.fragment_count;
907 struct packet_timeout_info tinfo;
925 tinfo.seconds_to_phasedone =
931 tinfo.seconds_to_phasedone = -1.0;
940 send_packet_game_info(pconn, &(
game.
info));
942 send_packet_timeout_info(pconn, &tinfo);
1005 _(
"The turn timeout has exceeded its maximum value, "
1006 "fixing at its maximum."));
1007 log_debug(
"game.info.timeout exceeded maximum value");
1011 }
else if (
game.
info.timeout < 0) {
1013 _(
"The turn timeout is smaller than zero, "
1014 "fixing at zero."));
1015 log_debug(
"game.info.timeout less than zero");
1022 log_debug(
"timeout=%d, inc=%d incmult=%d\n "
1023 "int=%d, intinc=%d, turns till next=%d",
1044 +
static_cast<double>(
game.
server.timeoutaddenemymove));
1046 if (maxsec >
game.
tinfo.seconds_to_phasedone) {
1047 game.
tinfo.seconds_to_phasedone = maxsec;
1080 if (sdir ==
nullptr) {
1086 if (cname ==
nullptr) {
1090 fc_snprintf(fullname,
sizeof(fullname),
"%s/%s", qUtf8Printable(sdir),
1113 struct packet_ruleset_choices packet;
1118 for (
const auto &s : qAsConst(*ruleset_choices)) {
1119 const int maxlen =
sizeof packet.rulesets[i];
1121 qDebug(
"Can't send more than %d ruleset names to client, "
1126 if (
fc_strlcpy(packet.rulesets[i], qUtf8Printable(s), maxlen) < maxlen) {
1129 qDebug(
"Ruleset name '%s' too long to send to client, skipped",
1133 packet.ruleset_count = i;
1135 send_packet_ruleset_choices(pc, &packet);
1137 delete ruleset_choices;
1145 struct connection *pc,
const struct packet_single_want_hack_req *packet)
1148 const char *token =
nullptr;
1149 bool you_have_hack =
false;
1153 you_have_hack = (token && strcmp(token, packet->token) == 0);
1161 log_debug(
"Failed to read authentication token");
1164 if (you_have_hack) {
1168 dsend_packet_single_want_hack_reply(pc, you_have_hack);
bool adv_data_phase_init(struct player *pplayer, bool is_new_phase)
Make and cache lots of calculations needed for other functions.
void adv_data_phase_done(struct player *pplayer)
Clean up our mess.
#define CALL_PLR_AI_FUNC(_func, _player,...)
const char * calendar_text()
Produce a statically allocated textual representation of the current calendar time.
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.
#define conn_list_iterate(connlist, pconn)
#define conn_list_iterate_end
#define MAX_NUM_PLAYER_SLOTS
const struct ft_color ftc_server
const struct ft_color ftc_any
int current_turn_timeout()
Return timeout value for the current turn.
static void gen_challenge_filename(struct connection *pc)
Generate challenge filename for this connection, cannot fail.
const char * new_challenge_filename(struct connection *pc)
Find a file that we can write too, and return it's name.
static const char * get_challenge_fullname(struct connection *pc)
Get challenge full filename for this connection.
void init_new_game()
Initialize a new game: place the players' units onto the map, etc.
void send_scenario_description(struct conn_list *dest)
Send description of the current scenario.
void send_scenario_info(struct conn_list *dest)
Send current scenario info.
struct unit_type * crole_to_unit_type(char crole, struct player *pplayer)
Get unit_type for given role character.
#define team_placement_closest
static const char * get_challenge_filename(struct connection *pc)
Get challenge filename for this connection.
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'.
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.
void send_game_info(struct conn_list *dest)
Send game_info packet; some server options and various stuff...
static void send_ruleset_choices(struct connection *pc)
Call this on a connection with HACK access to send it a set of ruleset choices.
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.
#define startpos_list_iterate_end
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...
void send_year_to_clients()
Tell clients the year, and also update turn_done and nturns_idle fields for all players.
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.
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'.
#define startpos_list_iterate(list, plink, psp)
enum unit_role_id crole_to_role_id(char crole)
Get role_id for given role character.
static struct tile * find_dispersed_position(struct player *pplayer, struct tile *pcenter)
Find a valid position not far from our starting position.
static void team_placement_state_destroy(struct team_placement_state *pstate)
Destroys a team_placement_state structure.
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'.
int update_timeout()
adjusts game.info.timeout based on various server options
#define fc_assert_msg(condition, message,...)
#define fc_assert(condition)
#define fc_assert_ret_msg(condition, message,...)
#define fc_assert_ret_val(condition, val)
#define fc_assert_action(condition, action)
#define log_debug(message,...)
int sq_map_distance(const struct tile *tile0, const struct tile *tile1)
Return squared distance between two tiles.
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.
bool startpos_nation_allowed(const struct startpos *psp, const struct nation_type *pnation)
Returns TRUE if the given nation can start here.
bool startpos_allows_all(const struct startpos *psp)
Returns TRUE if any nation can start here.
int map_startpos_count()
Is there start positions set for map.
struct tile * startpos_tile(const struct startpos *psp)
Returns the tile where this start position is located.
int real_map_distance(const struct tile *tile0, const struct tile *tile1)
Return real distance between two tiles.
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 ...
#define iterate_outward(nmap, start_tile, max_dist, itr_tile)
#define iterate_outward_end
#define index_to_map_pos(pmap_x, pmap_y, mindex)
void map_show_circle(struct player *pplayer, struct tile *ptile, int radius_sq)
Shows the area to the player.
void update_tile_knowledge(struct tile *ptile)
Update playermap knowledge for everybody who sees the tile, and send a packet to everyone whose info ...
bool is_native_tile(const struct unit_type *punittype, const struct tile *ptile)
This tile is native to unit.
const char * nation_rule_name(const struct nation_type *pnation)
Return the (untranslated) rule name of the nation (adjective form).
struct nation_type * nation_of_player(const struct player *pplayer)
Return the nation of a player.
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.
int player_count()
Return the number of players.
int player_index(const struct player *pplayer)
Return the player index.
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
#define players_iterate_end
#define players_iterate(_pplayer)
#define player_list_iterate(playerlist, pplayer)
#define player_list_iterate_end
struct section_file * secfile_load(const QString &filename, bool allow_duplicates)
Create a section file from a file.
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(),...
QString freeciv_storage_dir()
Returns string which gives freeciv storage dir.
struct server_arguments srvarg
QVector< QString > * get_init_script_choices()
Return a list of init scripts found on the data path.
struct civ_game::@28::@32 server
struct packet_scenario_description scenario_desc
struct conn_list * est_connections
struct packet_game_info info
struct packet_scenario_info scenario
struct packet_timeout_info tinfo
struct packet_calendar_info calendar
QHash< struct tile *, struct startpos * > * startpos_table
struct civ_map::@39::@41 server
std::array< unit_type *, MAX_NUM_UNIT_LIST > init_units
int flexible_startpos_num
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
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-...
struct team * team_by_number(const int team_id)
Return struct team pointer for the given team index.
const char * team_rule_name(const struct team *pteam)
Returns the name (untranslated) of the team.
int team_count()
Return the current number of teams.
int team_number(const struct team *pteam)
Return the team index/number/id.
const struct player_list * team_members(const struct team *pteam)
Returns the member list of the team.
#define teams_iterate_end
#define teams_iterate(_pteam)
#define is_ocean_tile(ptile)
bool tile_extra_rm_apply(struct tile *ptile, struct extra_type *tgt)
Remove extra and adjust other extras accordingly.
#define tile_continent(_tile)
#define tile_has_extra(ptile, pextra)
double timer_read_seconds(civtimer *t)
Read value from timer.
struct unit * is_non_allied_unit_tile(const struct tile *ptile, const struct player *pplayer)
Is there an non-allied unit on this tile?
int num_role_units(int role)
How many unit types have specified role/flag.
struct unit_type * get_role_unit(int role, int role_index)
Return index-th unit with specified role/flag.
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.