diff --git a/common/events.cpp b/common/events.cpp index 2d01020751..bf6a71f6ca 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -156,10 +156,12 @@ static struct { GEN_EV(E_TREATY_PEACE, E_S_TREATY, N_("Peace")), GEN_EV(E_TREATY_SHARED_VISION, E_S_TREATY, N_("Shared Vision")), GEN_EV(E_UNIT_LOST_ATT, E_S_UNIT, N_("Attack Failed")), + GEN_EV(E_UNIT_TIE_ATT, E_S_UNIT, N_("Attack Tied")), GEN_EV(E_UNIT_WIN_ATT, E_S_UNIT, N_("Attack Succeeded")), GEN_EV(E_UNIT_BUY, E_S_UNIT, N_("Bought")), GEN_EV(E_UNIT_BUILT, E_S_UNIT, N_("Built")), GEN_EV(E_UNIT_LOST_DEF, E_S_UNIT, N_("Defender Destroyed")), + GEN_EV(E_UNIT_TIE_DEF, E_S_UNIT, N_("Defender Tied")), GEN_EV(E_UNIT_WIN_DEF, E_S_UNIT, N_("Defender Survived")), GEN_EV(E_UNIT_BECAME_VET, E_S_UNIT, N_("Promoted to Veteran")), GEN_EV(E_UNIT_LOST_MISC, E_S_UNIT, N_("Lost Outside Battle")), diff --git a/common/events.h b/common/events.h index 479bc29d9b..1d3e98396f 100644 --- a/common/events.h +++ b/common/events.h @@ -165,6 +165,10 @@ #define SPECENUM_VALUE133 E_UNIT_ACTION_TARGET_OTHER #define SPECENUM_VALUE134 E_UNIT_ACTION_TARGET_HOSTILE #define SPECENUM_VALUE135 E_UNIT_WAKE +// -- +#define SPECENUM_VALUE136 E_UNIT_TIE_ATT +#define SPECENUM_VALUE137 E_UNIT_TIE_DEF + /* * Note: If you add a new event, make sure you make a similar change * to the events array in "common/events.c" using GEN_EV, to diff --git a/common/featured_text.cpp b/common/featured_text.cpp index 58c164cd20..70e5ecb5b7 100644 --- a/common/featured_text.cpp +++ b/common/featured_text.cpp @@ -1164,8 +1164,7 @@ const char *unit_achieved_rank_string(const struct unit *punit) fc_snprintf(buf, sizeof(buf), /* TRANS: " and achieved the rank of "; * preserve leading space */ - _(" and achieved the rank of %s"), - unit_veteran_level_string(punit)); + _(", promoted to %s"), unit_veteran_level_string(punit)); return buf; } @@ -1208,3 +1207,21 @@ const char *unit_firepower_if_not_one(int firepower) } return buf; } + +/** + Get string of number of extra units killed by attacker + when a stack is taken down. + N.B.: The returned string is static, so every call to this function + overwrites the previous. + */ +const char *unit_n_stack_kills(int unitcount) +{ + static char buf[MAX_LEN_LINK]; + + if (unitcount > 2) { + fc_snprintf(buf, sizeof(buf), _("%d units were"), unitcount = 1); + } else { + fc_snprintf(buf, sizeof(buf), _("unit was")); + } + return buf; +} diff --git a/common/featured_text.h b/common/featured_text.h index 3fbc68caaf..1d4d5c18ea 100644 --- a/common/featured_text.h +++ b/common/featured_text.h @@ -238,3 +238,5 @@ const char *unit_veteran_level_string(const struct unit *punit); const char *unit_achieved_rank_string(const struct unit *punit); const char *unit_tired_attack_string(const struct unit *punit); const char *unit_firepower_if_not_one(int firepower); +const char *unit_firepower_if_not_one(int firepower); +const char *unit_n_stack_kills(int unitcount); \ No newline at end of file diff --git a/data/misc/events.png b/data/misc/events.png index f878d72654..50cb4f3200 100644 Binary files a/data/misc/events.png and b/data/misc/events.png differ diff --git a/data/misc/events.spec b/data/misc/events.spec index cbb803f1c0..65216e9422 100644 --- a/data/misc/events.spec +++ b/data/misc/events.spec @@ -81,28 +81,30 @@ tiles = { "row", "column", "tag" 2, 11, "e_tech_goal" 3, 0, "e_unit_lost_att" - 3, 1, "e_unit_win_att" - 3, 1, "e_unit_action_actor_success" - 3, 2, "e_unit_buy" - 3, 3, "e_unit_built" - 3, 4, "e_unit_lost_def" - 3, 4, "e_unit_action_target_hostile" - 3, 4, "e_unit_wake" - 3, 5, "e_unit_lost_misc" - 3, 6, "e_unit_became_vet" - 3, 7, "e_unit_upgraded" - 3, 8, "e_unit_relocated" - 3, 9, "e_unit_orders" - 3, 10, "e_unit_illegal_action" - 3, 11, "e_caravan_action" - 3, 12, "e_unit_win_def" - 3, 13, "e_unit_escaped" - 3, 14, "e_unit_was_expelled" - 3, 15, "e_unit_did_expel" - 3, 16, "e_unit_action_failed" - 3, 17, "e_my_unit_did_heal" - 3, 18, "e_my_unit_was_healed" - 3, 19, "e_unit_action_target_other" + 3, 1, "e_unit_tie_att" + 3, 2, "e_unit_win_att" + 3, 2, "e_unit_action_actor_success" + 3, 3, "e_unit_buy" + 3, 4, "e_unit_built" + 3, 5, "e_unit_lost_def" + 3, 5, "e_unit_action_target_hostile" + 3, 5, "e_unit_wake" + 3, 6, "e_unit_lost_misc" + 3, 7, "e_unit_became_vet" + 3, 8, "e_unit_upgraded" + 3, 9, "e_unit_relocated" + 3, 10, "e_unit_orders" + 3, 11, "e_unit_illegal_action" + 3, 12, "e_caravan_action" + 3, 13, "e_unit_tie_def" + 3, 14, "e_unit_win_def" + 3, 15, "e_unit_escaped" + 3, 16, "e_unit_was_expelled" + 3, 17, "e_unit_did_expel" + 3, 18, "e_unit_action_failed" + 3, 20, "e_my_unit_did_heal" + 3, 20, "e_my_unit_was_healed" + 3, 20, "e_unit_action_target_other" 3, 20, "e_unit_action_actor_failure" 4, 0, "e_my_diplomat_escape" ; base sprite for my diplomats diff --git a/data/stdsounds.soundspec b/data/stdsounds.soundspec index 7e9a5180c5..fbbf0b5512 100644 --- a/data/stdsounds.soundspec +++ b/data/stdsounds.soundspec @@ -308,7 +308,9 @@ e_log_fatal = "stdsounds/LrgExpl.ogg" ; [warzone] ;e_unit_orders = "" ;e_unit_relocated = "" ;e_unit_upgraded = "" +;e_unit_tie_def = "" ;e_unit_win_def = "" +;e_unit_tie_att = "" ;e_unit_win_att = "" ;e_unit_did_expel = "" ;e_unit_was_expelled = "" diff --git a/server/unithand.cpp b/server/unithand.cpp index 808281dc05..0997d03f0c 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -3905,20 +3905,18 @@ static bool unit_do_destroy_city(struct player *act_player, This function assumes the attack is legal. The calling function should have already made all necessary checks. - Returns TRUE iff action could be done, FALSE if it couldn't. Even if + Returns TRUE if action could be done, FALSE if it couldn't. Even if this returns TRUE, unit may have died during the action. */ static bool do_attack(struct unit *punit, struct tile *def_tile, const struct action *paction) { - char loser_link[MAX_LEN_LINK], winner_link[MAX_LEN_LINK]; + char attacker_link[MAX_LEN_LINK], defender_link[MAX_LEN_LINK]; char attacker_vet[MAX_LEN_LINK], defender_vet[MAX_LEN_LINK]; char attacker_fp[MAX_LEN_LINK], defender_fp[MAX_LEN_LINK]; char attacker_tired[MAX_LEN_LINK]; - struct unit *ploser, *pwinner; int moves_used, def_moves_used; - int old_unit_vet, old_defender_vet, vet; - int winner_id; + int old_unit_vet, old_defender_vet; struct player *pplayer = unit_owner(punit); bool adj; enum direction8 facing; @@ -4022,81 +4020,105 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, action_consequence_success(paction, pplayer, unit_owner(pdefender), def_tile, unit_link(pdefender)); - if (punit->hp > 0 && pdefender->hp > 0) { - // Neither died - send_combat(punit, pdefender, punit->veteran - old_unit_vet, - pdefender->veteran - old_defender_vet, 0); - return true; - } - pwinner = (punit->hp > 0) ? punit : pdefender; - winner_id = pwinner->id; - ploser = (pdefender->hp > 0) ? punit : pdefender; - - vet = (pwinner->veteran - == ((punit->hp > 0) ? old_unit_vet : old_defender_vet)) - ? 0 - : 1; - send_combat(punit, pdefender, punit->veteran - old_unit_vet, pdefender->veteran - old_defender_vet, 0); - // N.B.: unit_link always returns the same pointer. - sz_strlcpy(loser_link, unit_tile_link(ploser)); - sz_strlcpy(winner_link, - utype_is_consumed_by_action(paction, pwinner->utype) - ? unit_tile_link(pwinner) - : unit_link(pwinner)); + // Neither died + if (punit->hp > 0 && pdefender->hp > 0) { + // both units are alive - link to them. + sz_strlcpy(attacker_link, unit_link(punit)); + sz_strlcpy(defender_link, unit_link(pdefender)); - if (punit == ploser) { - // The attacker lost - log_debug("Attacker lost: %s %s against %s %s.", + log_debug("Tied battle: %s %s against %s %s.", nation_rule_name(nation_of_player(pplayer)), unit_rule_name(punit), nation_rule_name(nation_of_unit(pdefender)), unit_rule_name(pdefender)); + // notify attacker of battle tie notify_player( - unit_owner(pwinner), unit_tile(pwinner), E_UNIT_WIN_DEF, ftc_server, - /* TRANS: "Your green Legion [id:100 ...D:4.0 lost 1 HP, - * 9 HP remaining] survived the pathetic ...attack from the - * green Greek Warriors [id:90 ...A:1.0 HP:10]. */ - _("Your %s %s [id:%d %sD:%.1f lost %d HP, %d HP remaining]" - " survived the pathetic %sattack from the %s %s %s " - "[id:%d %sA:%.1f HP:%d]."), - defender_vet, winner_link, pdefender->id, defender_fp, + unit_owner(punit), unit_tile(punit), E_UNIT_TIE_ATT, ftc_server, + /* TRANS: "Your green Warrior [id:100 ...A:1.0, lost 3 HP, + * 7 HP remaining] attacked the Greek Polish Archer [id:200 + * ...D:8.0, lost 5 HP, 5 HP remaining]!"*/ + _("Your %s %s [id:%d %sA:%.1f, lost %d HP, %d HP remaining]" + " attacked the %s %s %s [id:%d %sD:%.1f, lost %d" + " HP, %d HP remaining%s]!"), + attacker_vet, attacker_link, punit->id, attacker_fp, + (float) att_power / POWER_FACTOR, att_hp_start - punit->hp, + punit->hp, nation_adjective_for_player(unit_owner(pdefender)), + defender_vet, defender_link, pdefender->id, defender_fp, (float) def_power / POWER_FACTOR, def_hp_start - pdefender->hp, - pdefender->hp, attacker_tired, - nation_adjective_for_player(unit_owner(ploser)), attacker_vet, - loser_link, punit->id, attacker_fp, (float) att_power / POWER_FACTOR, - att_hp_start); + pdefender->hp, + (pdefender->veteran - old_defender_vet) + ? unit_achieved_rank_string(pdefender) + : ""); + + // notify attacker of promotion + if (punit->veteran == old_unit_vet ? 0 : 1) { + notify_unit_experience(punit); + } - if (vet) { - notify_unit_experience(pwinner); + // notify defender of battle tie + notify_player( + unit_owner(pdefender), unit_tile(pdefender), E_UNIT_TIE_DEF, + ftc_server, + /* TRANS: "Your green Warrior [id:100 ...A:1.0, lost 3 HP, + * 7 HP remaining%s] was attacked by the Greek Polish Archer [id:200 + * ...D:8.0, lost 5 HP, 5 HP remaining%s]!"; + * The %s's after "remaining" are either rankup strings or empty */ + _("Your %s %s [id:%d %sA:%.1f, lost %d HP, %d HP remaining]" + " was attacked by the %s %s %s [id:%d %sD:%.1f, lost %d" + " HP, %d HP remaining%s]!"), + defender_vet, defender_link, pdefender->id, defender_fp, + (float) def_power / POWER_FACTOR, def_hp_start - pdefender->hp, + pdefender->hp, nation_adjective_for_player(unit_owner(punit)), + attacker_vet, attacker_link, punit->id, attacker_fp, + (float) att_power / POWER_FACTOR, att_hp_start - punit->hp, + punit->hp, + (punit->veteran - old_unit_vet) ? unit_achieved_rank_string(punit) + : ""); + + // notify defender of promotion + if (pdefender->veteran == old_defender_vet ? 0 : 1) { + notify_unit_experience(pdefender); } - notify_player(unit_owner(ploser), def_tile, E_UNIT_LOST_ATT, ftc_server, - /* TRANS: "Your attacking green Cannon [id:100 ...A:8.0 - * failed against the Greek Polish Destroyer [id:200 lost - * 27 HP, 3 HP remaining%s]!"; - * last %s is either "and ..." or empty string */ - _("Your attacking %s %s [id:%d %sA:%.1f HP:%d] failed " - "against the %s %s %s [id:%d lost %d HP, %d HP " - "remaining%s]!"), - attacker_vet, loser_link, punit->id, attacker_fp, - (float) att_power / POWER_FACTOR, att_hp_start, - nation_adjective_for_player(unit_owner(pdefender)), - defender_vet, winner_link, pdefender->id, - def_hp_start - pdefender->hp, pdefender->hp, - vet ? unit_achieved_rank_string(pdefender) : ""); - wipe_unit(ploser, ULR_KILLED, unit_owner(pwinner)); - } else { - // The defender lost, the attacker punit lives! + return true; + } + + // attacker killed the defender + if (punit->hp > 0 && pdefender->hp <= 0) { + // defender is dead; link to tile instead. + sz_strlcpy(attacker_link, unit_link(punit)); + sz_strlcpy(defender_link, unit_tile_link(pdefender)); - log_debug("Defender lost: %s %s against %s %s.", + log_debug("Attacker won: %s %s against %s %s.", nation_rule_name(nation_of_player(pplayer)), unit_rule_name(punit), nation_rule_name(nation_of_unit(pdefender)), unit_rule_name(pdefender)); + // notify the attacker of victory + notify_player( + unit_owner(punit), unit_tile(punit), E_UNIT_WIN_ATT, ftc_server, + /* TRANS: "Your attacking green Legion [id:200 ...A:4.0 + * lost 1 HP, has 9 HP remaining%s] succeeded against the + * Greek green Warriors [id:100 HP:10]." */ + _("Your %s %s [id:%d %s%sA:%.1f, lost %d HP, " + "has %d remaining] eliminated the %s %s %s " + "[id:%d %sD:%.1f, lost %d HP]."), + attacker_vet, attacker_link, punit->id, attacker_fp, attacker_tired, + (float) att_power / POWER_FACTOR, att_hp_start - punit->hp, + punit->hp, nation_adjective_for_player(unit_owner(pdefender)), + defender_vet, defender_link, pdefender->id, defender_fp, + (float) def_power / POWER_FACTOR, def_hp_start); + + // notify attacker of promotion + if (punit->veteran == old_unit_vet ? 0 : 1) { + notify_unit_experience(punit); + } + + // notify defender of defeat notify_player(unit_owner(pdefender), unit_tile(pdefender), E_UNIT_LOST_DEF, ftc_server, /* TRANS: "Your green Warriors [id:100 ...D:1.0 HP:10] @@ -4104,32 +4126,22 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, * [id:200 ...A:4.0 lost 1 HP, has 9 HP remaining%s]." * last %s is either "and ..." or empty string */ _("Your %s %s [id:%d %sD:%.1f HP:%d] lost to an attack by " - "the %s %s %s [id:%d %sA:%.1f lost %d HP, has %d HP " + "the %s %s %s [id:%d %s%sA:%.1f, lost %d HP, has %d HP " "remaining%s]."), - defender_vet, loser_link, pdefender->id, defender_fp, + defender_vet, defender_link, pdefender->id, defender_fp, (float) def_power / POWER_FACTOR, def_hp_start, nation_adjective_for_player(unit_owner(punit)), - attacker_vet, winner_link, punit->id, attacker_fp, - (float) att_power / POWER_FACTOR, - att_hp_start - pwinner->hp, pwinner->hp, - vet ? unit_achieved_rank_string(punit) : ""); - - notify_player( - unit_owner(punit), unit_tile(punit), E_UNIT_WIN_ATT, ftc_server, - /* TRANS: "Your attacking green Legion [id:200 ...A:4.0 - * lost 1 HP, has 9 HP remaining] succeeded against the - * Greek green Warriors [id:100 HP:10]." */ - _("Your attacking %s %s [id:%d %s%sA:%.1f lost %d HP, " - "has %d remaining] succeeded against the %s %s %s " - "[id:%d HP:%d]."), - attacker_vet, winner_link, punit->id, attacker_fp, attacker_tired, - (float) att_power / POWER_FACTOR, att_hp_start - pwinner->hp, - pwinner->hp, nation_adjective_for_player(unit_owner(pdefender)), - defender_vet, loser_link, pdefender->id, def_hp_start); + attacker_vet, attacker_link, punit->id, attacker_fp, + attacker_tired, (float) att_power / POWER_FACTOR, + att_hp_start - punit->hp, punit->hp, + (punit->veteran - old_unit_vet) + ? unit_achieved_rank_string(punit) + : ""); punit->moved = true; // We moved - kill_unit(pwinner, ploser, - vet && !utype_is_consumed_by_action(paction, punit->utype)); + kill_unit(punit, pdefender, + punit->veteran == old_unit_vet + && !utype_is_consumed_by_action(paction, punit->utype)); /* Now that dead defender is certainly no longer listed as unit * supported by the city, we may even remove the city @@ -4137,30 +4149,84 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, if (auto pcity = tile_city(def_tile); pcity != nullptr) { unit_attack_civilian_casualties(punit, pcity, paction, "attack"); } - if (unit_is_alive(winner_id)) { - if (utype_is_consumed_by_action(paction, pwinner->utype)) { - return true; + if (!utype_is_consumed_by_action(paction, punit->utype)) { + /* If attacker wins, and occupychance > 0, it might move in. Don't + * move in if there are enemy units in the tile (a fortress, city or + * air base with multiple defenders and unstacked combat). Note that + * this could mean capturing (or destroying) a city. */ + if (fc_rand(100) < game.server.occupychance + && !is_non_allied_unit_tile(def_tile, pplayer)) { + occupy_move(punit, def_tile); + } + // The attacker may have died for many reasons + // 2024-09-04 HF: Not very sure why this is needed here + // but not in the other outcome cases? Is send_combat() + // doing this as well? + if (game_unit_by_number(punit->id) != nullptr) { + send_unit_info(nullptr, punit); } - } else { - return true; } + return true; } - /* If attacker wins, and occupychance > 0, it might move in. Don't move in - * if there are enemy units in the tile (a fortress, city or air base with - * multiple defenders and unstacked combat). Note that this could mean - * capturing (or destroying) a city. */ + // defender killed the attacker + if (punit->hp <= 0 && pdefender->hp > 0) { + // attacker is dead; link to tile instead. + sz_strlcpy(attacker_link, unit_tile_link(punit)); + sz_strlcpy(defender_link, unit_link(pdefender)); - if (pwinner == punit && fc_rand(100) < game.server.occupychance - && !is_non_allied_unit_tile(def_tile, pplayer)) { - occupy_move(punit, def_tile); - } + // The attacker lost + log_debug("Attacker lost: %s %s against %s %s.", + nation_rule_name(nation_of_player(pplayer)), + unit_rule_name(punit), + nation_rule_name(nation_of_unit(pdefender)), + unit_rule_name(pdefender)); - // The attacker may have died for many reasons - if (game_unit_by_number(winner_id) != nullptr) { - send_unit_info(nullptr, pwinner); - } + // notify attacker of defeat + notify_player(unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, + ftc_server, + /* TRANS: "Your attacking green Cannon [id:100 ...A:8.0 + * failed against the Greek Polish Destroyer [id:200 lost + * 27 HP, 3 HP remaining%s]!"; + * last %s is either "and ..." or empty string */ + _("Your %s %s [id:%d %sA:%.1f, lost %d HP] were defeated " + "by the %s %s %s [id:%d lost %d HP, %d HP " + "remaining%s]!"), + attacker_vet, attacker_link, punit->id, attacker_fp, + (float) att_power / POWER_FACTOR, att_hp_start, + nation_adjective_for_player(unit_owner(pdefender)), + defender_vet, defender_link, pdefender->id, + def_hp_start - pdefender->hp, pdefender->hp, + (pdefender->veteran - old_defender_vet) + ? unit_achieved_rank_string(pdefender) + : ""); + // notify defender of victory + notify_player( + unit_owner(pdefender), def_tile, E_UNIT_WIN_DEF, ftc_server, + /* TRANS: "Your green Legion [id:100 ...D:4.0 lost 1 HP, + * 9 HP remaining] survived the pathetic ...attack from the + * green Greek Warriors [id:90 ...A:1.0 HP:10]. */ + _("Your %s %s [id:%d %sD:%.1f lost %d HP, %d HP remaining]" + " survived the pathetic %sattack from the %s %s %s " + "[id:%d %sA:%.1f HP:%d]."), + defender_vet, defender_link, pdefender->id, defender_fp, + (float) def_power / POWER_FACTOR, def_hp_start - pdefender->hp, + pdefender->hp, attacker_tired, + nation_adjective_for_player(unit_owner(punit)), attacker_vet, + attacker_link, punit->id, attacker_fp, + (float) att_power / POWER_FACTOR, att_hp_start); + + // notify defender of promotion + if (pdefender->veteran == old_defender_vet ? 0 : 1) { + notify_unit_experience(pdefender); + } + + wipe_unit(punit, ULR_KILLED, unit_owner(pdefender)); + return true; + } + // this function should have not passed through this line of code + fc_assert_ret_val(false, true); return true; } diff --git a/server/unittools.cpp b/server/unittools.cpp index 6178118326..3614ab49e1 100644 --- a/server/unittools.cpp +++ b/server/unittools.cpp @@ -33,6 +33,7 @@ #include "city.h" #include "combat.h" #include "events.h" +#include "featured_text.h" #include "game.h" #include "government.h" #include "idex.h" @@ -2468,9 +2469,6 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) } if (!is_stack_vulnerable(unit_tile(punit)) || unitcount == 1) { - if (vet) { - notify_unit_experience(pkiller); - } wipe_unit(punit, ULR_KILLED, pvictor); } else { // unitcount > 1 int i; @@ -2559,18 +2557,9 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) /* Inform the destroyer again if more than one unit was killed */ if (unitcount > 1) { notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server, - /* TRANS: "... Cannon ... the Polish Destroyer ...." */ - PL_("Your attacking %s succeeded against the %s %s " - "(and %d other unit)!", - "Your attacking %s succeeded against the %s %s " - "(and %d other units)!", - unitcount - 1), - pkiller_link, nation_adjective_for_player(pvictim), - punit_link, unitcount - 1); - } - - if (vet) { - notify_unit_experience(pkiller); + /* TRANS: "Another unit was eliminated by..." */ + "Another %s eliminated by our attacking %s!", + unit_n_stack_kills(unitcount), punit_link); } /* inform the owners: this only tells about owned units that were killed. @@ -2586,15 +2575,16 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) notify_player(player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, // TRANS: "Cannon ... the Polish Destroyer." - _("%s lost to an attack by the %s %s."), punit_link, - nation_adjective_for_player(pvictor), pkiller_link); + _("%s lost when the %s %s defeated your %s."), + punit_link, nation_adjective_for_player(pvictor), + pkiller_link, punit_link); } else { fc_assert(other_killed[i] != punit); notify_player(player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, /* TRANS: "Cannon lost when the Polish Destroyer * attacked the German Musketeers." */ - _("%s lost when the %s %s attacked the %s %s."), + _("%s lost when the %s %s defeated the %s %s."), unit_link(other_killed[i]), nation_adjective_for_player(pvictor), pkiller_link, nation_adjective_for_player(pvictim), punit_link); @@ -2602,37 +2592,24 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) } else if (num_killed[i] > 1) { if (i == player_index(pvictim)) { int others = num_killed[i] - 1; - - if (others == 1) { - notify_player( - player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, - /* TRANS: "Musketeers (and Cannon) lost to an - * attack from the Polish Destroyer." */ - _("%s (and %s) lost to an attack from the %s %s."), - punit_link, unit_link(other_killed[i]), - nation_adjective_for_player(pvictor), pkiller_link); - } else { - notify_player( - player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, - /* TRANS: "Musketeers and 3 other units lost to - * an attack from the Polish Destroyer." - * (only happens with at least 2 other units) */ - PL_("%s and %d other unit lost to an attack " - "from the %s %s.", - "%s and %d other units lost to an attack " - "from the %s %s.", - others), - punit_link, others, nation_adjective_for_player(pvictor), - pkiller_link); - } + notify_player( + player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, + /* TRANS: "Musketeers and 3 other units lost to + * an attack from the Polish Destroyer." + * (only happens with at least 2 other units) */ + PL_("%d other unit lost when the %s %s defeated your %s.", + "%d other units lost when the %s %s defeated your %s.", + others), + others, nation_adjective_for_player(pvictor), pkiller_link, + punit_link); } else { notify_player( player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, /* TRANS: "2 units lost when the Polish Destroyer * attacked the German Musketeers." * (only happens with at least 2 other units) */ - PL_("%d unit lost when the %s %s attacked the %s %s.", - "%d units lost when the %s %s attacked the %s %s.", + PL_("%d unit lost when the %s %s defeated the %s %s.", + "%d units lost when the %s %s defeated the %s %s.", num_killed[i]), num_killed[i], nation_adjective_for_player(pvictor), pkiller_link, nation_adjective_for_player(pvictim),