From 3efad4fdc6b6dec685649501ae6f582adc888c7c Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 8 Apr 2023 15:19:29 +0300 Subject: [PATCH 37/37] Notify looting player what they get See osdn #45152 Signed-off-by: Marko Lindqvist --- server/citytools.c | 28 +++++++-------- server/maphand.c | 89 +++++++++++++++++++++++++++++----------------- server/maphand.h | 2 +- server/plrhand.c | 41 ++++++++++++++++----- server/techtools.c | 6 ++-- 5 files changed, 107 insertions(+), 59 deletions(-) diff --git a/server/citytools.c b/server/citytools.c index ccfb536a83..403c70176f 100644 --- a/server/citytools.c +++ b/server/citytools.c @@ -106,31 +106,31 @@ static void announce_trade_route_removal(struct city *pc1, struct city *pc2, bool source_gone); /************************************************************************//** - Freeze the workers (citizens on tiles) for the city. They will not be - auto-arranged until unfreeze_workers is called. + Freeze the workers (citizens on tiles) for the city. They will not be + auto-arranged until unfreeze_workers() is called. Long explanation: Historically auto_arrange_workers was called every time a city changed. If the city grew or shrunk, a new tile became available or was removed, - the function would be called. However in at least one place this breaks. - In some operations (like transfer_city) multiple things may change and - the city is not left in a sane state in between. Calling - auto_arrange_workers after each change means it's called with an "insane" - city. This can lead at best to a failed sanity check with a wasted call, - or at worse to a more major bug. The solution is freeze_workers and - thaw_workers. - - Call freeze_workers to freeze the auto-arranging of citizens. So long as - the freeze is in place no arrangement will be done for this city. Any - call to auto_arrange_workers will just queue up an arrangement for later. + the function would be called. However in at least one place this breaks. + In some operations (like transfer_city() ) multiple things may change and + the city is not left in a sane state in between. Calling + auto_arrange_workers() after each change means it's called with an "insane" + city. This can lead at best to a failed sanity check with a wasted call, + or at worse to a more major bug. The solution is freeze_workers() and + thaw_workers() + + Call freeze_workers() to freeze the auto-arranging of citizens. So long as + the freeze is in place no arrangement will be done for this city. Any + call to auto_arrange_workers() will just queue up an arrangement for later. Later when thaw_workers is called, the freeze is removed and the auto-arrange will be done if there is any arrangement pending. Freezing may safely be done more than once. It is thus always safe to call freeze and thaw around any set of city - actions. However this is unlikely to be needed in very many places. + actions. However this is unlikely to be needed in very many places. ****************************************************************************/ void city_freeze_workers(struct city *pcity) { diff --git a/server/maphand.c b/server/maphand.c index bcca8d024a..a61fdd4cee 100644 --- a/server/maphand.c +++ b/server/maphand.c @@ -66,9 +66,9 @@ static bool send_tile_suppressed = FALSE; static void player_tile_init(struct tile *ptile, struct player *pplayer); static void player_tile_free(struct tile *ptile, struct player *pplayer); -static void give_tile_info_from_player_to_player(struct player *pfrom, - struct player *pdest, - struct tile *ptile); +static bool give_tile_info_from_player_to_player(struct player *pfrom, + struct player *pdest, + struct tile *ptile); static void shared_vision_change_seen(struct player *pplayer, struct tile *ptile, const v_radius_t change, @@ -1447,12 +1447,18 @@ void update_player_tile_last_seen(struct player *pplayer, /**********************************************************************//** Give tile information from one player to one player. + + @param pfrom Who gives the information + @param pdest Who receives the information + @param ptile Tile to give info about + @return Whether there was any new info to give **************************************************************************/ -static void really_give_tile_info_from_player_to_player(struct player *pfrom, +static bool really_give_tile_info_from_player_to_player(struct player *pfrom, struct player *pdest, struct tile *ptile) { struct player_tile *from_tile, *dest_tile; + if (!map_is_known_and_seen(ptile, pdest, V_MAIN)) { /* I can just hear people scream as they try to comprehend this if :). * Let me try in words: @@ -1462,10 +1468,10 @@ static void really_give_tile_info_from_player_to_player(struct player *pfrom, * OR it is not known by pdest) */ if (map_is_known_and_seen(ptile, pfrom, V_MAIN) - || (map_is_known(ptile, pfrom) - && (((map_get_player_tile(ptile, pfrom)->last_updated - > map_get_player_tile(ptile, pdest)->last_updated)) - || !map_is_known(ptile, pdest)))) { + || (map_is_known(ptile, pfrom) + && (((map_get_player_tile(ptile, pfrom)->last_updated + > map_get_player_tile(ptile, pdest)->last_updated)) + || !map_is_known(ptile, pdest)))) { from_tile = map_get_player_tile(ptile, pfrom); dest_tile = map_get_player_tile(ptile, pdest); /* Update and send tile knowledge */ @@ -1478,37 +1484,42 @@ static void really_give_tile_info_from_player_to_player(struct player *pfrom, dest_tile->last_updated = from_tile->last_updated; send_tile_info(pdest->connections, ptile, FALSE); - /* update and send city knowledge */ - /* remove outdated cities */ + /* Update and send city knowledge */ + /* Remove outdated cities */ if (dest_tile->site) { - if (!from_tile->site) { - /* As the city was gone on the newer from_tile - it will be removed by this function */ - reality_check_city(pdest, ptile); - } else /* We have a dest_city. update */ - if (from_tile->site->identity + if (!from_tile->site) { + /* As the city was gone on the newer from_tile + it will be removed by this function */ + reality_check_city(pdest, ptile); + } else { /* We have a dest_city. update */ + if (from_tile->site->identity != dest_tile->site->identity) { - /* As the city was gone on the newer from_tile - it will be removed by this function */ - reality_check_city(pdest, ptile); + /* As the city was gone on the newer from_tile + it will be removed by this function */ + reality_check_city(pdest, ptile); } + } } /* Set and send new city info */ if (from_tile->site) { - if (!dest_tile->site) { + if (!dest_tile->site) { /* We cannot assign new vision site with change_playertile_site(), * since location is not yet set up for new site */ dest_tile->site = vision_site_copy(from_tile->site); - } + } /* Note that we don't care if receiver knows vision source city * or not. */ - send_city_info_at_tile(pdest, pdest->connections, NULL, ptile); + send_city_info_at_tile(pdest, pdest->connections, NULL, ptile); } city_map_update_tile_frozen(ptile); + + return TRUE; } } + + return FALSE; } /**********************************************************************//** @@ -1529,18 +1540,25 @@ static void really_give_map_from_player_to_player(struct player *pfrom, /**********************************************************************//** Give tile information from player to player. Handles chains of shared vision so that receiver may give information forward. + + @param pfrom Who gives the information + @param pdest Who receives the information + @param ptile Tile to give info about + @return Whether there was any new info to give **************************************************************************/ -static void give_tile_info_from_player_to_player(struct player *pfrom, +static bool give_tile_info_from_player_to_player(struct player *pfrom, struct player *pdest, struct tile *ptile) { - really_give_tile_info_from_player_to_player(pfrom, pdest, ptile); + bool updt = really_give_tile_info_from_player_to_player(pfrom, pdest, ptile); players_iterate(pplayer2) { if (really_gives_vision(pdest, pplayer2)) { - really_give_tile_info_from_player_to_player(pfrom, pplayer2, ptile); + updt |= really_give_tile_info_from_player_to_player(pfrom, pplayer2, ptile); } } players_iterate_end; + + return updt; } /**********************************************************************//** @@ -1622,9 +1640,9 @@ void give_shared_vision(struct player *pfrom, struct player *pto) } } whole_map_iterate_end; - /* squares that are not seen, but which pfrom may have more recent - knowledge of */ - really_give_map_from_player_to_player(pplayer, pplayer2); + /* Squares that are not seen, but which pfrom may have more recent + knowledge of */ + really_give_map_from_player_to_player(pplayer, pplayer2); } } players_iterate_end; unbuffer_shared_vision(pplayer); @@ -1804,7 +1822,7 @@ static void check_units_single_tile(struct tile *ptile) unit_activity_handling(punit, ACTIVITY_IDLE); } break; - } + } } adjc_iterate_end; if (unit_alive && unit_tile(punit) == ptile) { /* If we get here we could not move punit. */ @@ -2568,25 +2586,32 @@ void destroy_extra(struct tile *ptile, struct extra_type *pextra) /**********************************************************************//** Transfer (random parts of) player pfrom's world map to pto. + @param pfrom player that is the source of the map @param pto player that receives the map @param prob probability for the transfer each known tile @param reveal_cities if the map of all known cities should be transferred + + @return Whether there any new info was given **************************************************************************/ -void give_distorted_map(struct player *pfrom, struct player *pto, +bool give_distorted_map(struct player *pfrom, struct player *pto, int prob, bool reveal_cities) { + bool updt = FALSE; + buffer_shared_vision(pto); whole_map_iterate(&(wld.map), ptile) { if (fc_rand(100) < prob) { - give_tile_info_from_player_to_player(pfrom, pto, ptile); + updt |= give_tile_info_from_player_to_player(pfrom, pto, ptile); } else if (reveal_cities && NULL != tile_city(ptile)) { - give_tile_info_from_player_to_player(pfrom, pto, ptile); + updt|= give_tile_info_from_player_to_player(pfrom, pto, ptile); } } whole_map_iterate_end; unbuffer_shared_vision(pto); + + return updt; } /**********************************************************************//** diff --git a/server/maphand.h b/server/maphand.h index 825d33ec72..ef62cd4b8e 100644 --- a/server/maphand.h +++ b/server/maphand.h @@ -139,7 +139,7 @@ void create_extra(struct tile *ptile, struct extra_type *pextra, struct player *pplayer); void destroy_extra(struct tile *ptile, struct extra_type *pextra); -void give_distorted_map(struct player *pfrom, struct player *pto, +bool give_distorted_map(struct player *pfrom, struct player *pto, int prob, bool reveal_cities); void tile_change_side_effects(struct tile *ptile, bool refresh_city) diff --git a/server/plrhand.c b/server/plrhand.c index 481725781a..07f9efe55f 100644 --- a/server/plrhand.c +++ b/server/plrhand.c @@ -403,22 +403,39 @@ void government_change(struct player *pplayer, struct government *gov, /**********************************************************************//** pvictor gets parts of treasury, map and cities of pvictim. Normally happens when pvictim's gameloss unit is killed. - FIXME: any control over types of the loot? + FIXME: Any control over types of the loot? + TODO: Proper event types (likely needs a new one). + For now ones related to Huts (similar loot) used. **************************************************************************/ void player_loot_player(struct player *pvictor, struct player *pvictim) { int ransom = fc_rand(1 + pvictim->economic.gold); int n = 1 + fc_rand(3); - /* give map */ - give_distorted_map(pvictim, pvictor, 50, TRUE); + /* Give map */ + if (give_distorted_map(pvictim, pvictor, 50, TRUE)) { + notify_player(pvictor, NULL, E_HUT_MAP, + ftc_server, + _("You looted parts of %s map!"), + nation_adjective_for_player(pvictim)); + } log_debug("victim has money: %d", pvictim->economic.gold); + + if (ransom > 0) { + notify_player(pvictor, NULL, E_HUT_GOLD, + ftc_server, + PL_("You loot %d gold!", "You loot %d gold!", ransom), + ransom); + } pvictor->economic.gold += ransom; pvictim->economic.gold -= ransom; while (n > 0) { - Tech_type_id ttid = steal_a_tech(pvictor, pvictim, A_UNSET); + Tech_type_id ttid; + + /* steal_a_tech() handles also notifying of the player */ + ttid = steal_a_tech(pvictor, pvictim, A_UNSET); if (ttid == A_NONE) { log_debug("Worthless enemy doesn't have more techs to steal."); @@ -427,13 +444,13 @@ void player_loot_player(struct player *pvictor, struct player *pvictim) log_debug("Pressed tech %s from captured enemy", research_advance_rule_name(research_get(pvictor), ttid)); if (!fc_rand(3)) { - break; /* out of luck */ + break; /* Out of luck */ } n--; } } - { /* try to submit some cities */ + { /* Try to submit some cities */ int vcsize = city_list_size(pvictim->cities); int evcsize = vcsize; int conqsize = evcsize; @@ -443,7 +460,7 @@ void player_loot_player(struct player *pvictor, struct player *pvictim) } else { evcsize -=3; } - /* about a quarter on average with high numbers less probable */ + /* About a quarter on average with high numbers less probable */ conqsize = fc_rand(fc_rand(evcsize)); log_debug("conqsize=%d", conqsize); @@ -452,10 +469,10 @@ void player_loot_player(struct player *pvictor, struct player *pvictim) bool palace = game.server.savepalace; bool submit = FALSE; - game.server.savepalace = FALSE; /* moving it around is dumb */ + game.server.savepalace = FALSE; /* Moving it around is dumb */ city_list_iterate_safe(pvictim->cities, pcity) { - /* kindly ask the citizens to submit */ + /* Kindly ask the citizens to submit */ if (fc_rand(vcsize) < conqsize) { submit = TRUE; } @@ -467,6 +484,12 @@ void player_loot_player(struct player *pvictor, struct player *pvictim) * give verbose messages of every unit transferred, * and raze buildings according to raze chance * (also removes palace) */ + notify_player(pvictor, city_tile(pcity), E_UNIT_WIN_ATT, + ftc_server, + /* TRANS: Getting a city as loot */ + _("You conquer %s as loot!"), + city_link(pcity)); + (void) transfer_city(pvictor, pcity, 7, TRUE, TRUE, TRUE, !is_barbarian(pvictor)); submit = FALSE; diff --git a/server/techtools.c b/server/techtools.c index 041cf30294..18e31ea7e1 100644 --- a/server/techtools.c +++ b/server/techtools.c @@ -1256,16 +1256,16 @@ Tech_type_id steal_a_tech(struct player *pplayer, struct player *victim, } advance_index_iterate_max_end; if (j == 0) { - /* we've moved on to future tech */ + /* We've moved on to future tech */ if (vresearch->future_tech > presearch->future_tech) { stolen_tech = A_FUTURE; } else { return A_NONE; } } else { - /* pick random tech */ + /* Pick random tech */ j = fc_rand(j) + 1; - stolen_tech = A_NONE; /* avoid compiler warning */ + stolen_tech = A_NONE; /* Avoid compiler warning */ advance_index_iterate_max(A_FIRST, i, ac) { if (research_invention_gettable(presearch, i, game.info.tech_steal_allow_holes) -- 2.39.2