Skip to content

Commit

Permalink
Only send bombardment combat when targets are visible
Browse files Browse the repository at this point in the history
Bombarding cities was very powerful because it was showing every unit
inside the city, something only diplomats and spies can normally do.
Stop sending this around.
  • Loading branch information
lmoureaux committed Sep 7, 2024
1 parent fe6dc4a commit 7a72b5c
Showing 1 changed file with 39 additions and 15 deletions.
54 changes: 39 additions & 15 deletions server/unithand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3530,10 +3530,21 @@ void handle_unit_change_activity(struct player *pplayer, int unit_id,
activity_target);
}

/**
* How much information users can see about a combat.
*/
enum class combat_visibility {
/// Anyone who can see the tile can see the unit fighting there
full,
/// The defensor is hidden to those who cannot normally see it
defensor_hidden,
};

/**
Make sure everyone who can see combat does.
*/
static void see_combat(struct unit *pattacker, struct unit *pdefender)
static void see_combat(struct unit *pattacker, struct unit *pdefender,
combat_visibility visibility)
{
struct packet_unit_short_info unit_att_short_packet, unit_def_short_packet;
struct packet_unit_info unit_att_packet, unit_def_packet;
Expand All @@ -3556,6 +3567,8 @@ static void see_combat(struct unit *pattacker, struct unit *pdefender)
package_unit(pattacker, &unit_att_packet);
package_unit(pdefender, &unit_def_packet);

bool always_show_defender = (visibility == combat_visibility::full);

conn_list_iterate(game.est_connections, pconn)
{
struct player *pplayer = pconn->playing;
Expand All @@ -3567,15 +3580,16 @@ static void see_combat(struct unit *pattacker, struct unit *pdefender)
|| map_is_known_and_seen(unit_tile(pdefender), pplayer, V_MAIN)) {
/* Units are sent even if they were visible already. They may
* have changed orientation for combat. */
if (pplayer == unit_owner(pattacker)) {
if (players_on_same_team(pplayer, unit_owner(pattacker))) {
send_packet_unit_info(pconn, &unit_att_packet);
} else {
send_packet_unit_short_info(pconn, &unit_att_short_packet, false);
}

if (pplayer == unit_owner(pdefender)) {
if (players_on_same_team(pplayer, unit_owner(pdefender))) {
send_packet_unit_info(pconn, &unit_def_packet);
} else {
} else if (always_show_defender
|| can_player_see_unit(pplayer, pdefender)) {
send_packet_unit_short_info(pconn, &unit_def_short_packet, false);
}
}
Expand All @@ -3592,7 +3606,8 @@ static void see_combat(struct unit *pattacker, struct unit *pdefender)
Send combat info to players.
*/
static void send_combat(struct unit *pattacker, struct unit *pdefender,
int att_veteran, int def_veteran, int bombard)
int att_veteran, int def_veteran,
combat_visibility visibility)
{
struct packet_unit_combat_info combat;

Expand All @@ -3603,23 +3618,30 @@ static void send_combat(struct unit *pattacker, struct unit *pdefender,
combat.make_att_veteran = att_veteran;
combat.make_def_veteran = def_veteran;

bool always_show_defender = (visibility == combat_visibility::full);

players_iterate(other_player)
{
/* NOTE: this means the player can see combat between submarines even
* if neither sub is visible. See similar comment in see_combat. */
if (map_is_known_and_seen(unit_tile(pattacker), other_player, V_MAIN)
|| map_is_known_and_seen(unit_tile(pdefender), other_player,
V_MAIN)) {
lsend_packet_unit_combat_info(other_player->connections, &combat);
// Only send the combat if the attacker can see the defender, so we
// don't leak info about the number of defenders.
if (always_show_defender
|| can_player_see_unit(other_player, pdefender)) {
lsend_packet_unit_combat_info(other_player->connections, &combat);
}

/*
* Remove the client knowledge of the units. This corresponds to the
* send_packet_unit_short_info calls up above.
*/
// Remove the client knowledge of the units. This corresponds to the
// send_packet_unit_short_info calls in see_combat.
if (!can_player_see_unit(other_player, pattacker)) {
unit_goes_out_of_sight(other_player, pattacker);
}
if (!can_player_see_unit(other_player, pdefender)) {
// Only send a remove packet if we sent the defender earlier.
if (always_show_defender
&& !can_player_see_unit(other_player, pdefender)) {
unit_goes_out_of_sight(other_player, pdefender);
}
}
Expand Down Expand Up @@ -3724,12 +3746,13 @@ static bool unit_bombard(struct unit *punit, struct tile *ptile,
nation_adjective_for_player(pplayer),
unit_name_translation(punit));

see_combat(punit, pdefender);
see_combat(punit, pdefender, combat_visibility::defensor_hidden);

punit->hp = att_hp;
pdefender->hp = def_hp;

send_combat(punit, pdefender, 0, 0, 1);
send_combat(punit, pdefender, 0, 0,
combat_visibility::defensor_hidden);

send_unit_info(nullptr, pdefender);

Expand Down Expand Up @@ -3989,7 +4012,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile,
unit_transport_unload_send(punit);
}

see_combat(punit, pdefender);
see_combat(punit, pdefender, combat_visibility::full);

punit->hp = att_hp;
pdefender->hp = def_hp;
Expand Down Expand Up @@ -4021,7 +4044,8 @@ static bool do_attack(struct unit *punit, struct tile *def_tile,
def_tile, unit_link(pdefender));

send_combat(punit, pdefender, punit->veteran - old_unit_vet,
pdefender->veteran - old_defender_vet, 0);
pdefender->veteran - old_defender_vet,
combat_visibility::full);

// Neither died
if (punit->hp > 0 && pdefender->hp > 0) {
Expand Down

0 comments on commit 7a72b5c

Please sign in to comment.