webperimental: killstack decides stack protects.
[freeciv.git] / server / maphand.c
blobea88dff8c269362ad57ddacbb08206c5b0618d67
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "bitvector.h"
20 #include "fcintl.h"
21 #include "log.h"
22 #include "mem.h"
23 #include "rand.h"
24 #include "support.h"
26 /* common */
27 #include "ai.h"
28 #include "base.h"
29 #include "borders.h"
30 #include "events.h"
31 #include "game.h"
32 #include "map.h"
33 #include "movement.h"
34 #include "nation.h"
35 #include "packets.h"
36 #include "player.h"
37 #include "road.h"
38 #include "unit.h"
39 #include "unitlist.h"
40 #include "vision.h"
42 /* server */
43 #include "citytools.h"
44 #include "cityturn.h"
45 #include "notify.h"
46 #include "plrhand.h"
47 #include "sanitycheck.h"
48 #include "sernet.h"
49 #include "srv_main.h"
50 #include "unithand.h"
51 #include "unittools.h"
53 /* server/generator */
54 #include "mapgen_utils.h"
56 #include "maphand.h"
58 #define MAXIMUM_CLAIMED_OCEAN_SIZE (20)
60 /* Suppress send_tile_info() during game_load() */
61 static bool send_tile_suppressed = FALSE;
63 static void player_tile_init(struct tile *ptile, struct player *pplayer);
64 static void player_tile_free(struct tile *ptile, struct player *pplayer);
65 static void give_tile_info_from_player_to_player(struct player *pfrom,
66 struct player *pdest,
67 struct tile *ptile);
68 static void shared_vision_change_seen(struct player *pplayer,
69 struct tile *ptile,
70 const v_radius_t change,
71 bool can_reveal_tiles);
72 static void map_change_seen(struct player *pplayer,
73 struct tile *ptile,
74 const v_radius_t change,
75 bool can_reveal_tiles);
76 static void map_change_own_seen(struct player *pplayer,
77 struct tile *ptile,
78 const v_radius_t change);
79 static inline int map_get_seen(const struct player *pplayer,
80 const struct tile *ptile,
81 enum vision_layer vlayer);
82 static inline int map_get_own_seen(const struct player *pplayer,
83 const struct tile *ptile,
84 enum vision_layer vlayer);
86 static bool is_claimable_ocean(struct tile *ptile, struct tile *source,
87 struct player *pplayer);
89 /**************************************************************************
90 Used only in global_warming() and nuclear_winter() below.
91 **************************************************************************/
92 static bool is_terrain_ecologically_wet(struct tile *ptile)
94 return (is_terrain_class_near_tile(ptile, TC_OCEAN)
95 || tile_has_river(ptile)
96 || count_river_near_tile(ptile, NULL) > 0);
99 /**************************************************************************
100 Wrapper for climate_change().
101 **************************************************************************/
102 void global_warming(int effect)
104 climate_change(TRUE, effect);
105 notify_player(NULL, NULL, E_GLOBAL_ECO, ftc_server,
106 _("Global warming has occurred!"));
107 notify_player(NULL, NULL, E_GLOBAL_ECO, ftc_server,
108 _("Coastlines have been flooded and vast "
109 "ranges of grassland have become deserts."));
112 /**************************************************************************
113 Wrapper for climate_change().
114 **************************************************************************/
115 void nuclear_winter(int effect)
117 climate_change(FALSE, effect);
118 notify_player(NULL, NULL, E_GLOBAL_ECO, ftc_server,
119 _("Nuclear winter has occurred!"));
120 notify_player(NULL, NULL, E_GLOBAL_ECO, ftc_server,
121 _("Wetlands have dried up and vast "
122 "ranges of grassland have become tundra."));
125 /*****************************************************************************
126 Do a climate change. Global warming occurred if 'warming' is TRUE, else
127 there is a nuclear winter.
128 *****************************************************************************/
129 void climate_change(bool warming, int effect)
131 int k = map_num_tiles();
132 bool used[k];
133 memset(used, 0, sizeof(used));
135 log_verbose("Climate change: %s (%d)",
136 warming ? "Global warming" : "Nuclear winter", effect);
138 while (effect > 0 && (k--) > 0) {
139 struct terrain *old, *candidates[2], *new;
140 struct tile *ptile;
141 int i;
143 do {
144 /* We want to transform a tile at most once due to a climate change. */
145 ptile = rand_map_pos(&(wld.map));
146 } while (used[tile_index(ptile)]);
147 used[tile_index(ptile)] = TRUE;
149 old = tile_terrain(ptile);
150 /* Prefer the transformation that's appropriate to the ambient moisture,
151 * but be prepared to fall back in exceptional circumstances */
153 struct terrain *wetter, *drier;
154 wetter = warming ? old->warmer_wetter_result : old->cooler_wetter_result;
155 drier = warming ? old->warmer_drier_result : old->cooler_drier_result;
156 if (is_terrain_ecologically_wet(ptile)) {
157 candidates[0] = wetter;
158 candidates[1] = drier;
159 } else {
160 candidates[0] = drier;
161 candidates[1] = wetter;
165 /* If the preferred transformation is ruled out for some exceptional reason
166 * specific to this tile, fall back to the other, rather than letting this
167 * tile be immune to change. */
168 for (i=0; i<2; i++) {
169 new = candidates[i];
171 /* If the preferred transformation simply hasn't been specified
172 * for this terrain at all, don't fall back to the other. */
173 if (new == T_NONE) {
174 break;
177 if (tile_city(ptile) != NULL && terrain_has_flag(new, TER_NO_CITIES)) {
178 /* do not change to a terrain with the flag TER_NO_CITIES if the tile
179 * has a city */
180 continue;
183 /* Only change between water and land at coastlines, and between
184 * frozen and unfrozen at ice margin */
185 if (!terrain_surroundings_allow_change(ptile, new)) {
186 continue;
189 /* OK! */
190 break;
192 if (i == 2) {
193 /* Neither transformation was permitted. Give up. */
194 continue;
197 if (new != T_NONE && old != new) {
198 effect--;
200 /* Really change the terrain. */
201 tile_change_terrain(ptile, new);
202 check_terrain_change(ptile, old);
203 update_tile_knowledge(ptile);
205 /* Check the unit activities. */
206 unit_list_iterate(ptile->units, punit) {
207 if (!can_unit_continue_current_activity(punit)) {
208 unit_activity_handling(punit, ACTIVITY_IDLE);
210 } unit_list_iterate_end;
211 } else if (old == new) {
212 /* This counts toward a climate change although nothing is changed. */
213 effect--;
218 /***************************************************************
219 Check city for extra upgrade. Returns whether anything was
220 done.
221 *gained will be set if there's exactly one kind of extra added.
222 ***************************************************************/
223 bool upgrade_city_extras(struct city *pcity, struct extra_type **gained)
225 struct tile *ptile = pcity->tile;
226 struct player *pplayer = city_owner(pcity);
227 bool upgradet = FALSE;
229 extra_type_iterate(pextra) {
230 if (!tile_has_extra(ptile, pextra)) {
231 if (extra_has_flag(pextra, EF_ALWAYS_ON_CITY_CENTER)
232 || (extra_has_flag(pextra, EF_AUTO_ON_CITY_CENTER)
233 && player_can_build_extra(pextra, pplayer, ptile)
234 && !tile_has_conflicting_extra(ptile, pextra))) {
235 tile_add_extra(pcity->tile, pextra);
236 if (gained != NULL) {
237 if (upgradet) {
238 *gained = NULL;
239 } else {
240 *gained = pextra;
243 upgradet = TRUE;
246 } extra_type_iterate_end;
248 return upgradet;
251 /***************************************************************
252 To be called when a player gains some better extra building tech
253 for the first time. Sends a message, and upgrades all city
254 squares to new extras. "discovery" just affects the message: set to
255 1 if the tech is a "discovery",
256 0 if otherwise acquired (conquer/trade/GLib). --dwp
257 ***************************************************************/
258 void upgrade_all_city_extras(struct player *pplayer, bool discovery)
260 int cities_upgradet = 0;
261 struct extra_type *upgradet = NULL;
262 bool multiple_types = FALSE;
263 int cities_total = city_list_size(pplayer->cities);
264 int percent;
266 conn_list_do_buffer(pplayer->connections);
268 city_list_iterate(pplayer->cities, pcity) {
269 struct extra_type *new_upgrade;
271 if (upgrade_city_extras(pcity, &new_upgrade)) {
272 update_tile_knowledge(pcity->tile);
273 cities_upgradet++;
274 if (new_upgrade == NULL) {
275 /* This single city alone had multiple types */
276 multiple_types = TRUE;
277 } else if (upgradet == NULL) {
278 /* First gained */
279 upgradet = new_upgrade;
280 } else if (upgradet != new_upgrade) {
281 /* Different type from what another city got. */
282 multiple_types = TRUE;
285 } city_list_iterate_end;
287 if (cities_total > 0) {
288 percent = cities_upgradet * 100 / cities_total;
289 } else {
290 percent = 0;
293 if (cities_upgradet > 0) {
294 if (discovery) {
295 if (percent >= 75) {
296 notify_player(pplayer, NULL, E_TECH_GAIN, ftc_server,
297 _("New hope sweeps like fire through the country as "
298 "the discovery of new infrastructure building technology "
299 "is announced."));
301 } else {
302 if (percent >= 75) {
303 notify_player(pplayer, NULL, E_TECH_GAIN, ftc_server,
304 _("The people are pleased to hear that your "
305 "scientists finally know about new infrastructure building "
306 "technology."));
310 if (multiple_types) {
311 notify_player(pplayer, NULL, E_TECH_GAIN, ftc_server,
312 _("Workers spontaneously gather and upgrade all "
313 "possible cities with better infrastructure."));
314 } else {
315 notify_player(pplayer, NULL, E_TECH_GAIN, ftc_server,
316 _("Workers spontaneously gather and upgrade all "
317 "possible cities with %s."), extra_name_translation(upgradet));
321 conn_list_do_unbuffer(pplayer->connections);
324 /**************************************************************************
325 Return TRUE iff the player me really gives shared vision to player them.
326 **************************************************************************/
327 bool really_gives_vision(struct player *me, struct player *them)
329 return BV_ISSET(me->server.really_gives_vision, player_index(them));
332 /**************************************************************************
333 Start buffering shared vision
334 **************************************************************************/
335 static void buffer_shared_vision(struct player *pplayer)
337 players_iterate(pplayer2) {
338 if (really_gives_vision(pplayer, pplayer2)) {
339 conn_list_compression_freeze(pplayer2->connections);
340 conn_list_do_buffer(pplayer2->connections);
342 } players_iterate_end;
343 conn_list_compression_freeze(pplayer->connections);
344 conn_list_do_buffer(pplayer->connections);
347 /**************************************************************************
348 Stop buffering shared vision
349 **************************************************************************/
350 static void unbuffer_shared_vision(struct player *pplayer)
352 players_iterate(pplayer2) {
353 if (really_gives_vision(pplayer, pplayer2)) {
354 conn_list_do_unbuffer(pplayer2->connections);
355 conn_list_compression_thaw(pplayer2->connections);
357 } players_iterate_end;
358 conn_list_do_unbuffer(pplayer->connections);
359 conn_list_compression_thaw(pplayer->connections);
362 /**************************************************************************
363 Give information about whole map (all tiles) from player to player.
364 **************************************************************************/
365 void give_map_from_player_to_player(struct player *pfrom, struct player *pdest)
367 buffer_shared_vision(pdest);
369 whole_map_iterate(&(wld.map), ptile) {
370 give_tile_info_from_player_to_player(pfrom, pdest, ptile);
371 } whole_map_iterate_end;
373 unbuffer_shared_vision(pdest);
374 city_thaw_workers_queue();
375 sync_cities();
378 /**************************************************************************
379 Give information about all oceanic tiles from player to player
380 **************************************************************************/
381 void give_seamap_from_player_to_player(struct player *pfrom, struct player *pdest)
383 buffer_shared_vision(pdest);
385 whole_map_iterate(&(wld.map), ptile) {
386 if (is_ocean_tile(ptile)) {
387 give_tile_info_from_player_to_player(pfrom, pdest, ptile);
389 } whole_map_iterate_end;
391 unbuffer_shared_vision(pdest);
392 city_thaw_workers_queue();
393 sync_cities();
396 /**************************************************************************
397 Give information about tiles within city radius from player to player
398 **************************************************************************/
399 void give_citymap_from_player_to_player(struct city *pcity,
400 struct player *pfrom, struct player *pdest)
402 struct tile *pcenter = city_tile(pcity);
404 buffer_shared_vision(pdest);
406 city_tile_iterate(city_map_radius_sq_get(pcity), pcenter, ptile) {
407 give_tile_info_from_player_to_player(pfrom, pdest, ptile);
408 } city_tile_iterate_end;
410 unbuffer_shared_vision(pdest);
411 city_thaw_workers_queue();
412 sync_cities();
415 /**************************************************************************
416 Send all tiles known to specified clients.
417 If dest is NULL means game.est_connections.
419 Note for multiple connections this may change "sent" multiple times
420 for single player. This is ok, because "sent" data is just optimised
421 calculations, so it will be correct before this, for each connection
422 during this, and at end.
423 **************************************************************************/
424 void send_all_known_tiles(struct conn_list *dest)
426 int tiles_sent;
428 if (!dest) {
429 dest = game.est_connections;
432 /* send whole map piece by piece to each player to balance the load
433 of the send buffers better */
434 tiles_sent = 0;
435 conn_list_do_buffer(dest);
437 whole_map_iterate(&(wld.map), ptile) {
438 tiles_sent++;
439 if ((tiles_sent % wld.map.xsize) == 0) {
440 conn_list_do_unbuffer(dest);
441 flush_packets();
442 conn_list_do_buffer(dest);
445 send_tile_info(dest, ptile, FALSE);
446 } whole_map_iterate_end;
448 conn_list_do_unbuffer(dest);
449 flush_packets();
452 /**************************************************************************
453 Suppress send_tile_info() during game_load()
454 **************************************************************************/
455 bool send_tile_suppression(bool now)
457 bool formerly = send_tile_suppressed;
459 send_tile_suppressed = now;
460 return formerly;
463 /**************************************************************************
464 Send tile information to all the clients in dest which know and see
465 the tile. If dest is NULL, sends to all clients (game.est_connections)
466 which know and see tile.
468 Note that this function does not update the playermap. For that call
469 update_tile_knowledge().
470 **************************************************************************/
471 void send_tile_info(struct conn_list *dest, struct tile *ptile,
472 bool send_unknown)
474 struct packet_tile_info info;
475 const struct player *owner;
476 const struct player *eowner;
478 if (dest == NULL) {
479 CALL_FUNC_EACH_AI(tile_info, ptile);
482 if (send_tile_suppressed) {
483 return;
486 if (!dest) {
487 dest = game.est_connections;
490 info.tile = tile_index(ptile);
492 if (ptile->spec_sprite) {
493 sz_strlcpy(info.spec_sprite, ptile->spec_sprite);
494 } else {
495 info.spec_sprite[0] = '\0';
498 conn_list_iterate(dest, pconn) {
499 struct player *pplayer = pconn->playing;
501 if (NULL == pplayer && !pconn->observer) {
502 continue;
505 if (!pplayer || map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
506 info.known = TILE_KNOWN_SEEN;
507 info.continent = tile_continent(ptile);
508 owner = tile_owner(ptile);
509 eowner = extra_owner(ptile);
510 info.owner = (owner ? player_number(owner) : MAP_TILE_OWNER_NULL);
511 info.extras_owner = (eowner ? player_number(eowner) : MAP_TILE_OWNER_NULL);
512 info.worked = (NULL != tile_worked(ptile))
513 ? tile_worked(ptile)->id
514 : IDENTITY_NUMBER_ZERO;
516 info.terrain = (NULL != tile_terrain(ptile))
517 ? terrain_number(tile_terrain(ptile))
518 : terrain_count();
519 info.resource = (NULL != tile_resource(ptile))
520 ? extra_number(tile_resource(ptile))
521 : extra_count();
523 if (pplayer != NULL) {
524 info.extras = map_get_player_tile(ptile, pplayer)->extras;
525 } else {
526 info.extras = ptile->extras;
529 if (ptile->label != NULL) {
530 strncpy(info.label, ptile->label, sizeof(info.label));
531 } else {
532 info.label[0] = '\0';
535 send_packet_tile_info(pconn, &info);
536 } else if (pplayer && map_is_known(ptile, pplayer)) {
537 struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
538 struct vision_site *psite = map_get_player_site(ptile, pplayer);
540 info.known = TILE_KNOWN_UNSEEN;
541 info.continent = tile_continent(ptile);
542 owner = (game.server.foggedborders
543 ? plrtile->owner
544 : tile_owner(ptile));
545 eowner = plrtile->extras_owner;
546 info.owner = (owner ? player_number(owner) : MAP_TILE_OWNER_NULL);
547 info.extras_owner = (eowner ? player_number(eowner) : MAP_TILE_OWNER_NULL);
548 info.worked = (NULL != psite)
549 ? psite->identity
550 : IDENTITY_NUMBER_ZERO;
552 info.terrain = (NULL != plrtile->terrain)
553 ? terrain_number(plrtile->terrain)
554 : terrain_count();
555 info.resource = (NULL != plrtile->resource)
556 ? extra_number(plrtile->resource)
557 : extra_count();
559 info.extras = plrtile->extras;
561 /* Labels never change, so they are not subject to fog of war */
562 if (ptile->label != NULL) {
563 strncpy(info.label, ptile->label, sizeof(info.label));
564 } else {
565 info.label[0] = '\0';
568 send_packet_tile_info(pconn, &info);
569 } else if (send_unknown) {
570 info.known = TILE_UNKNOWN;
571 info.continent = 0;
572 info.owner = MAP_TILE_OWNER_NULL;
573 info.extras_owner = MAP_TILE_OWNER_NULL;
574 info.worked = IDENTITY_NUMBER_ZERO;
576 info.terrain = terrain_count();
577 info.resource = extra_count();
579 BV_CLR_ALL(info.extras);
581 info.label[0] = '\0';
583 send_packet_tile_info(pconn, &info);
586 conn_list_iterate_end;
589 /****************************************************************************
590 Assumption: Each unit type is visible on only one layer.
591 ****************************************************************************/
592 static bool unit_is_visible_on_layer(const struct unit *punit,
593 enum vision_layer vlayer)
595 return XOR(vlayer == V_MAIN, is_hiding_unit(punit));
598 /**************************************************************************
599 Send basic map information: map size, topology, and is_earth.
600 **************************************************************************/
601 void send_map_info(struct conn_list *dest)
603 struct packet_map_info minfo;
605 minfo.xsize = wld.map.xsize;
606 minfo.ysize = wld.map.ysize;
607 minfo.topology_id = wld.map.topology_id;
609 lsend_packet_map_info(dest, &minfo);
612 /****************************************************************************
613 Change the seen count of a tile for a pplayer. It will automatically
614 handle the shared visions.
615 ****************************************************************************/
616 static void shared_vision_change_seen(struct player *pplayer,
617 struct tile *ptile,
618 const v_radius_t change,
619 bool can_reveal_tiles)
621 map_change_own_seen(pplayer, ptile, change);
622 map_change_seen(pplayer, ptile, change, can_reveal_tiles);
624 players_iterate(pplayer2) {
625 if (really_gives_vision(pplayer, pplayer2)) {
626 map_change_seen(pplayer2, ptile, change, can_reveal_tiles);
628 } players_iterate_end;
631 /**************************************************************************
632 There doesn't have to be a city.
633 **************************************************************************/
634 void map_vision_update(struct player *pplayer, struct tile *ptile,
635 const v_radius_t old_radius_sq,
636 const v_radius_t new_radius_sq,
637 bool can_reveal_tiles)
639 v_radius_t change;
640 int max_radius;
642 if (old_radius_sq[V_MAIN] == new_radius_sq[V_MAIN]
643 && old_radius_sq[V_INVIS] == new_radius_sq[V_INVIS]) {
644 return;
647 /* Determines 'max_radius' value. */
648 max_radius = 0;
649 vision_layer_iterate(v) {
650 if (max_radius < old_radius_sq[v]) {
651 max_radius = old_radius_sq[v];
653 if (max_radius < new_radius_sq[v]) {
654 max_radius = new_radius_sq[v];
656 } vision_layer_iterate_end;
658 #ifdef FREECIV_DEBUG
659 log_debug("Updating vision at (%d, %d) in a radius of %d.",
660 TILE_XY(ptile), max_radius);
661 vision_layer_iterate(v) {
662 log_debug(" vision layer %d is changing from %d to %d.",
663 v, old_radius_sq[v], new_radius_sq[v]);
664 } vision_layer_iterate_end;
665 #endif /* FREECIV_DEBUG */
667 buffer_shared_vision(pplayer);
668 circle_dxyr_iterate(&(wld.map), ptile, max_radius, tile1, dx, dy, dr) {
669 vision_layer_iterate(v) {
670 if (dr > old_radius_sq[v] && dr <= new_radius_sq[v]) {
671 change[v] = 1;
672 } else if (dr > new_radius_sq[v] && dr <= old_radius_sq[v]) {
673 change[v] = -1;
674 } else {
675 change[v] = 0;
677 } vision_layer_iterate_end;
678 shared_vision_change_seen(pplayer, tile1, change, can_reveal_tiles);
679 } circle_dxyr_iterate_end;
680 unbuffer_shared_vision(pplayer);
683 /**************************************************************************
684 Turn a players ability to see inside his borders on or off.
686 It is safe to set the current value.
687 **************************************************************************/
688 void map_set_border_vision(struct player *pplayer,
689 const bool is_enabled)
691 const v_radius_t radius_sq = V_RADIUS(is_enabled ? 1 : -1, 0);
693 if (pplayer->server.border_vision == is_enabled) {
694 /* No change. Changing the seen count beyond what already exists would
695 * be a bug. */
696 return;
699 /* Set the new border seer value. */
700 pplayer->server.border_vision = is_enabled;
702 whole_map_iterate(&(wld.map), ptile) {
703 if (pplayer == ptile->owner) {
704 /* The tile is within the player's borders. */
705 shared_vision_change_seen(pplayer, ptile, radius_sq, TRUE);
707 } whole_map_iterate_end;
710 /****************************************************************************
711 Shows the area to the player. Unless the tile is "seen", it will remain
712 fogged and units will be hidden.
714 Callers may wish to buffer_shared_vision before calling this function.
715 ****************************************************************************/
716 void map_show_tile(struct player *src_player, struct tile *ptile)
718 static int recurse = 0;
720 log_debug("Showing %i,%i to %s", TILE_XY(ptile), player_name(src_player));
722 fc_assert(recurse == 0);
723 recurse++;
725 players_iterate(pplayer) {
726 if (pplayer == src_player || really_gives_vision(src_player, pplayer)) {
727 struct city *pcity;
729 if (!map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
730 map_set_known(ptile, pplayer);
732 /* as the tile may be fogged send_tile_info won't always do this for us */
733 update_player_tile_knowledge(pplayer, ptile);
734 update_player_tile_last_seen(pplayer, ptile);
736 send_tile_info(pplayer->connections, ptile, FALSE);
738 /* remove old cities that exist no more */
739 reality_check_city(pplayer, ptile);
741 if ((pcity = tile_city(ptile))) {
742 /* as the tile may be fogged send_city_info won't do this for us */
743 update_dumb_city(pplayer, pcity);
744 send_city_info(pplayer, pcity);
747 vision_layer_iterate(v) {
748 if (0 < map_get_seen(pplayer, ptile, v)) {
749 unit_list_iterate(ptile->units, punit) {
750 if (unit_is_visible_on_layer(punit, v)) {
751 send_unit_info(pplayer->connections, punit);
753 } unit_list_iterate_end;
755 } vision_layer_iterate_end;
758 } players_iterate_end;
760 recurse--;
763 /****************************************************************************
764 Hides the area to the player.
766 Callers may wish to buffer_shared_vision before calling this function.
767 ****************************************************************************/
768 void map_hide_tile(struct player *src_player, struct tile *ptile)
770 static int recurse = 0;
772 log_debug("Hiding %d,%d to %s", TILE_XY(ptile), player_name(src_player));
774 fc_assert(recurse == 0);
775 recurse++;
777 players_iterate(pplayer) {
778 if (pplayer == src_player || really_gives_vision(src_player, pplayer)) {
779 if (map_is_known(ptile, pplayer)) {
780 if (0 < map_get_seen(pplayer, ptile, V_MAIN)) {
781 update_player_tile_last_seen(pplayer, ptile);
784 /* Remove city. */
785 remove_dumb_city(pplayer, ptile);
787 /* Remove units. */
788 vision_layer_iterate(v) {
789 if (0 < map_get_seen(pplayer, ptile, v)) {
790 unit_list_iterate(ptile->units, punit) {
791 if (unit_is_visible_on_layer(punit, v)) {
792 unit_goes_out_of_sight(pplayer, punit);
794 } unit_list_iterate_end;
796 } vision_layer_iterate_end;
799 map_clear_known(ptile, pplayer);
801 send_tile_info(pplayer->connections, ptile, TRUE);
803 } players_iterate_end;
805 recurse--;
808 /****************************************************************************
809 Shows the area to the player. Unless the tile is "seen", it will remain
810 fogged and units will be hidden.
811 ****************************************************************************/
812 void map_show_circle(struct player *pplayer, struct tile *ptile, int radius_sq)
814 buffer_shared_vision(pplayer);
816 circle_iterate(&(wld.map), ptile, radius_sq, tile1) {
817 map_show_tile(pplayer, tile1);
818 } circle_iterate_end;
820 unbuffer_shared_vision(pplayer);
823 /****************************************************************************
824 Shows the area to the player. Unless the tile is "seen", it will remain
825 fogged and units will be hidden.
826 ****************************************************************************/
827 void map_show_all(struct player *pplayer)
829 buffer_shared_vision(pplayer);
831 whole_map_iterate(&(wld.map), ptile) {
832 map_show_tile(pplayer, ptile);
833 } whole_map_iterate_end;
835 unbuffer_shared_vision(pplayer);
838 /****************************************************************************
839 Return whether the player knows the tile. Knowing a tile means you've
840 seen it once (as opposed to seeing a tile which means you can see it now).
841 ****************************************************************************/
842 bool map_is_known(const struct tile *ptile, const struct player *pplayer)
844 return dbv_isset(&pplayer->tile_known, tile_index(ptile));
847 /****************************************************************************
848 Returns whether the layer 'vlayer' of the tile 'ptile' is known and seen
849 by the player 'pplayer'.
850 ****************************************************************************/
851 bool map_is_known_and_seen(const struct tile *ptile,
852 const struct player *pplayer,
853 enum vision_layer vlayer)
855 return (map_is_known(ptile, pplayer)
856 && 0 < map_get_seen(pplayer, ptile, vlayer));
859 /****************************************************************************
860 Return whether the player can see the tile. Seeing a tile means you have
861 vision of it now (as opposed to knowing a tile which means you've seen it
862 before). Note that a tile can be seen but not known (currently this only
863 happens when a city is founded with some unknown tiles in its radius); in
864 this case the tile is unknown (but map_get_seen will still return TRUE).
865 ****************************************************************************/
866 static inline int map_get_seen(const struct player *pplayer,
867 const struct tile *ptile,
868 enum vision_layer vlayer)
870 return map_get_player_tile(ptile, pplayer)->seen_count[vlayer];
873 /****************************************************************************
874 This function changes the seen state of one player for all vision layers
875 of a tile. It reveals the tiles if needed and controls the fog of war.
877 See also map_change_own_seen(), shared_vision_change_seen().
878 ****************************************************************************/
879 void map_change_seen(struct player *pplayer,
880 struct tile *ptile,
881 const v_radius_t change,
882 bool can_reveal_tiles)
884 struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
885 bool revealing_tile = FALSE;
887 #ifdef FREECIV_DEBUG
888 log_debug("%s() for player %s (nb %d) at (%d, %d).",
889 __FUNCTION__, player_name(pplayer), player_number(pplayer),
890 TILE_XY(ptile));
891 vision_layer_iterate(v) {
892 log_debug(" vision layer %d is changing from %d to %d.",
893 v, plrtile->seen_count[v], plrtile->seen_count[v] + change[v]);
894 } vision_layer_iterate_end;
895 #endif /* FREECIV_DEBUG */
897 /* Removes units out of vision. First, check V_INVIS layer because
898 * we must remove all units before fog of war because clients expect
899 * the tile is empty when it is fogged. */
900 if (0 > change[V_INVIS]
901 && plrtile->seen_count[V_INVIS] == -change[V_INVIS]) {
902 log_debug("(%d, %d): hiding invisible units to player %s (nb %d).",
903 TILE_XY(ptile), player_name(pplayer), player_number(pplayer));
905 unit_list_iterate(ptile->units, punit) {
906 if (unit_is_visible_on_layer(punit, V_INVIS)
907 && can_player_see_unit(pplayer, punit)) {
908 unit_goes_out_of_sight(pplayer, punit);
910 } unit_list_iterate_end;
913 if (0 > change[V_MAIN]
914 && plrtile->seen_count[V_MAIN] == -change[V_MAIN]) {
915 log_debug("(%d, %d): hiding visible units to player %s (nb %d).",
916 TILE_XY(ptile), player_name(pplayer), player_number(pplayer));
918 unit_list_iterate(ptile->units, punit) {
919 if (unit_is_visible_on_layer(punit, V_MAIN)
920 && can_player_see_unit(pplayer, punit)) {
921 unit_goes_out_of_sight(pplayer, punit);
923 } unit_list_iterate_end;
926 vision_layer_iterate(v) {
927 /* Avoid underflow. */
928 fc_assert(0 <= change[v] || -change[v] <= plrtile->seen_count[v]);
929 plrtile->seen_count[v] += change[v];
930 } vision_layer_iterate_end;
932 /* V_MAIN vision ranges must always be more than V_INVIS ranges
933 * (see comment in common/vision.h), so we assume that the V_MAIN
934 * seen count cannot be inferior to V_INVIS seen count.
935 * Moreover, when the fog of war is disabled, V_MAIN has an extra
936 * seen count point. */
937 fc_assert(plrtile->seen_count[V_INVIS] + !game.info.fogofwar
938 <= plrtile->seen_count[V_MAIN]);
940 if (!map_is_known(ptile, pplayer)) {
941 if (0 < plrtile->seen_count[V_MAIN] && can_reveal_tiles) {
942 log_debug("(%d, %d): revealing tile to player %s (nb %d).",
943 TILE_XY(ptile), player_name(pplayer),
944 player_number(pplayer));
946 map_set_known(ptile, pplayer);
947 revealing_tile = TRUE;
948 } else {
949 return;
953 /* Fog the tile. */
954 if (0 > change[V_MAIN] && 0 == plrtile->seen_count[V_MAIN]) {
955 log_debug("(%d, %d): fogging tile for player %s (nb %d).",
956 TILE_XY(ptile), player_name(pplayer), player_number(pplayer));
958 update_player_tile_last_seen(pplayer, ptile);
959 if (game.server.foggedborders) {
960 plrtile->owner = tile_owner(ptile);
962 plrtile->extras_owner = extra_owner(ptile);
963 send_tile_info(pplayer->connections, ptile, FALSE);
966 if ((revealing_tile && 0 < plrtile->seen_count[V_MAIN])
967 || (0 < change[V_MAIN]
968 /* plrtile->seen_count[V_MAIN] Always set to 1
969 * when the fog of war is disabled. */
970 && (change[V_MAIN] + !game.info.fogofwar
971 == (plrtile->seen_count[V_MAIN])))) {
972 struct city *pcity;
974 log_debug("(%d, %d): unfogging tile for player %s (nb %d).",
975 TILE_XY(ptile), player_name(pplayer), player_number(pplayer));
977 /* Send info about the tile itself.
978 * It has to be sent first because the client needs correct
979 * continent number before it can handle following packets
981 update_player_tile_knowledge(pplayer, ptile);
982 send_tile_info(pplayer->connections, ptile, FALSE);
984 /* Discover units. */
985 unit_list_iterate(ptile->units, punit) {
986 if (unit_is_visible_on_layer(punit, V_MAIN)) {
987 send_unit_info(pplayer->connections, punit);
989 } unit_list_iterate_end;
991 /* Discover cities. */
992 reality_check_city(pplayer, ptile);
994 if (NULL != (pcity = tile_city(ptile))) {
995 send_city_info(pplayer, pcity);
999 if ((revealing_tile && 0 < plrtile->seen_count[V_INVIS])
1000 || (0 < change[V_INVIS]
1001 && change[V_INVIS] == plrtile->seen_count[V_INVIS])) {
1002 log_debug("(%d, %d): revealing invisible units to player %s (nb %d).",
1003 TILE_XY(ptile), player_name(pplayer),
1004 player_number(pplayer));
1005 /* Discover units. */
1006 unit_list_iterate(ptile->units, punit) {
1007 if (unit_is_visible_on_layer(punit, V_INVIS)) {
1008 send_unit_info(pplayer->connections, punit);
1010 } unit_list_iterate_end;
1014 /****************************************************************************
1015 Returns the own seen count of a tile for a player. It doesn't count the
1016 shared vision.
1018 See also map_get_seen().
1019 ****************************************************************************/
1020 static inline int map_get_own_seen(const struct player *pplayer,
1021 const struct tile *ptile,
1022 enum vision_layer vlayer)
1024 return map_get_player_tile(ptile, pplayer)->own_seen[vlayer];
1027 /***************************************************************
1028 Changes the own seen count of a tile for a player.
1029 ***************************************************************/
1030 static void map_change_own_seen(struct player *pplayer,
1031 struct tile *ptile,
1032 const v_radius_t change)
1034 struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1036 vision_layer_iterate(v) {
1037 plrtile->own_seen[v] += change[v];
1038 } vision_layer_iterate_end;
1041 /***************************************************************
1042 Changes site information for player tile.
1043 ***************************************************************/
1044 void change_playertile_site(struct player_tile *ptile,
1045 struct vision_site *new_site)
1047 if (ptile->site == new_site) {
1048 /* Do nothing. */
1049 return;
1052 if (ptile->site != NULL) {
1053 /* Releasing old site from tile */
1054 vision_site_destroy(ptile->site);
1057 ptile->site = new_site;
1060 /***************************************************************
1061 Set known status of the tile.
1062 ***************************************************************/
1063 void map_set_known(struct tile *ptile, struct player *pplayer)
1065 dbv_set(&pplayer->tile_known, tile_index(ptile));
1068 /***************************************************************
1069 Clear known status of the tile.
1070 ***************************************************************/
1071 void map_clear_known(struct tile *ptile, struct player *pplayer)
1073 dbv_clr(&pplayer->tile_known, tile_index(ptile));
1076 /****************************************************************************
1077 Call this function to unfog all tiles. This should only be called when
1078 a player dies or at the end of the game as it will result in permanent
1079 vision of the whole map.
1080 ****************************************************************************/
1081 void map_know_and_see_all(struct player *pplayer)
1083 const v_radius_t radius_sq = V_RADIUS(1, 1);
1085 buffer_shared_vision(pplayer);
1086 whole_map_iterate(&(wld.map), ptile) {
1087 map_change_seen(pplayer, ptile, radius_sq, TRUE);
1088 } whole_map_iterate_end;
1089 unbuffer_shared_vision(pplayer);
1092 /**************************************************************************
1093 Unfogs all tiles for all players. See map_know_and_see_all.
1094 **************************************************************************/
1095 void show_map_to_all(void)
1097 players_iterate(pplayer) {
1098 map_know_and_see_all(pplayer);
1099 } players_iterate_end;
1102 /***************************************************************
1103 Allocate space for map, and initialise the tiles.
1104 Uses current map.xsize and map.ysize.
1105 ****************************************************************/
1106 void player_map_init(struct player *pplayer)
1108 pplayer->server.private_map
1109 = fc_realloc(pplayer->server.private_map,
1110 MAP_INDEX_SIZE * sizeof(*pplayer->server.private_map));
1112 whole_map_iterate(&(wld.map), ptile) {
1113 player_tile_init(ptile, pplayer);
1114 } whole_map_iterate_end;
1116 dbv_init(&pplayer->tile_known, MAP_INDEX_SIZE);
1119 /**************************************************************************
1120 Free a player's private map.
1121 **************************************************************************/
1122 void player_map_free(struct player *pplayer)
1124 if (!pplayer->server.private_map) {
1125 return;
1128 whole_map_iterate(&(wld.map), ptile) {
1129 player_tile_free(ptile, pplayer);
1130 } whole_map_iterate_end;
1132 free(pplayer->server.private_map);
1133 pplayer->server.private_map = NULL;
1135 dbv_free(&pplayer->tile_known);
1138 /**************************************************************************
1139 Remove all knowledge of a player from main map and other players'
1140 private maps, and send updates to connected clients.
1141 Frees all vision_sites associated with that player.
1142 **************************************************************************/
1143 void remove_player_from_maps(struct player *pplayer)
1145 /* only after removing borders! */
1146 conn_list_do_buffer(game.est_connections);
1147 whole_map_iterate(&(wld.map), ptile) {
1148 /* Clear all players' knowledge about the removed player, and free
1149 * data structures (including those in removed player's player map). */
1150 bool reality_changed = FALSE;
1152 players_iterate(aplayer) {
1153 struct player_tile *aplrtile;
1154 bool changed = FALSE;
1156 if (!aplayer->server.private_map) {
1157 continue;
1159 aplrtile = map_get_player_tile(ptile, aplayer);
1161 /* Free vision sites (cities) for removed and other players */
1162 if (aplrtile && aplrtile->site &&
1163 vision_site_owner(aplrtile->site) == pplayer) {
1164 change_playertile_site(aplrtile, NULL);
1165 changed = TRUE;
1168 /* Remove references to player from others' maps */
1169 if (aplrtile->owner == pplayer) {
1170 aplrtile->owner = NULL;
1171 changed = TRUE;
1173 if (aplrtile->extras_owner == pplayer) {
1174 aplrtile->extras_owner = NULL;
1175 changed = TRUE;
1178 /* Must ensure references to dying player are gone from clients
1179 * before player is destroyed */
1180 if (changed) {
1181 /* This will use player tile if fogged */
1182 send_tile_info(pplayer->connections, ptile, FALSE);
1184 } players_iterate_end;
1186 /* Clear removed player's knowledge */
1187 if (pplayer->tile_known.vec) {
1188 map_clear_known(ptile, pplayer);
1191 /* Free all claimed tiles. */
1192 if (tile_owner(ptile) == pplayer) {
1193 tile_set_owner(ptile, NULL, NULL);
1194 reality_changed = TRUE;
1196 if (extra_owner(ptile) == pplayer) {
1197 ptile->extras_owner = NULL;
1198 reality_changed = TRUE;
1201 if (reality_changed) {
1202 /* Update anyone who can see the tile (e.g. global observers) */
1203 send_tile_info(NULL, ptile, FALSE);
1205 } whole_map_iterate_end;
1206 conn_list_do_unbuffer(game.est_connections);
1209 /***************************************************************
1210 We need to use fogofwar_old here, so the player's tiles get
1211 in the same state as the other players' tiles.
1212 ***************************************************************/
1213 static void player_tile_init(struct tile *ptile, struct player *pplayer)
1215 struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1217 plrtile->terrain = T_UNKNOWN;
1218 plrtile->resource = NULL;
1219 plrtile->owner = NULL;
1220 plrtile->extras_owner = NULL;
1221 plrtile->site = NULL;
1222 BV_CLR_ALL(plrtile->extras);
1223 if (!game.server.last_updated_year) {
1224 plrtile->last_updated = game.info.turn;
1225 } else {
1226 plrtile->last_updated = game.info.year;
1229 plrtile->seen_count[V_MAIN] = !game.server.fogofwar_old;
1230 plrtile->seen_count[V_INVIS] = 0;
1231 memcpy(plrtile->own_seen, plrtile->seen_count, sizeof(v_radius_t));
1234 /****************************************************************************
1235 Free the memory stored into the player tile.
1236 ****************************************************************************/
1237 static void player_tile_free(struct tile *ptile, struct player *pplayer)
1239 struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1241 if (plrtile->site != NULL) {
1242 vision_site_destroy(plrtile->site);
1246 /****************************************************************************
1247 Returns city located at given tile from player map.
1248 ****************************************************************************/
1249 struct vision_site *map_get_player_city(const struct tile *ptile,
1250 const struct player *pplayer)
1252 struct vision_site *psite = map_get_player_site(ptile, pplayer);
1254 fc_assert_ret_val(psite == NULL || psite->location == ptile, NULL);
1256 return psite;
1259 /****************************************************************************
1260 Returns site located at given tile from player map.
1261 ****************************************************************************/
1262 struct vision_site *map_get_player_site(const struct tile *ptile,
1263 const struct player *pplayer)
1265 return map_get_player_tile(ptile, pplayer)->site;
1268 /****************************************************************************
1269 Players' information of tiles is tracked so that fogged area can be kept
1270 consistent even when the client disconnects. This function returns the
1271 player tile information for the given tile and player.
1272 ****************************************************************************/
1273 struct player_tile *map_get_player_tile(const struct tile *ptile,
1274 const struct player *pplayer)
1276 fc_assert_ret_val(pplayer->server.private_map, NULL);
1278 return pplayer->server.private_map + tile_index(ptile);
1281 /****************************************************************************
1282 Give pplayer the correct knowledge about tile; return TRUE iff
1283 knowledge changed.
1285 Note that unlike update_tile_knowledge, this function will not send any
1286 packets to the client. Callers may want to call send_tile_info() if this
1287 function returns TRUE.
1288 ****************************************************************************/
1289 bool update_player_tile_knowledge(struct player *pplayer, struct tile *ptile)
1291 struct player_tile *plrtile = map_get_player_tile(ptile, pplayer);
1292 bool plrtile_owner_valid = game.server.foggedborders
1293 && !map_is_known_and_seen(ptile, pplayer, V_MAIN);
1294 struct player *owner = plrtile_owner_valid
1295 ? plrtile->owner
1296 : tile_owner(ptile);
1298 if (plrtile->terrain != ptile->terrain
1299 || !BV_ARE_EQUAL(plrtile->extras, ptile->extras)
1300 || plrtile->resource != ptile->resource
1301 || owner != tile_owner(ptile)
1302 || plrtile->extras_owner != extra_owner(ptile)) {
1303 plrtile->terrain = ptile->terrain;
1304 extra_type_iterate(pextra) {
1305 if (player_knows_extra_exist(pplayer, pextra, ptile)) {
1306 BV_SET(plrtile->extras, extra_number(pextra));
1307 } else {
1308 BV_CLR(plrtile->extras, extra_number(pextra));
1310 } extra_type_iterate_end;
1311 plrtile->resource = ptile->resource;
1312 if (plrtile_owner_valid) {
1313 plrtile->owner = tile_owner(ptile);
1315 plrtile->extras_owner = extra_owner(ptile);
1317 return TRUE;
1320 return FALSE;
1323 /****************************************************************************
1324 Update playermap knowledge for everybody who sees the tile, and send a
1325 packet to everyone whose info is changed.
1327 Note this only checks for changing of the terrain, special, or resource
1328 for the tile, since these are the only values held in the playermap.
1330 A tile's owner always can see terrain changes in his or her territory.
1331 ****************************************************************************/
1332 void update_tile_knowledge(struct tile *ptile)
1334 /* Players */
1335 players_iterate(pplayer) {
1336 if (map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
1337 if (update_player_tile_knowledge(pplayer, ptile)) {
1338 send_tile_info(pplayer->connections, ptile, FALSE);
1341 } players_iterate_end;
1343 /* Global observers */
1344 conn_list_iterate(game.est_connections, pconn) {
1345 struct player *pplayer = pconn->playing;
1347 if (NULL == pplayer && pconn->observer) {
1348 send_tile_info(pconn->self, ptile, FALSE);
1350 } conn_list_iterate_end;
1353 /***************************************************************
1354 Remember that tile was last seen this year.
1355 ***************************************************************/
1356 void update_player_tile_last_seen(struct player *pplayer,
1357 struct tile *ptile)
1359 if (!game.server.last_updated_year) {
1360 map_get_player_tile(ptile, pplayer)->last_updated = game.info.turn;
1361 } else {
1362 map_get_player_tile(ptile, pplayer)->last_updated = game.info.year;
1366 /***************************************************************
1367 Give tile information from one player to one player.
1368 ***************************************************************/
1369 static void really_give_tile_info_from_player_to_player(struct player *pfrom,
1370 struct player *pdest,
1371 struct tile *ptile)
1373 struct player_tile *from_tile, *dest_tile;
1374 if (!map_is_known_and_seen(ptile, pdest, V_MAIN)) {
1375 /* I can just hear people scream as they try to comprehend this if :).
1376 * Let me try in words:
1377 * 1) if the tile is seen by pfrom the info is sent to pdest
1378 * OR
1379 * 2) if the tile is known by pfrom AND (he has more recent info
1380 * OR it is not known by pdest)
1382 if (map_is_known_and_seen(ptile, pfrom, V_MAIN)
1383 || (map_is_known(ptile, pfrom)
1384 && (((map_get_player_tile(ptile, pfrom)->last_updated
1385 > map_get_player_tile(ptile, pdest)->last_updated))
1386 || !map_is_known(ptile, pdest)))) {
1387 from_tile = map_get_player_tile(ptile, pfrom);
1388 dest_tile = map_get_player_tile(ptile, pdest);
1389 /* Update and send tile knowledge */
1390 map_set_known(ptile, pdest);
1391 dest_tile->terrain = from_tile->terrain;
1392 dest_tile->extras = from_tile->extras;
1393 dest_tile->resource = from_tile->resource;
1394 dest_tile->owner = from_tile->owner;
1395 dest_tile->extras_owner = from_tile->extras_owner;
1396 dest_tile->last_updated = from_tile->last_updated;
1397 send_tile_info(pdest->connections, ptile, FALSE);
1399 /* update and send city knowledge */
1400 /* remove outdated cities */
1401 if (dest_tile->site) {
1402 if (!from_tile->site) {
1403 /* As the city was gone on the newer from_tile
1404 it will be removed by this function */
1405 reality_check_city(pdest, ptile);
1406 } else /* We have a dest_city. update */
1407 if (from_tile->site->identity
1408 != dest_tile->site->identity) {
1409 /* As the city was gone on the newer from_tile
1410 it will be removed by this function */
1411 reality_check_city(pdest, ptile);
1415 /* Set and send new city info */
1416 if (from_tile->site) {
1417 if (!dest_tile->site) {
1418 /* We cannot assign new vision site with change_playertile_site(),
1419 * since location is not yet set up for new site */
1420 dest_tile->site = vision_site_new(0, ptile, NULL);
1421 *dest_tile->site = *from_tile->site;
1423 /* Note that we don't care if receiver knows vision source city
1424 * or not. */
1425 send_city_info_at_tile(pdest, pdest->connections, NULL, ptile);
1428 city_map_update_tile_frozen(ptile);
1433 /***************************************************************
1434 Give tile information from player to player. Handles chains of
1435 shared vision so that receiver may give information forward.
1436 ***************************************************************/
1437 static void give_tile_info_from_player_to_player(struct player *pfrom,
1438 struct player *pdest,
1439 struct tile *ptile)
1441 really_give_tile_info_from_player_to_player(pfrom, pdest, ptile);
1443 players_iterate(pplayer2) {
1444 if (really_gives_vision(pdest, pplayer2)) {
1445 really_give_tile_info_from_player_to_player(pfrom, pplayer2, ptile);
1447 } players_iterate_end;
1450 /***************************************************************
1451 This updates all players' really_gives_vision field.
1452 If p1 gives p2 shared vision and p2 gives p3 shared vision p1
1453 should also give p3 shared vision.
1454 ***************************************************************/
1455 static void create_vision_dependencies(void)
1457 int added;
1459 players_iterate(pplayer) {
1460 pplayer->server.really_gives_vision = pplayer->gives_shared_vision;
1461 } players_iterate_end;
1463 /* In words: This terminates when it has run a round without adding
1464 a dependency. One loop only propagates dependencies one level deep,
1465 which is why we keep doing it as long as changes occur. */
1466 do {
1467 added = 0;
1468 players_iterate(pplayer) {
1469 players_iterate(pplayer2) {
1470 if (really_gives_vision(pplayer, pplayer2)
1471 && pplayer != pplayer2) {
1472 players_iterate(pplayer3) {
1473 if (really_gives_vision(pplayer2, pplayer3)
1474 && !really_gives_vision(pplayer, pplayer3)
1475 && pplayer != pplayer3) {
1476 BV_SET(pplayer->server.really_gives_vision, player_index(pplayer3));
1477 added++;
1479 } players_iterate_end;
1481 } players_iterate_end;
1482 } players_iterate_end;
1483 } while (added > 0);
1486 /***************************************************************
1487 Starts shared vision between two players.
1488 ***************************************************************/
1489 void give_shared_vision(struct player *pfrom, struct player *pto)
1491 bv_player save_vision[player_slot_count()];
1492 if (pfrom == pto) return;
1493 if (gives_shared_vision(pfrom, pto)) {
1494 log_error("Trying to give shared vision from %s to %s, "
1495 "but that vision is already given!",
1496 player_name(pfrom), player_name(pto));
1497 return;
1500 players_iterate(pplayer) {
1501 save_vision[player_index(pplayer)] = pplayer->server.really_gives_vision;
1502 } players_iterate_end;
1504 BV_SET(pfrom->gives_shared_vision, player_index(pto));
1505 create_vision_dependencies();
1506 log_debug("giving shared vision from %s to %s",
1507 player_name(pfrom), player_name(pto));
1509 players_iterate(pplayer) {
1510 buffer_shared_vision(pplayer);
1511 players_iterate(pplayer2) {
1512 if (really_gives_vision(pplayer, pplayer2)
1513 && !BV_ISSET(save_vision[player_index(pplayer)],
1514 player_index(pplayer2))) {
1515 log_debug("really giving shared vision from %s to %s",
1516 player_name(pplayer), player_name(pplayer2));
1517 whole_map_iterate(&(wld.map), ptile) {
1518 const v_radius_t change =
1519 V_RADIUS(map_get_own_seen(pplayer, ptile, V_MAIN),
1520 map_get_own_seen(pplayer, ptile, V_INVIS));
1522 if (0 < change[V_MAIN] || 0 < change[V_INVIS]) {
1523 map_change_seen(pplayer2, ptile, change,
1524 map_is_known(ptile, pplayer));
1526 } whole_map_iterate_end;
1528 /* squares that are not seen, but which pfrom may have more recent
1529 knowledge of */
1530 give_map_from_player_to_player(pplayer, pplayer2);
1532 } players_iterate_end;
1533 unbuffer_shared_vision(pplayer);
1534 } players_iterate_end;
1536 if (S_S_RUNNING == server_state()) {
1537 send_player_info_c(pfrom, NULL);
1541 /***************************************************************
1542 Removes shared vision from between two players.
1543 ***************************************************************/
1544 void remove_shared_vision(struct player *pfrom, struct player *pto)
1546 bv_player save_vision[player_slot_count()];
1548 fc_assert_ret(pfrom != pto);
1549 if (!gives_shared_vision(pfrom, pto)) {
1550 log_error("Tried removing the shared vision from %s to %s, "
1551 "but it did not exist in the first place!",
1552 player_name(pfrom), player_name(pto));
1553 return;
1556 players_iterate(pplayer) {
1557 save_vision[player_index(pplayer)] = pplayer->server.really_gives_vision;
1558 } players_iterate_end;
1560 log_debug("removing shared vision from %s to %s",
1561 player_name(pfrom), player_name(pto));
1563 BV_CLR(pfrom->gives_shared_vision, player_index(pto));
1564 create_vision_dependencies();
1566 players_iterate(pplayer) {
1567 buffer_shared_vision(pplayer);
1568 players_iterate(pplayer2) {
1569 if (!really_gives_vision(pplayer, pplayer2)
1570 && BV_ISSET(save_vision[player_index(pplayer)],
1571 player_index(pplayer2))) {
1572 log_debug("really removing shared vision from %s to %s",
1573 player_name(pplayer), player_name(pplayer2));
1574 whole_map_iterate(&(wld.map), ptile) {
1575 const v_radius_t change =
1576 V_RADIUS(-map_get_own_seen(pplayer, ptile, V_MAIN),
1577 -map_get_own_seen(pplayer, ptile, V_INVIS));
1579 if (0 > change[V_MAIN] || 0 > change[V_INVIS]) {
1580 map_change_seen(pplayer2, ptile, change, FALSE);
1582 } whole_map_iterate_end;
1584 } players_iterate_end;
1585 unbuffer_shared_vision(pplayer);
1586 } players_iterate_end;
1588 if (S_S_RUNNING == server_state()) {
1589 send_player_info_c(pfrom, NULL);
1593 /*************************************************************************
1594 Turns FoW on for player
1595 *************************************************************************/
1596 void enable_fog_of_war_player(struct player *pplayer)
1598 const v_radius_t radius_sq = V_RADIUS(-1, 0);
1600 buffer_shared_vision(pplayer);
1601 whole_map_iterate(&(wld.map), ptile) {
1602 map_change_seen(pplayer, ptile, radius_sq, FALSE);
1603 } whole_map_iterate_end;
1604 unbuffer_shared_vision(pplayer);
1607 /*************************************************************************
1608 Turns FoW on for everyone.
1609 *************************************************************************/
1610 void enable_fog_of_war(void)
1612 players_iterate(pplayer) {
1613 enable_fog_of_war_player(pplayer);
1614 } players_iterate_end;
1617 /*************************************************************************
1618 Turns FoW off for player
1619 *************************************************************************/
1620 void disable_fog_of_war_player(struct player *pplayer)
1622 const v_radius_t radius_sq = V_RADIUS(1, 0);
1624 buffer_shared_vision(pplayer);
1625 whole_map_iterate(&(wld.map), ptile) {
1626 map_change_seen(pplayer, ptile, radius_sq, FALSE);
1627 } whole_map_iterate_end;
1628 unbuffer_shared_vision(pplayer);
1631 /*************************************************************************
1632 Turns FoW off for everyone
1633 *************************************************************************/
1634 void disable_fog_of_war(void)
1636 players_iterate(pplayer) {
1637 disable_fog_of_war_player(pplayer);
1638 } players_iterate_end;
1641 /**************************************************************************
1642 Set the tile to be a river if required.
1643 It's required if one of the tiles nearby would otherwise be part of a
1644 river to nowhere.
1645 (Note that rivers-to-nowhere can still occur if a single-tile lake is
1646 transformed away, but this is relatively unlikely.)
1647 For simplicity, I'm assuming that this is the only exit of the river,
1648 so I don't need to trace it across the continent. --CJM
1649 **************************************************************************/
1650 static void ocean_to_land_fix_rivers(struct tile *ptile)
1652 cardinal_adjc_iterate(&(wld.map), ptile, tile1) {
1653 bool ocean_near = FALSE;
1655 cardinal_adjc_iterate(&(wld.map), tile1, tile2) {
1656 if (is_ocean_tile(tile2))
1657 ocean_near = TRUE;
1658 } cardinal_adjc_iterate_end;
1660 if (!ocean_near) {
1661 /* If ruleset has several river types defined, this
1662 * may cause same tile to contain more than one river. */
1663 extra_type_by_cause_iterate(EC_ROAD, priver) {
1664 if (tile_has_extra(tile1, priver)
1665 && road_has_flag(extra_road_get(priver), RF_RIVER)) {
1666 tile_add_extra(ptile, priver);
1668 } extra_type_by_cause_iterate_end;
1670 } cardinal_adjc_iterate_end;
1673 /****************************************************************************
1674 Helper function for bounce_units_on_terrain_change() that checks units
1675 on a single tile.
1676 ****************************************************************************/
1677 static void check_units_single_tile(struct tile *ptile)
1679 unit_list_iterate_safe(ptile->units, punit) {
1680 bool unit_alive = TRUE;
1682 if (unit_tile(punit) == ptile
1683 && !unit_transported(punit)
1684 && !can_unit_exist_at_tile(&(wld.map), punit, ptile)) {
1685 /* look for a nearby safe tile */
1686 adjc_iterate(&(wld.map), ptile, ptile2) {
1687 if (can_unit_exist_at_tile(&(wld.map), punit, ptile2)
1688 && !is_non_allied_unit_tile(ptile2, unit_owner(punit))
1689 && !is_non_allied_city_tile(ptile2, unit_owner(punit))) {
1690 log_verbose("Moved %s %s due to changing terrain at (%d,%d).",
1691 nation_rule_name(nation_of_unit(punit)),
1692 unit_rule_name(punit), TILE_XY(unit_tile(punit)));
1693 notify_player(unit_owner(punit), unit_tile(punit),
1694 E_UNIT_RELOCATED, ftc_server,
1695 _("Moved your %s due to changing terrain."),
1696 unit_link(punit));
1697 unit_alive = unit_move(punit, ptile2, 0, NULL, FALSE);
1698 if (unit_alive && punit->activity == ACTIVITY_SENTRY) {
1699 unit_activity_handling(punit, ACTIVITY_IDLE);
1701 break;
1703 } adjc_iterate_end;
1704 if (unit_alive && unit_tile(punit) == ptile) {
1705 /* If we get here we could not move punit. */
1706 log_verbose("Disbanded %s %s due to changing land "
1707 " to sea at (%d, %d).",
1708 nation_rule_name(nation_of_unit(punit)),
1709 unit_rule_name(punit), TILE_XY(unit_tile(punit)));
1710 notify_player(unit_owner(punit), unit_tile(punit),
1711 E_UNIT_LOST_MISC, ftc_server,
1712 _("Disbanded your %s due to changing terrain."),
1713 unit_tile_link(punit));
1714 wipe_unit(punit, ULR_NONNATIVE_TERR, NULL);
1717 } unit_list_iterate_safe_end;
1720 /****************************************************************************
1721 Check ptile and nearby tiles to see if all units can remain at their
1722 current locations, and move or disband any that cannot. Call this after
1723 terrain or specials change on ptile.
1724 ****************************************************************************/
1725 void bounce_units_on_terrain_change(struct tile *ptile)
1727 /* Check this tile for direct effect on its units */
1728 check_units_single_tile(ptile);
1729 /* We have to check adjacent tiles too, in case units in cities are now
1730 * illegal (e.g., boat in a city that has become landlocked). */
1731 adjc_iterate(&(wld.map), ptile, ptile2) {
1732 check_units_single_tile(ptile2);
1733 } adjc_iterate_end;
1736 /****************************************************************************
1737 Returns TRUE if the terrain change from 'oldter' to 'newter' may require
1738 expensive reassignment of continents.
1739 ****************************************************************************/
1740 bool need_to_reassign_continents(const struct terrain *oldter,
1741 const struct terrain *newter)
1743 bool old_is_ocean, new_is_ocean;
1745 if (!oldter || !newter) {
1746 return FALSE;
1749 old_is_ocean = is_ocean(oldter);
1750 new_is_ocean = is_ocean(newter);
1752 return (old_is_ocean && !new_is_ocean)
1753 || (!old_is_ocean && new_is_ocean);
1756 /****************************************************************************
1757 Handle local side effects for a terrain change.
1758 ****************************************************************************/
1759 void terrain_changed(struct tile *ptile)
1761 struct city *pcity = tile_city(ptile);
1763 if (pcity != NULL) {
1764 /* Tile is city center and new terrain may support better extras. */
1765 upgrade_city_extras(pcity, NULL);
1768 bounce_units_on_terrain_change(ptile);
1771 /****************************************************************************
1772 Handles local side effects for a terrain change (tile and its
1773 surroundings). Does *not* handle global side effects (such as reassigning
1774 continents).
1775 For in-game terrain changes 'extend_rivers' should be TRUE; for edits it
1776 should be FALSE.
1777 ****************************************************************************/
1778 void fix_tile_on_terrain_change(struct tile *ptile,
1779 struct terrain *oldter,
1780 bool extend_rivers)
1782 if (is_ocean(oldter) && !is_ocean_tile(ptile)) {
1783 if (extend_rivers) {
1784 ocean_to_land_fix_rivers(ptile);
1786 city_landlocked_sell_coastal_improvements(ptile);
1789 terrain_changed(ptile);
1792 /****************************************************************************
1793 Handles local and global side effects for a terrain change for a single
1794 tile.
1795 Call this in the server immediately after calling tile_change_terrain.
1796 Assumes an in-game terrain change (e.g., by workers/engineers).
1797 ****************************************************************************/
1798 void check_terrain_change(struct tile *ptile, struct terrain *oldter)
1800 struct terrain *newter = tile_terrain(ptile);
1801 struct tile *claimer;
1803 /* Check if new terrain is a freshwater terrain next to non-freshwater.
1804 * In that case, the new terrain is *changed*. */
1805 if (is_ocean(newter) && terrain_has_flag(newter, TER_FRESHWATER)) {
1806 bool nonfresh = FALSE;
1808 adjc_iterate(&(wld.map), ptile, atile) {
1809 if (is_ocean(tile_terrain(atile))
1810 && !terrain_has_flag(tile_terrain(atile), TER_FRESHWATER)) {
1811 nonfresh = TRUE;
1812 break;
1814 } adjc_iterate_end;
1815 if (nonfresh) {
1816 /* Need to pick a new, non-freshwater ocean type for this tile.
1817 * We don't want e.g. Deep Ocean to be propagated to this tile
1818 * and then to a whole lake by the flooding below, so we pick
1819 * the shallowest non-fresh oceanic type.
1820 * Prefer terrain that matches the frozenness of the target. */
1821 newter = most_shallow_ocean(terrain_has_flag(newter, TER_FROZEN));
1822 tile_change_terrain(ptile, newter);
1826 fix_tile_on_terrain_change(ptile, oldter, TRUE);
1828 /* Check for saltwater filling freshwater lake */
1829 if (game.scenario.lake_flooding
1830 && is_ocean(newter) && !terrain_has_flag(newter, TER_FRESHWATER)) {
1831 adjc_iterate(&(wld.map), ptile, atile) {
1832 if (terrain_has_flag(tile_terrain(atile), TER_FRESHWATER)) {
1833 struct terrain *aold = tile_terrain(atile);
1835 tile_change_terrain(atile,
1836 most_shallow_ocean(terrain_has_flag(aold,
1837 TER_FROZEN)));
1839 /* Recursive, but as lakes are of limited size, this
1840 * won't recurse so much as to cause stack problems. */
1841 check_terrain_change(atile, aold);
1842 update_tile_knowledge(atile);
1844 } adjc_iterate_end;
1847 if (need_to_reassign_continents(oldter, newter)) {
1848 assign_continent_numbers();
1849 send_all_known_tiles(NULL);
1852 claimer = tile_claimer(ptile);
1853 if (claimer != NULL && is_ocean_tile(ptile)) {
1854 if (!is_claimable_ocean(ptile, claimer, tile_owner(ptile))) {
1855 map_clear_border(ptile);
1859 sanity_check_tile(ptile);
1862 /*************************************************************************
1863 Ocean tile can be claimed iff one of the following conditions stands:
1864 a) it is an inland lake not larger than MAXIMUM_OCEAN_SIZE
1865 b) it is adjacent to only one continent and not more than two ocean tiles
1866 c) It is one tile away from a border source
1867 d) Player knows tech with Claim_Ocean flag
1868 e) Source itself is Oceanic tile and player knows tech with Claim_Ocean_Limited flag
1869 The source which claims the ocean has to be placed on the correct continent.
1870 in case a) The continent which surrounds the inland lake
1871 in case b) The only continent which is adjacent to the tile
1872 *************************************************************************/
1873 static bool is_claimable_ocean(struct tile *ptile, struct tile *source,
1874 struct player *pplayer)
1876 Continent_id cont = tile_continent(ptile);
1877 Continent_id cont1 = tile_continent(source);
1878 Continent_id cont2;
1879 int ocean_tiles;
1880 bool other_continent;
1882 if (get_ocean_size(-cont) <= MAXIMUM_CLAIMED_OCEAN_SIZE
1883 && get_lake_surrounders(cont) == cont1) {
1884 return TRUE;
1887 if (ptile == source) {
1888 /* Source itself is always claimable. */
1889 return TRUE;
1892 if (num_known_tech_with_flag(pplayer, TF_CLAIM_OCEAN) > 0
1893 || (cont1 < 0 && num_known_tech_with_flag(pplayer, TF_CLAIM_OCEAN_LIMITED) > 0)) {
1894 return TRUE;
1897 ocean_tiles = 0;
1898 other_continent = FALSE;
1899 adjc_iterate(&(wld.map), ptile, tile2) {
1900 cont2 = tile_continent(tile2);
1901 if (tile2 == source) {
1902 /* Water next to border source is always claimable */
1903 return TRUE;
1905 if (cont2 == cont) {
1906 ocean_tiles++;
1907 } else if (cont1 <= 0) {
1908 /* First adjacent land (only if border source is not on land) */
1909 cont1 = cont2;
1910 } else if (cont2 != cont1) {
1911 /* This water has two land continents adjacent, or land adjacent
1912 * that is of a different continent from the border source */
1913 other_continent = TRUE;
1915 } adjc_iterate_end;
1916 if (!other_continent && ocean_tiles <= 2) {
1917 return TRUE;
1918 } else {
1919 return FALSE;
1923 /*************************************************************************
1924 For each unit at the tile, queue any unique home city.
1925 *************************************************************************/
1926 static void map_unit_homecity_enqueue(struct tile *ptile)
1928 unit_list_iterate(ptile->units, punit) {
1929 struct city *phome = game_city_by_number(punit->homecity);
1931 if (NULL == phome) {
1932 continue;
1935 city_refresh_queue_add(phome);
1936 } unit_list_iterate_end;
1939 /*************************************************************************
1940 Claim ownership of a single tile.
1941 *************************************************************************/
1942 static void map_claim_border_ownership(struct tile *ptile,
1943 struct player *powner,
1944 struct tile *psource)
1946 struct player *ploser = tile_owner(ptile);
1948 if ((ploser != powner && ploser != NULL)
1949 && (BORDERS_SEE_INSIDE == game.info.borders
1950 || BORDERS_EXPAND == game.info.borders
1951 || ploser->server.border_vision)) {
1952 const v_radius_t radius_sq = V_RADIUS(-1, 0);
1954 shared_vision_change_seen(ploser, ptile, radius_sq, FALSE);
1957 if (powner != NULL
1958 && (BORDERS_SEE_INSIDE == game.info.borders
1959 || BORDERS_EXPAND == game.info.borders
1960 || powner->server.border_vision)) {
1961 const v_radius_t radius_sq = V_RADIUS(1, 0);
1963 shared_vision_change_seen(powner, ptile, radius_sq, TRUE);
1966 tile_set_owner(ptile, powner, psource);
1968 /* Needed only when foggedborders enabled, but we do it unconditionally
1969 * in case foggedborders ever gets enabled later. Better to have correct
1970 * information in player map just in case. */
1971 update_tile_knowledge(ptile);
1973 if (ploser != powner) {
1974 if (S_S_RUNNING == server_state() && game.info.happyborders != HB_DISABLED) {
1975 map_unit_homecity_enqueue(ptile);
1978 if (!city_map_update_tile_frozen(ptile)) {
1979 send_tile_info(NULL, ptile, FALSE);
1984 /*************************************************************************
1985 Claim ownership of a single tile.
1986 *************************************************************************/
1987 void map_claim_ownership(struct tile *ptile, struct player *powner,
1988 struct tile *psource, bool claim_bases)
1990 map_claim_border_ownership(ptile, powner, psource);
1992 if (claim_bases) {
1993 tile_claim_bases(ptile, powner);
1997 /*************************************************************************
1998 Claim ownership of bases on single tile.
1999 *************************************************************************/
2000 void tile_claim_bases(struct tile *ptile, struct player *powner)
2002 struct player *base_loser = extra_owner(ptile);
2004 /* This MUST be before potentially recursive call to map_claim_base(),
2005 * so that the recursive call will get new owner == base_loser and
2006 * abort recursion. */
2007 ptile->extras_owner = powner;
2009 extra_type_by_cause_iterate(EC_BASE, pextra) {
2010 map_claim_base(ptile, pextra, powner, base_loser);
2011 } extra_type_by_cause_iterate_end;
2014 /*************************************************************************
2015 Remove border for this source.
2016 *************************************************************************/
2017 void map_clear_border(struct tile *ptile)
2019 int radius_sq = tile_border_source_radius_sq(ptile);
2021 circle_dxyr_iterate(&(wld.map), ptile, radius_sq, dtile, dx, dy, dr) {
2022 struct tile *claimer = tile_claimer(dtile);
2024 if (claimer == ptile) {
2025 map_claim_ownership(dtile, NULL, NULL, FALSE);
2027 } circle_dxyr_iterate_end;
2030 /*************************************************************************
2031 Update borders for this source. Changes the radius without temporary
2032 clearing.
2033 *************************************************************************/
2034 void map_update_border(struct tile *ptile, struct player *owner,
2035 int old_radius_sq, int new_radius_sq)
2037 if (old_radius_sq == new_radius_sq) {
2038 /* No change */
2039 return;
2042 if (BORDERS_DISABLED == game.info.borders) {
2043 return;
2046 if (old_radius_sq < new_radius_sq) {
2047 map_claim_border(ptile, owner, new_radius_sq);
2048 } else {
2049 circle_dxyr_iterate(&(wld.map), ptile, old_radius_sq, dtile, dx, dy, dr) {
2050 if (dr > new_radius_sq) {
2051 struct tile *claimer = tile_claimer(dtile);
2053 if (claimer == ptile) {
2054 map_claim_ownership(dtile, NULL, NULL, FALSE);
2057 } circle_dxyr_iterate_end;
2061 /*************************************************************************
2062 Update borders for this source. Call this for each new source.
2064 If radius_sq is -1, get value from the border source on tile.
2065 *************************************************************************/
2066 void map_claim_border(struct tile *ptile, struct player *owner,
2067 int radius_sq)
2069 if (BORDERS_DISABLED == game.info.borders) {
2070 return;
2073 if (owner == NULL) {
2074 /* Clear the border instead of claiming. Code below this block
2075 * cannot handle NULL owner. */
2076 map_clear_border(ptile);
2078 return;
2081 if (radius_sq < 0) {
2082 radius_sq = tile_border_source_radius_sq(ptile);
2085 circle_dxyr_iterate(&(wld.map), ptile, radius_sq, dtile, dx, dy, dr) {
2086 struct tile *dclaimer = tile_claimer(dtile);
2088 if (dclaimer == ptile) {
2089 /* Already claimed by the ptile */
2090 continue;
2093 if (dr != 0 && is_border_source(dtile)) {
2094 /* Do not claim border sources other than self */
2095 /* Note that this is extremely important at the moment for
2096 * base claiming to work correctly in case there's two
2097 * fortresses near each other. There could be infinite
2098 * recursion in them claiming each other. */
2099 continue;
2102 if (!map_is_known(dtile, owner) && game.info.borders < BORDERS_EXPAND) {
2103 continue;
2106 /* Always claim source itself (distance, dr, to it 0) */
2107 if (dr != 0 && NULL != dclaimer && dclaimer != ptile) {
2108 struct city *ccity = tile_city(dclaimer);
2109 int strength_old, strength_new;
2111 if (ccity != NULL) {
2112 /* Previously claimed by city */
2113 int city_x, city_y;
2115 map_distance_vector(&city_x, &city_y, ccity->tile, dtile);
2117 if (map_vector_to_sq_distance(city_x, city_y)
2118 <= city_map_radius_sq_get(ccity)
2119 + game.info.border_city_permanent_radius_sq) {
2120 /* Tile is within region permanently claimed by city */
2121 continue;
2125 strength_old = tile_border_strength(dtile, dclaimer);
2126 strength_new = tile_border_strength(dtile, ptile);
2128 if (strength_new <= strength_old) {
2129 /* Stronger shall prevail,
2130 * in case of equal strength older shall prevail */
2131 continue;
2135 if (is_ocean_tile(dtile)) {
2136 /* Only certain water tiles are claimable */
2137 if (is_claimable_ocean(dtile, ptile, owner)) {
2138 map_claim_ownership(dtile, owner, ptile, dr == 0);
2140 } else {
2141 /* Only land tiles on the same island as the border source
2142 * are claimable */
2143 if (tile_continent(dtile) == tile_continent(ptile)) {
2144 map_claim_ownership(dtile, owner, ptile, dr == 0);
2147 } circle_dxyr_iterate_end;
2150 /*************************************************************************
2151 Update borders for all sources. Call this on turn end.
2152 *************************************************************************/
2153 void map_calculate_borders(void)
2155 if (BORDERS_DISABLED == game.info.borders) {
2156 return;
2159 if (wld.map.tiles == NULL) {
2160 /* Map not yet initialized */
2161 return;
2164 log_verbose("map_calculate_borders()");
2166 whole_map_iterate(&(wld.map), ptile) {
2167 if (is_border_source(ptile)) {
2168 map_claim_border(ptile, ptile->owner, -1);
2170 } whole_map_iterate_end;
2172 log_verbose("map_calculate_borders() workers");
2173 city_thaw_workers_queue();
2174 city_refresh_queue_processing();
2177 /****************************************************************************
2178 Claim base to player's ownership.
2179 ****************************************************************************/
2180 void map_claim_base(struct tile *ptile, struct extra_type *pextra,
2181 struct player *powner, struct player *ploser)
2183 struct base_type *pbase;
2184 int units_num;
2185 bv_player *could_see_unit;
2186 int i;
2188 if (!tile_has_extra(ptile, pextra)) {
2189 return;
2192 units_num = unit_list_size(ptile->units);
2193 could_see_unit = (units_num > 0
2194 ? fc_malloc(sizeof(*could_see_unit) * units_num)
2195 : NULL);
2197 i = 0;
2198 if (pextra->eus != EUS_NORMAL) {
2199 unit_list_iterate(ptile->units, aunit) {
2200 BV_CLR_ALL(could_see_unit[i]);
2201 players_iterate(aplayer) {
2202 if (can_player_see_unit(aplayer, aunit)) {
2203 BV_SET(could_see_unit[i], player_index(aplayer));
2205 } players_iterate_end;
2206 i++;
2207 } unit_list_iterate_end;
2210 pbase = extra_base_get(pextra);
2212 fc_assert_ret(pbase != NULL);
2214 /* Transfer base provided vision to new owner */
2215 if (powner != NULL) {
2216 const v_radius_t old_radius_sq = V_RADIUS(-1, -1);
2217 const v_radius_t new_radius_sq = V_RADIUS(pbase->vision_main_sq,
2218 pbase->vision_invis_sq);
2220 map_vision_update(powner, ptile, old_radius_sq, new_radius_sq,
2221 game.server.vision_reveal_tiles);
2224 if (ploser != NULL) {
2225 const v_radius_t old_radius_sq = V_RADIUS(pbase->vision_main_sq,
2226 pbase->vision_invis_sq);
2227 const v_radius_t new_radius_sq = V_RADIUS(-1, -1);
2229 map_vision_update(ploser, ptile, old_radius_sq, new_radius_sq,
2230 game.server.vision_reveal_tiles);
2233 if (BORDERS_DISABLED != game.info.borders
2234 && territory_claiming_base(pbase) && powner != ploser) {
2235 /* Clear borders from old owner. New owner may not know all those
2236 * tiles and thus does not claim them when borders mode is less
2237 * than EXPAND. */
2238 if (ploser != NULL) {
2239 /* Set this particular tile owner by NULL so in recursion
2240 * both loser and owner will be NULL. */
2241 map_claim_border_ownership(ptile, NULL, ptile);
2242 map_clear_border(ptile);
2245 /* We here first claim this tile ownership -> now on extra_owner()
2246 * will return new owner. Then we claim border, which will recursively
2247 * lead to this tile and base being claimed. But at that point
2248 * ploser == powner and above check will abort the recursion. */
2249 if (powner != NULL) {
2250 map_claim_border_ownership(ptile, powner, ptile);
2251 map_claim_border(ptile, powner, -1);
2253 city_thaw_workers_queue();
2254 city_refresh_queue_processing();
2257 i = 0;
2258 if (pextra->eus != EUS_NORMAL) {
2259 unit_list_iterate(ptile->units, aunit) {
2260 players_iterate(aplayer) {
2261 if (can_player_see_unit(aplayer, aunit)) {
2262 if (!BV_ISSET(could_see_unit[i], player_index(aplayer))) {
2263 send_unit_info(aplayer->connections, aunit);
2265 } else {
2266 if (BV_ISSET(could_see_unit[i], player_index(aplayer))) {
2267 unit_goes_out_of_sight(aplayer, aunit);
2270 } players_iterate_end;
2271 i++;
2272 } unit_list_iterate_end;
2276 /****************************************************************************
2277 Change the sight points for the vision source, fogging or unfogging tiles
2278 as needed.
2280 See documentation in vision.h.
2281 ****************************************************************************/
2282 void vision_change_sight(struct vision *vision, const v_radius_t radius_sq)
2284 map_vision_update(vision->player, vision->tile, vision->radius_sq,
2285 radius_sq, vision->can_reveal_tiles);
2286 memcpy(vision->radius_sq, radius_sq, sizeof(v_radius_t));
2289 /****************************************************************************
2290 Clear all sight points from this vision source.
2292 See documentation in vision.h.
2293 ****************************************************************************/
2294 void vision_clear_sight(struct vision *vision)
2296 const v_radius_t vision_radius_sq = V_RADIUS(-1, -1);
2298 vision_change_sight(vision, vision_radius_sq);
2301 /****************************************************************************
2302 Create extra to tile.
2303 ****************************************************************************/
2304 void create_extra(struct tile *ptile, struct extra_type *pextra,
2305 struct player *pplayer)
2307 bool extras_removed = FALSE;
2309 extra_type_iterate(old_extra) {
2310 if (tile_has_extra(ptile, old_extra)
2311 && !can_extras_coexist(old_extra, pextra)) {
2312 destroy_extra(ptile, old_extra);
2313 extras_removed = TRUE;
2315 } extra_type_iterate_end;
2317 if (pextra->eus != EUS_NORMAL) {
2318 unit_list_iterate(ptile->units, aunit) {
2319 if (is_native_extra_to_utype(pextra, unit_type_get(aunit))) {
2320 players_iterate(aplayer) {
2321 if (!pplayers_allied(pplayer, aplayer)
2322 && can_player_see_unit(aplayer, aunit)) {
2323 unit_goes_out_of_sight(aplayer, aunit);
2325 } players_iterate_end;
2327 } unit_list_iterate_end;
2330 tile_add_extra(ptile, pextra);
2332 /* Watchtower might become effective. */
2333 unit_list_refresh_vision(ptile->units);
2335 if (pextra->data.base != NULL) {
2336 /* Claim bases on tile */
2337 if (pplayer) {
2338 struct player *old_owner = extra_owner(ptile);
2340 /* Created base from NULL -> pplayer */
2341 map_claim_base(ptile, pextra, pplayer, NULL);
2343 if (old_owner != pplayer) {
2344 /* Existing bases from old_owner -> pplayer */
2345 extra_type_by_cause_iterate(EC_BASE, oldbase) {
2346 if (oldbase != pextra) {
2347 map_claim_base(ptile, oldbase, pplayer, old_owner);
2349 } extra_type_by_cause_iterate_end;
2351 ptile->extras_owner = pplayer;
2353 } else {
2354 /* Player who already owns bases on tile claims new base */
2355 map_claim_base(ptile, pextra, extra_owner(ptile), NULL);
2359 if (extras_removed) {
2360 /* Maybe conflicting extra that was removed was the only thing
2361 * making tile native to some unit. */
2362 bounce_units_on_terrain_change(ptile);
2366 /****************************************************************************
2367 Remove extra from tile.
2368 ****************************************************************************/
2369 void destroy_extra(struct tile *ptile, struct extra_type *pextra)
2371 bv_player base_seen;
2372 bool virtual = tile_virtual_check(ptile);
2374 /* Remember what players were able to see the base. */
2375 if (!virtual) {
2376 BV_CLR_ALL(base_seen);
2377 players_iterate(pplayer) {
2378 if (map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
2379 BV_SET(base_seen, player_index(pplayer));
2381 } players_iterate_end;
2384 if (is_extra_caused_by(pextra, EC_BASE)) {
2385 struct base_type *pbase = extra_base_get(pextra);
2386 struct player *owner = extra_owner(ptile);
2388 if (territory_claiming_base(pbase)) {
2389 map_clear_border(ptile);
2392 if (NULL != owner
2393 && (0 <= pbase->vision_main_sq || 0 <= pbase->vision_invis_sq)) {
2394 /* Base provides vision, but no borders. */
2395 const v_radius_t old_radius_sq =
2396 V_RADIUS(0 <= pbase->vision_main_sq ? pbase->vision_main_sq : -1,
2397 0 <= pbase->vision_invis_sq ? pbase->vision_invis_sq : -1);
2398 const v_radius_t new_radius_sq = V_RADIUS(-1, -1);
2400 map_vision_update(owner, ptile, old_radius_sq, new_radius_sq,
2401 game.server.vision_reveal_tiles);
2405 tile_remove_extra(ptile, pextra);
2407 if (!virtual) {
2408 /* Remove base from vision of players which were able to see the base. */
2409 players_iterate(pplayer) {
2410 if (BV_ISSET(base_seen, player_index(pplayer))
2411 && update_player_tile_knowledge(pplayer, ptile)) {
2412 send_tile_info(pplayer->connections, ptile, FALSE);
2414 } players_iterate_end;
2416 if (pextra->eus != EUS_NORMAL) {
2417 struct player *eowner = extra_owner(ptile);
2419 unit_list_iterate(ptile->units, aunit) {
2420 if (is_native_extra_to_utype(pextra, unit_type_get(aunit))) {
2421 players_iterate(aplayer) {
2422 if (can_player_see_unit(aplayer, aunit)
2423 && !pplayers_allied(aplayer, eowner)) {
2424 send_unit_info(aplayer->connections, aunit);
2426 } players_iterate_end;
2428 } unit_list_iterate_end;
2433 /**************************************************************************
2434 Give player pto the map of pfrom, but do some random damage; good to bad
2435 is the ratio of tiles revealed to tiles not revealed, e.g., calling
2436 give_distorted_map(pfrom, pto, 1, 1, TRUE) reveals half the map on
2437 average. If reveal_cities is TRUE tiles with cities are always revealed.
2438 **************************************************************************/
2439 void give_distorted_map(struct player *pfrom, struct player *pto,
2440 int good, int bad, bool reveal_cities)
2442 int all = good + bad;
2444 buffer_shared_vision(pto);
2446 whole_map_iterate(&(wld.map), ptile) {
2447 if (fc_rand(all) >= bad) {
2448 give_tile_info_from_player_to_player(pfrom, pto, ptile);
2449 } else if (reveal_cities && NULL != tile_city(ptile)) {
2450 give_tile_info_from_player_to_player(pfrom, pto, ptile);
2452 } whole_map_iterate_end;
2454 unbuffer_shared_vision(pto);