From 35516386d5f877f19945a068c9b726bae5b7c87a Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Wed, 4 Sep 2024 15:04:58 -0400 Subject: [PATCH 01/16] improved battle messages (closes #2358) --- common/events.cpp | 2 + common/events.h | 4 + common/featured_text.cpp | 21 +++- common/featured_text.h | 2 + data/misc/events.png | Bin 12893 -> 16111 bytes data/misc/events.spec | 46 +++---- data/stdsounds.soundspec | 2 + server/unithand.cpp | 264 ++++++++++++++++++++++++--------------- server/unittools.cpp | 63 +++------- 9 files changed, 238 insertions(+), 166 deletions(-) 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 f878d726543c052927e79d4a080f86b50b165532..50cb4f320033b39f92ba6104c0abe4ba850534b4 100644 GIT binary patch literal 16111 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 > 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), From 7c7fb3b3080d14ef0843733af4aff8c297d8e428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:08:19 -0400 Subject: [PATCH 02/16] Update common/featured_text.h as suggesed by @lmoureaux Co-authored-by: Louis Moureaux --- common/featured_text.h | 1 - 1 file changed, 1 deletion(-) diff --git a/common/featured_text.h b/common/featured_text.h index 1d4d5c18ea..a4e407b3a7 100644 --- a/common/featured_text.h +++ b/common/featured_text.h @@ -238,5 +238,4 @@ 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 From 1b9b70d660f228d366f3c62306868670ddd60594 Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Wed, 4 Sep 2024 16:28:48 -0400 Subject: [PATCH 03/16] remove unit_n_stack_kills --- common/featured_text.cpp | 18 ------------------ common/featured_text.h | 1 - server/unittools.cpp | 6 ++++-- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/common/featured_text.cpp b/common/featured_text.cpp index 70e5ecb5b7..02b522bbfd 100644 --- a/common/featured_text.cpp +++ b/common/featured_text.cpp @@ -1207,21 +1207,3 @@ 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 a4e407b3a7..3fbc68caaf 100644 --- a/common/featured_text.h +++ b/common/featured_text.h @@ -238,4 +238,3 @@ 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_n_stack_kills(int unitcount); \ No newline at end of file diff --git a/server/unittools.cpp b/server/unittools.cpp index 3614ab49e1..e3051ad355 100644 --- a/server/unittools.cpp +++ b/server/unittools.cpp @@ -2558,8 +2558,10 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) if (unitcount > 1) { notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server, /* TRANS: "Another unit was eliminated by..." */ - "Another %s eliminated by our attacking %s!", - unit_n_stack_kills(unitcount), punit_link); + PL_("Another unit was eliminated by your attacking %s!", + "Another %2$d units were eliminated by your attacking %1$s!", + unitcount - 1), + punit_link, unitcount - 1); } /* inform the owners: this only tells about owned units that were killed. From 3ca7be798a8530d42da1e34e04ab65c897a7fd6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:38:29 -0400 Subject: [PATCH 04/16] Update common/events.h as suggested by @lmoureaux Co-authored-by: Louis Moureaux --- common/events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/events.h b/common/events.h index 1d3e98396f..5923113a9e 100644 --- a/common/events.h +++ b/common/events.h @@ -165,7 +165,7 @@ #define SPECENUM_VALUE133 E_UNIT_ACTION_TARGET_OTHER #define SPECENUM_VALUE134 E_UNIT_ACTION_TARGET_HOSTILE #define SPECENUM_VALUE135 E_UNIT_WAKE -// -- +// Combat without winner (Combat_Rounds) #define SPECENUM_VALUE136 E_UNIT_TIE_ATT #define SPECENUM_VALUE137 E_UNIT_TIE_DEF From 00ce3282721de59d1f300852f8d957e0e236d44d Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Wed, 4 Sep 2024 16:53:02 -0400 Subject: [PATCH 05/16] ran clang on troublesome file --- server/unittools.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/server/unittools.cpp b/server/unittools.cpp index e3051ad355..ed5f852c31 100644 --- a/server/unittools.cpp +++ b/server/unittools.cpp @@ -2556,12 +2556,13 @@ 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: "Another unit was eliminated by..." */ - PL_("Another unit was eliminated by your attacking %s!", - "Another %2$d units were eliminated by your attacking %1$s!", - unitcount - 1), - punit_link, unitcount - 1); + notify_player( + pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server, + /* TRANS: "Another unit was eliminated by..." */ + PL_("Another unit was eliminated by your attacking %s!", + "Another %2$d units were eliminated by your attacking %1$s!", + unitcount - 1), + punit_link, unitcount - 1); } /* inform the owners: this only tells about owned units that were killed. From e7b5d33b353b0eb93382524e7a42fdaccc133056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:39:56 -0400 Subject: [PATCH 06/16] remove return true statment as suggested by @lmoureaux Co-authored-by: Louis Moureaux --- server/unithand.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 0997d03f0c..5825ad9df6 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4227,7 +4227,6 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, } // this function should have not passed through this line of code fc_assert_ret_val(false, true); - return true; } /** From 773a94f775b334acda3b1130ff815d442b652135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:11:15 -0400 Subject: [PATCH 07/16] Update server/unittools.cpp as suggested by @lmoureaux Co-authored-by: Louis Moureaux --- server/unittools.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/unittools.cpp b/server/unittools.cpp index ed5f852c31..01d9a17197 100644 --- a/server/unittools.cpp +++ b/server/unittools.cpp @@ -2600,11 +2600,11 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) /* 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.", + PL_("One other unit lost when the %s %s defeated your %s.", + "%4$d other units lost when the %s %s defeated your %s.", others), - others, nation_adjective_for_player(pvictor), pkiller_link, - punit_link); + punit_link, nation_adjective_for_player(pvictor), pkiller_link, + others); } else { notify_player( player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, From f45364720db09fef85a545c3576af1207380c52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:00:14 -0400 Subject: [PATCH 08/16] Update server/unithand.cpp following suggestion by @lmoureaux Co-authored-by: Louis Moureaux --- server/unithand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 5825ad9df6..6dc6f17fe0 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4080,7 +4080,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, : ""); // notify defender of promotion - if (pdefender->veteran == old_defender_vet ? 0 : 1) { + if (pdefender->veteran != old_defender_vet) { notify_unit_experience(pdefender); } return true; From 81a2caa8e8ac8448164979a16e24352133e07e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:00:29 -0400 Subject: [PATCH 09/16] Update server/unithand.cpp following suggestion by @lmoureaux Co-authored-by: Louis Moureaux --- server/unithand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 6dc6f17fe0..a1e1ee5677 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4114,7 +4114,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, (float) def_power / POWER_FACTOR, def_hp_start); // notify attacker of promotion - if (punit->veteran == old_unit_vet ? 0 : 1) { + if (punit->veteran != old_unit_vet) { notify_unit_experience(punit); } From 71c7e55010627bb59e421d2da47cc483c665d5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:00:42 -0400 Subject: [PATCH 10/16] Update server/unithand.cpp following suggestion by @lmoureaux Co-authored-by: Louis Moureaux --- server/unithand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index a1e1ee5677..22d0b8b70a 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4055,7 +4055,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, : ""); // notify attacker of promotion - if (punit->veteran == old_unit_vet ? 0 : 1) { + if (punit->veteran != old_unit_vet) { notify_unit_experience(punit); } From 874e0febc127fa637ca25e41f7a594dae0f46f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:01:09 -0400 Subject: [PATCH 11/16] Update server/unithand.cpp following suggestion by @lmoureaux Co-authored-by: Louis Moureaux --- server/unithand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 22d0b8b70a..fc6735e687 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4050,7 +4050,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, defender_vet, defender_link, pdefender->id, defender_fp, (float) def_power / POWER_FACTOR, def_hp_start - pdefender->hp, pdefender->hp, - (pdefender->veteran - old_defender_vet) + (pdefender->veteran != old_defender_vet) ? unit_achieved_rank_string(pdefender) : ""); From d1f9516829ab6c893d7787fa74fb737527b4ba74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Fl=C3=A1vio?= <40389021+hugomflavio@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:01:22 -0400 Subject: [PATCH 12/16] Update server/unithand.cpp following suggestion by @lmoureaux Co-authored-by: Louis Moureaux --- server/unithand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index fc6735e687..15d3ec9890 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4076,7 +4076,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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) + (punit->veteran != old_unit_vet) ? unit_achieved_rank_string(punit) : ""); // notify defender of promotion From 89f5c2ab2c1fc90665beb30e045314b24183e6f8 Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Sat, 7 Sep 2024 10:05:00 -0400 Subject: [PATCH 13/16] improved stack messages and special messages for extreme battle results --- server/unithand.cpp | 329 ++++++++++++++++++++++++++++--------------- server/unittools.cpp | 78 +++++----- 2 files changed, 256 insertions(+), 151 deletions(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 15d3ec9890..15c939981c 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4035,50 +4035,90 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, nation_rule_name(nation_of_unit(pdefender)), unit_rule_name(pdefender)); - // notify attacker of battle tie - notify_player( - 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, - (pdefender->veteran != old_defender_vet) - ? unit_achieved_rank_string(pdefender) - : ""); + // scorn the attacker if defender lost no hp + if (def_hp_start == pdefender->hp) { + // notify attacker of battle tie + notify_player( + 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] tried to attack 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]" + " tried to attack 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, + (pdefender->veteran != old_defender_vet) + ? unit_achieved_rank_string(pdefender) + : ""); + // 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] brushed off a pathetic attack from the Greek + * Polish Archer [id:200* ...D:8.0, lost 5 HP, 5 HP remaining%s]!"; + * The last %s is either a promoted string or empty */ + _("Your %s %s [id:%d %sA:%.1f, lost %d HP, %d HP remaining]" + " brushed off a pathetic attack from 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) : ""); + } else { + // notify attacker of battle tie + notify_player( + 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, + (pdefender->veteran != old_defender_vet) + ? unit_achieved_rank_string(pdefender) + : ""); + // 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] fought back the attacking Greek Polish Archer + * [id:200 ...D:8.0, lost 5 HP, 5 HP remaining%s]!"; + * The last %s is either a promoted string or empty */ + _("Your %s %s [id:%d %sA:%.1f, lost %d HP, %d HP remaining]" + " fought back the attacking %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 attacker of promotion if (punit->veteran != old_unit_vet) { notify_unit_experience(punit); } - // 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) { notify_unit_experience(pdefender); @@ -4098,46 +4138,81 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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); - + // scorn the defender if the attacker didn't lose any hp + if (att_hp_start == punit->hp) { + // 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] eliminated the worthless + * Greek green Warriors [id:100 HP:10]." */ + _("Your %s %s [id:%d %s%sA:%.1f, lost %d HP, " + "has %d remaining] eliminated the worthless %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 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] + * helplessly perished in an attack by the Greek green Legion + * [id:200 ...A:4.0 lost 1 HP, has 9 HP remaining%s]." + * last %s is either ", promoted ..." or empty string */ + _("Your %s %s [id:%d %sD:%.1f HP:%d] helplessly perished in an" + " attack by the %s %s %s [id:%d %s%sA:%.1f, lost %d HP, has %d HP " + "remaining%s]."), + 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, 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) + : ""); + } else { + // notify the attacker of victory + notify_player( + unit_owner(punit), unit_tile(punit), E_UNIT_WIN_ATT, ftc_server, + /* TRANS: "Your green Legion [id:200 ...A:4.0 + * lost 1 HP, has 9 HP remaining%s] eliminated 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 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] + * perished in an attack by the Greek green Legion + * [id:200 ...A:4.0 lost 1 HP, has 9 HP remaining%s]." + * last %s is either ", promoted ..." or empty string */ + _("Your %s %s [id:%d %sD:%.1f HP:%d] perished in an attack by " + "the %s %s %s [id:%d %s%sA:%.1f, lost %d HP, has %d HP " + "remaining%s]."), + 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, 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) + : ""); + } // notify attacker of promotion if (punit->veteran != old_unit_vet) { 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] - * lost to an attack by the Greek green Legion - * [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 %s%sA:%.1f, lost %d HP, has %d HP " - "remaining%s]."), - 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, 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(punit, pdefender, punit->veteran == old_unit_vet @@ -4159,9 +4234,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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? + // For example if there's a hut on the target tile. if (game_unit_by_number(punit->id) != nullptr) { send_unit_info(nullptr, punit); } @@ -4182,41 +4255,75 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, nation_rule_name(nation_of_unit(pdefender)), unit_rule_name(pdefender)); - // 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); - + // scorn the attacker if the defender didn't lose any hp + if (def_hp_start == pdefender->hp) { + // notify attacker of defeat + notify_player(unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, + ftc_server, + /* TRANS: "Your 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] failed terribly" + " against 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]" + " stopped 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); + } else { + // notify attacker of defeat + notify_player(unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, + ftc_server, + /* TRANS: "Your green Cannon [id:100 ...A:8.0 + * perished while attacking 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] perished while" + " attacking 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_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]" + " stopped the %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); diff --git a/server/unittools.cpp b/server/unittools.cpp index 01d9a17197..dd32371760 100644 --- a/server/unittools.cpp +++ b/server/unittools.cpp @@ -33,7 +33,6 @@ #include "city.h" #include "combat.h" #include "events.h" -#include "featured_text.h" #include "game.h" #include "government.h" #include "idex.h" @@ -2344,6 +2343,12 @@ struct unit *unit_change_owner(struct unit *punit, struct player *pplayer, Called when one unit kills another in combat (this function is only called in one place). It handles all side effects including notifications and killstack. + \note WARNING: This function iterates through all _possible_ players, + not just the players present in the server. That means that, in the + loops, you must account for situations where the loop is going to go + through players that do not exist, and the consequences that such + iterations could have. E.g. notify_player, when pointed to nullptr, + will send messages to _everyone_. */ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) { @@ -2544,7 +2549,6 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) if (!escaped) { num_killed[player_index(vplayer)]++; - if (vunit != punit) { other_killed[player_index(vplayer)] = vunit; other_killed[player_index(pvictor)] = vunit; @@ -2572,51 +2576,45 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) * Also if a large number of units die you don't find out what type * they all are. */ for (i = 0; i < MAX_NUM_PLAYER_SLOTS; i++) { - if (num_killed[i] == 1) { - if (i == player_index(pvictim)) { - fc_assert(other_killed[i] == nullptr); - notify_player(player_by_number(i), ptile, E_UNIT_LOST_DEF, - ftc_server, - // TRANS: "Cannon ... the Polish Destroyer." - _("%s lost when the %s %s defeated your %s."), - punit_link, nation_adjective_for_player(pvictor), - pkiller_link, punit_link); - } else { + /* The owner can get two extra messages. + * One if more units of their own died + * One if allied units died as well. */ + if (i == player_index(pvictim)) { + if (num_killed[i] > 1) { 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 defeated the %s %s."), - unit_link(other_killed[i]), - nation_adjective_for_player(pvictor), pkiller_link, - nation_adjective_for_player(pvictim), punit_link); - } - } else if (num_killed[i] > 1) { - if (i == player_index(pvictim)) { - int others = num_killed[i] - 1; 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) */ + /* TRANS: "One other unit lost when the celtiberian armor + defeated your mech inf. */ PL_("One other unit lost when the %s %s defeated your %s.", - "%4$d other units lost when the %s %s defeated your %s.", - others), - punit_link, nation_adjective_for_player(pvictor), pkiller_link, - others); - } else { + "%4$d other units lost when the %1$s %2$s defeated your %3$s.", + num_killed[i] - 1), + nation_adjective_for_player(pvictor), pkiller_link, punit_link, + num_killed[i] - 1); + } + if ((unitcount-1) > num_killed[i]) { + notify_player( + player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, + /* TRANS: "One allied unit lost when the celtiberian armor + defeated your mech inf. */ + PL_("One allied unit lost when the %s %s defeated your %s.", + "%4$d allied units lost when the %1$s %2$s defeated your %3$s.", + unitcount), + nation_adjective_for_player(pvictor), pkiller_link, punit_link, + unitcount); + } + } else { + if (num_killed[i] >= 1) { 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 defeated the %s %s.", - "%d units lost when the %s %s defeated the %s %s.", + /* TRANS: "One unit lost when the celtiberian armor + defeated the roman mech inf. */ + PL_("One unit lost when the %s %s defeated the %s %s.", + "%5$d units lost when the %1$s %2$s defeated the %3$s %4$s.", num_killed[i]), - num_killed[i], nation_adjective_for_player(pvictor), - pkiller_link, nation_adjective_for_player(pvictim), - punit_link); + nation_adjective_for_player(pvictor), pkiller_link, + nation_adjective_for_player(pvictim), punit_link, + num_killed[i]); } } } From 61b09efe936a82997e3522504accbee4cfe5cc27 Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Sat, 7 Sep 2024 10:08:51 -0400 Subject: [PATCH 14/16] replace - with != per @lmoureaux suggestion --- server/unithand.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 15c939981c..3c5ee3e5e9 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4272,7 +4272,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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) + (pdefender->veteran != old_defender_vet) ? unit_achieved_rank_string(pdefender) : ""); // notify defender of victory @@ -4306,7 +4306,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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) + (pdefender->veteran != old_defender_vet) ? unit_achieved_rank_string(pdefender) : ""); notify_player( From 047e273618bc4ace4ccd6c927c9e946a3c61065d Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Sat, 7 Sep 2024 10:10:53 -0400 Subject: [PATCH 15/16] forgot to run clang. done now. --- server/unithand.cpp | 152 ++++++++++++++++++++++--------------------- server/unittools.cpp | 11 ++-- 2 files changed, 85 insertions(+), 78 deletions(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index 3c5ee3e5e9..be3d468879 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4060,11 +4060,12 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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] brushed off a pathetic attack from the Greek + * 7 HP remaining%s] brushed off a pathetic attack from the Greek * Polish Archer [id:200* ...D:8.0, lost 5 HP, 5 HP remaining%s]!"; * The last %s is either a promoted string or empty */ _("Your %s %s [id:%d %sA:%.1f, lost %d HP, %d HP remaining]" - " brushed off a pathetic attack from the %s %s %s [id:%d %sD:%.1f, lost %d" + " brushed off a pathetic attack from 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, @@ -4072,8 +4073,8 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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) : ""); + (punit->veteran != old_unit_vet) ? unit_achieved_rank_string(punit) + : ""); } else { // notify attacker of battle tie notify_player( @@ -4110,8 +4111,8 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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) : ""); + (punit->veteran != old_unit_vet) ? unit_achieved_rank_string(punit) + : ""); } // notify attacker of promotion @@ -4141,56 +4142,60 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, // scorn the defender if the attacker didn't lose any hp if (att_hp_start == punit->hp) { // 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] eliminated the worthless - * Greek green Warriors [id:100 HP:10]." */ - _("Your %s %s [id:%d %s%sA:%.1f, lost %d HP, " - "has %d remaining] eliminated the worthless %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_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] eliminated the + * worthless Greek green Warriors [id:100 HP:10]." */ + _("Your %s %s [id:%d %s%sA:%.1f, lost %d HP, " + "has %d remaining] eliminated the worthless %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 defender of defeat - notify_player(unit_owner(pdefender), unit_tile(pdefender), - E_UNIT_LOST_DEF, ftc_server, + 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] * helplessly perished in an attack by the Greek green Legion * [id:200 ...A:4.0 lost 1 HP, has 9 HP remaining%s]." * last %s is either ", promoted ..." or empty string */ _("Your %s %s [id:%d %sD:%.1f HP:%d] helplessly perished in an" - " attack by the %s %s %s [id:%d %s%sA:%.1f, lost %d HP, has %d HP " + " attack by the %s %s %s [id:%d %s%sA:%.1f, lost %d HP, has %d " + "HP " "remaining%s]."), 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, 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) - : ""); + nation_adjective_for_player(unit_owner(punit)), 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) + : ""); } else { // notify the attacker of victory - notify_player( - unit_owner(punit), unit_tile(punit), E_UNIT_WIN_ATT, ftc_server, - /* TRANS: "Your green Legion [id:200 ...A:4.0 - * lost 1 HP, has 9 HP remaining%s] eliminated 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_player(unit_owner(punit), unit_tile(punit), E_UNIT_WIN_ATT, + ftc_server, + /* TRANS: "Your green Legion [id:200 ...A:4.0 + * lost 1 HP, has 9 HP remaining%s] eliminated 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 defender of defeat - notify_player(unit_owner(pdefender), unit_tile(pdefender), - E_UNIT_LOST_DEF, ftc_server, + 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] * perished in an attack by the Greek green Legion * [id:200 ...A:4.0 lost 1 HP, has 9 HP remaining%s]." @@ -4200,13 +4205,12 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, "remaining%s]."), 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, 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) - : ""); + nation_adjective_for_player(unit_owner(punit)), 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) + : ""); } // notify attacker of promotion if (punit->veteran != old_unit_vet) { @@ -4258,23 +4262,23 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, // scorn the attacker if the defender didn't lose any hp if (def_hp_start == pdefender->hp) { // notify attacker of defeat - notify_player(unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, - ftc_server, - /* TRANS: "Your 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] failed terribly" - " against 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_player( + unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, ftc_server, + /* TRANS: "Your 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] failed terribly" + " against 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, @@ -4292,8 +4296,8 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, (float) att_power / POWER_FACTOR, att_hp_start); } else { // notify attacker of defeat - notify_player(unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, - ftc_server, + notify_player( + unit_owner(punit), unit_tile(punit), E_UNIT_LOST_ATT, ftc_server, /* TRANS: "Your green Cannon [id:100 ...A:8.0 * perished while attacking the Greek Polish Destroyer [id:200 lost * 27 HP, 3 HP remaining%s]!"; @@ -4303,9 +4307,9 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, "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, + 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) : ""); @@ -4322,7 +4326,7 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, 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); + (float) att_power / POWER_FACTOR, att_hp_start); } // notify defender of promotion if (pdefender->veteran == old_defender_vet ? 0 : 1) { diff --git a/server/unittools.cpp b/server/unittools.cpp index dd32371760..79889bfcfc 100644 --- a/server/unittools.cpp +++ b/server/unittools.cpp @@ -2587,18 +2587,20 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) /* TRANS: "One other unit lost when the celtiberian armor defeated your mech inf. */ PL_("One other unit lost when the %s %s defeated your %s.", - "%4$d other units lost when the %1$s %2$s defeated your %3$s.", + "%4$d other units lost when the %1$s %2$s defeated your " + "%3$s.", num_killed[i] - 1), nation_adjective_for_player(pvictor), pkiller_link, punit_link, num_killed[i] - 1); } - if ((unitcount-1) > num_killed[i]) { + if ((unitcount - 1) > num_killed[i]) { notify_player( player_by_number(i), ptile, E_UNIT_LOST_DEF, ftc_server, /* TRANS: "One allied unit lost when the celtiberian armor defeated your mech inf. */ PL_("One allied unit lost when the %s %s defeated your %s.", - "%4$d allied units lost when the %1$s %2$s defeated your %3$s.", + "%4$d allied units lost when the %1$s %2$s defeated your " + "%3$s.", unitcount), nation_adjective_for_player(pvictor), pkiller_link, punit_link, unitcount); @@ -2610,7 +2612,8 @@ void kill_unit(struct unit *pkiller, struct unit *punit, bool vet) /* TRANS: "One unit lost when the celtiberian armor defeated the roman mech inf. */ PL_("One unit lost when the %s %s defeated the %s %s.", - "%5$d units lost when the %1$s %2$s defeated the %3$s %4$s.", + "%5$d units lost when the %1$s %2$s defeated the %3$s " + "%4$s.", num_killed[i]), nation_adjective_for_player(pvictor), pkiller_link, nation_adjective_for_player(pvictim), punit_link, From 29e98c9bf01f903c3d5cc9a35ff579ef65802b2a Mon Sep 17 00:00:00 2001 From: hugomflavio Date: Sat, 7 Sep 2024 14:27:54 -0400 Subject: [PATCH 16/16] final tweaks to message content --- server/unithand.cpp | 58 +++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/server/unithand.cpp b/server/unithand.cpp index be3d468879..56cd1b6bf4 100644 --- a/server/unithand.cpp +++ b/server/unithand.cpp @@ -4044,14 +4044,12 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, * 7 HP remaining] tried to attack 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]" - " tried to attack the %s %s %s [id:%d %sD:%.1f, lost %d" - " HP, %d HP remaining%s]!"), + " failed to hit the %s %s %s [id:%d %sD:%.1f HP:%d%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, + (float) def_power / POWER_FACTOR, pdefender->hp, (pdefender->veteran != old_defender_vet) ? unit_achieved_rank_string(pdefender) : ""); @@ -4063,14 +4061,14 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, * 7 HP remaining%s] brushed off a pathetic attack from the Greek * Polish Archer [id:200* ...D:8.0, lost 5 HP, 5 HP remaining%s]!"; * The last %s is either a promoted string or empty */ - _("Your %s %s [id:%d %sA:%.1f, lost %d HP, %d HP remaining]" + _("Your %s %s [id:%d %sA:%.1f HP:%d]" " brushed off a pathetic attack from 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) def_power / POWER_FACTOR, 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) @@ -4142,20 +4140,18 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, // scorn the defender if the attacker didn't lose any hp if (att_hp_start == punit->hp) { // 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] eliminated the - * worthless Greek green Warriors [id:100 HP:10]." */ - _("Your %s %s [id:%d %s%sA:%.1f, lost %d HP, " - "has %d remaining] eliminated the worthless %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_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] eliminated the + * worthless Greek green Warriors [id:100 HP:10]." */ + _("Your %s %s [id:%d %s%sA:%.1f, HP:%d] eliminated the " + "worthless %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, 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 defender of defeat notify_player( unit_owner(pdefender), unit_tile(pdefender), E_UNIT_LOST_DEF, @@ -4165,15 +4161,12 @@ 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 ", promoted ..." or empty string */ _("Your %s %s [id:%d %sD:%.1f HP:%d] helplessly perished in an" - " attack by the %s %s %s [id:%d %s%sA:%.1f, lost %d HP, has %d " - "HP " - "remaining%s]."), + " attack by the %s %s %s [id:%d %s%sA:%.1f HP:%d%s]."), 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, attacker_link, punit->id, attacker_fp, attacker_tired, - (float) att_power / POWER_FACTOR, att_hp_start - punit->hp, - punit->hp, + (float) att_power / POWER_FACTOR, punit->hp, (punit->veteran != old_unit_vet) ? unit_achieved_rank_string(punit) : ""); } else { @@ -4269,13 +4262,11 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, * 27 HP, 3 HP remaining%s]!"; * last %s is either "and ..." or empty string */ _("Your %s %s [id:%d %sA:%.1f, lost %d HP] failed terribly" - " against the %s %s %s [id:%d lost %d HP, %d HP " - "remaining%s]!"), + " against the %s %s %s [id:%d HP:%d%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, + defender_link, pdefender->id, pdefender->hp, (pdefender->veteran != old_defender_vet) ? unit_achieved_rank_string(pdefender) : ""); @@ -4285,12 +4276,11 @@ static bool do_attack(struct unit *punit, struct tile *def_tile, /* 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]" + _("Your %s %s [id:%d %sD:%.1f HP:%d]" " stopped 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, + (float) def_power / POWER_FACTOR, 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);