From f7b8e079b4eea1e9c95e13a60c978515b3fa5480 Mon Sep 17 00:00:00 2001 From: juliancoffee Date: Fri, 2 Feb 2024 20:25:46 +0200 Subject: [PATCH] Expose player gender to existing chat messages TODO: localize /tell and expose gender in 'hud-chat-you' --- voxygen/i18n-helpers/src/lib.rs | 368 +++++++++++++++++--------------- 1 file changed, 201 insertions(+), 167 deletions(-) diff --git a/voxygen/i18n-helpers/src/lib.rs b/voxygen/i18n-helpers/src/lib.rs index c7c1bcd5da..e4c3013505 100644 --- a/voxygen/i18n-helpers/src/lib.rs +++ b/voxygen/i18n-helpers/src/lib.rs @@ -1,9 +1,12 @@ #![feature(let_chains)] use std::borrow::Cow; -use common::comp::{ - chat::{KillSource, KillType}, - BuffKind, ChatMsg, ChatType, Content, +use common::{ + comp::{ + chat::{KillSource, KillType}, + BuffKind, ChatMsg, ChatType, Content, + }, + uid::Uid, }; use common_net::msg::{ChatTypeContext, PlayerInfo}; use i18n::Localization; @@ -16,8 +19,8 @@ pub fn localize_chat_message( ) -> (ChatType, String) { let info = lookup_fn(&msg); - let name_format = |uid: &common::uid::Uid| match info.player_alias.get(uid).cloned() { - Some(pi) => insert_alias(info.you == *uid, pi, localization), + let name_format_or_you = |you, uid: &Uid| match info.player_alias.get(uid).cloned() { + Some(pi) => insert_alias(you && info.you == *uid, pi, localization), None => info .entity_name .get(uid) @@ -25,8 +28,13 @@ pub fn localize_chat_message( .expect("client didn't proved enough info"), }; - let message_format = |from: &common::uid::Uid, content: &Content, group: Option<&String>| { - let alias = name_format(from); + let name_format = |uid: &Uid| name_format_or_you(false, uid); + + // FIXME: this shouldn't pass review! + let gender_str = |uid: &Uid| "he".to_owned(); + + let message_format = |from: &Uid, content: &Content, group: Option<&String>| { + let alias = name_format_or_you(true, from); let name = if let Some(pi) = info.player_alias.get(from).cloned() && show_char_name { pi.character.map(|c| c.name) } else { @@ -35,8 +43,8 @@ pub fn localize_chat_message( let message = localization.get_content(content); match (group, name) { (Some(group), None) => format!("({group}) [{alias}]: {message}"), - (None, None) => format!("[{alias}]: {message}"), (Some(group), Some(name)) => format!("({group}) [{alias}] {name}: {message}"), + (None, None) => format!("[{alias}]: {message}"), (None, Some(name)) => format!("[{alias}] {name}: {message}"), } }; @@ -44,19 +52,20 @@ pub fn localize_chat_message( let new_msg = match &msg.chat_type { ChatType::Online(uid) => localization .get_msg_ctx("hud-chat-online_msg", &i18n::fluent_args! { + "user_gender" => gender_str(uid), "name" => name_format(uid), }) .into_owned(), ChatType::Offline(uid) => localization .get_msg_ctx("hud-chat-offline_msg", &i18n::fluent_args! { - "name" => name_format(uid - ), + "user_gender" => gender_str(uid), + "name" => name_format(uid), }) .into_owned(), - ChatType::CommandError => localization.get_content(msg.content()), - ChatType::CommandInfo => localization.get_content(msg.content()), - ChatType::FactionMeta(_) => localization.get_content(msg.content()), - ChatType::GroupMeta(_) => localization.get_content(msg.content()), + ChatType::CommandError + | ChatType::CommandInfo + | ChatType::FactionMeta(_) + | ChatType::GroupMeta(_) => localization.get_content(msg.content()), ChatType::Tell(from, to) => { let from_alias = name_format(from); let to_alias = name_format(to); @@ -73,15 +82,15 @@ pub fn localize_chat_message( ) } }, - ChatType::Say(uid) => message_format(uid, msg.content(), None), - ChatType::Group(uid, s) => message_format(uid, msg.content(), Some(s)), - ChatType::Faction(uid, s) => message_format(uid, msg.content(), Some(s)), - ChatType::Region(uid) => message_format(uid, msg.content(), None), - ChatType::World(uid) => message_format(uid, msg.content(), None), + ChatType::Say(uid) | ChatType::Region(uid) | ChatType::World(uid) => { + message_format(uid, msg.content(), None) + }, + ChatType::Group(uid, descriptor) | ChatType::Faction(uid, descriptor) => { + message_format(uid, msg.content(), Some(descriptor)) + }, // NPCs can't talk. Should be filtered by hud/mod.rs for voxygen and // should be filtered by server (due to not having a Pos) for chat-cli - ChatType::Npc(uid) => message_format(uid, msg.content(), None), - ChatType::NpcSay(uid) => message_format(uid, msg.content(), None), + ChatType::Npc(uid) | ChatType::NpcSay(uid) => message_format(uid, msg.content(), None), ChatType::NpcTell(from, to) => { let from_alias = name_format(from); let to_alias = name_format(to); @@ -100,158 +109,183 @@ pub fn localize_chat_message( }, ChatType::Meta => localization.get_content(msg.content()), ChatType::Kill(kill_source, victim) => { - let get_buff_ident = |buff| match buff { - BuffKind::Burning => "burning", - BuffKind::Bleeding => "bleeding", - BuffKind::Cursed => "curse", - BuffKind::Crippled => "crippled", - BuffKind::Frozen => "frozen", - BuffKind::Regeneration - | BuffKind::Saturation - | BuffKind::Potion - | BuffKind::Agility - | BuffKind::CampfireHeal - | BuffKind::EnergyRegen - | BuffKind::IncreaseMaxEnergy - | BuffKind::IncreaseMaxHealth - | BuffKind::Invulnerability - | BuffKind::ProtectingWard - | BuffKind::Frenzied - | BuffKind::Hastened - | BuffKind::Fortitude - | BuffKind::Reckless - | BuffKind::Flame - | BuffKind::Frigid - | BuffKind::Lifesteal - // | BuffKind::SalamanderAspect - | BuffKind::ImminentCritical - | BuffKind::Fury - | BuffKind::Sunderer - | BuffKind::Defiance - | BuffKind::Bloodfeast - | BuffKind::Berserk => { - tracing::error!("Player was killed by a positive buff!"); - "mysterious" - }, - BuffKind::Wet - | BuffKind::Ensnared - | BuffKind::Poisoned - | BuffKind::Parried - | BuffKind::PotionSickness - | BuffKind::Polymorphed - | BuffKind::Heatstroke => { - tracing::error!("Player was killed by a debuff that doesn't do damage!"); - "mysterious" - }, - }; - - match kill_source { - // Buff deaths - KillSource::Player(attacker, KillType::Buff(buff_kind)) => { - let buff_ident = get_buff_ident(*buff_kind); - - let s = localization - .get_attr_ctx( - "hud-chat-died_of_pvp_buff_msg", - buff_ident, - &i18n::fluent_args! { - "victim" => name_format(victim), - "attacker" => name_format(attacker), - }, - ) - .into_owned(); - Cow::Owned(s) - }, - KillSource::NonPlayer(attacker_name, KillType::Buff(buff_kind)) => { - let buff_ident = get_buff_ident(*buff_kind); - - let s = localization - .get_attr_ctx( - "hud-chat-died_of_npc_buff_msg", - buff_ident, - &i18n::fluent_args! { - "victim" => name_format(victim), - "attacker" => attacker_name, - }, - ) - .into_owned(); - Cow::Owned(s) - }, - KillSource::NonExistent(KillType::Buff(buff_kind)) => { - let buff_ident = get_buff_ident(*buff_kind); - - let s = localization - .get_attr_ctx( - "hud-chat-died_of_buff_nonexistent_msg", - buff_ident, - &i18n::fluent_args! { - "victim" => name_format(victim), - }, - ) - .into_owned(); - Cow::Owned(s) - }, - // PvP deaths - KillSource::Player(attacker, kill_type) => { - let key = match kill_type { - KillType::Melee => "hud-chat-pvp_melee_kill_msg", - KillType::Projectile => "hud-chat-pvp_ranged_kill_msg", - KillType::Explosion => "hud-chat-pvp_explosion_kill_msg", - KillType::Energy => "hud-chat-pvp_energy_kill_msg", - KillType::Other => "hud-chat-pvp_other_kill_msg", - &KillType::Buff(_) => unreachable!("handled above"), - }; - localization.get_msg_ctx(key, &i18n::fluent_args! { - "victim" => name_format(victim), - "attacker" => name_format(attacker), - }) - }, - // PvE deaths - KillSource::NonPlayer(attacker_name, kill_type) => { - let key = match kill_type { - KillType::Melee => "hud-chat-npc_melee_kill_msg", - KillType::Projectile => "hud-chat-npc_ranged_kill_msg", - KillType::Explosion => "hud-chat-npc_explosion_kill_msg", - KillType::Energy => "hud-chat-npc_energy_kill_msg", - KillType::Other => "hud-chat-npc_other_kill_msg", - &KillType::Buff(_) => unreachable!("handled above"), - }; - localization.get_msg_ctx(key, &i18n::fluent_args! { - "victim" => name_format(victim), - "attacker" => attacker_name, - }) - }, - // Other deaths - KillSource::Environment(environment) => { - localization.get_msg_ctx("hud-chat-environment_kill_msg", &i18n::fluent_args! { - "name" => name_format(victim), - "environment" => environment, - }) - }, - KillSource::FallDamage => { - localization.get_msg_ctx("hud-chat-fall_kill_msg", &i18n::fluent_args! { - "name" => name_format(victim), - }) - }, - KillSource::Suicide => { - localization.get_msg_ctx("hud-chat-suicide_msg", &i18n::fluent_args! { - "name" => name_format(victim), - }) - }, - KillSource::NonExistent(_) | KillSource::Other => { - localization.get_msg_ctx("hud-chat-default_death_msg", &i18n::fluent_args! { - "name" => name_format(victim), - }) - }, - } - .into_owned() + localize_kill_message(kill_source, victim, name_format, gender_str, localization) }, }; (msg.chat_type, new_msg) } +fn localize_kill_message( + kill_source: &KillSource, + victim: &Uid, + name_format: impl Fn(&Uid) -> String, + gender_str: impl Fn(&Uid) -> String, + localization: &Localization, +) -> String { + match kill_source { + // Buff deaths + KillSource::Player(attacker, KillType::Buff(buff_kind)) => { + let buff_ident = get_buff_ident(*buff_kind); + + let s = localization + .get_attr_ctx( + "hud-chat-died_of_pvp_buff_msg", + buff_ident, + &i18n::fluent_args! { + "victim" => name_format(victim), + "victim_gender" => gender_str(victim), + "attacker" => name_format(attacker), + "attacker_gender" => gender_str(attacker), + }, + ) + .into_owned(); + Cow::Owned(s) + }, + KillSource::NonPlayer(attacker_name, KillType::Buff(buff_kind)) => { + let buff_ident = get_buff_ident(*buff_kind); + + let s = localization + .get_attr_ctx( + "hud-chat-died_of_npc_buff_msg", + buff_ident, + &i18n::fluent_args! { + "victim" => name_format(victim), + "victim_gender" => gender_str(victim), + "attacker" => attacker_name, + }, + ) + .into_owned(); + Cow::Owned(s) + }, + KillSource::NonExistent(KillType::Buff(buff_kind)) => { + let buff_ident = get_buff_ident(*buff_kind); + + let s = localization + .get_attr_ctx( + "hud-chat-died_of_buff_nonexistent_msg", + buff_ident, + &i18n::fluent_args! { + "victim" => name_format(victim), + "victim_gender" => gender_str(victim), + }, + ) + .into_owned(); + Cow::Owned(s) + }, + // PvP deaths + KillSource::Player(attacker, kill_type) => { + let key = match kill_type { + KillType::Melee => "hud-chat-pvp_melee_kill_msg", + KillType::Projectile => "hud-chat-pvp_ranged_kill_msg", + KillType::Explosion => "hud-chat-pvp_explosion_kill_msg", + KillType::Energy => "hud-chat-pvp_energy_kill_msg", + KillType::Other => "hud-chat-pvp_other_kill_msg", + &KillType::Buff(_) => unreachable!("handled above"), + }; + localization.get_msg_ctx(key, &i18n::fluent_args! { + "victim" => name_format(victim), + "victim_gender" => gender_str(victim), + "attacker" => name_format(attacker), + "attacker_gender" => gender_str(attacker), + }) + }, + // PvE deaths + KillSource::NonPlayer(attacker_name, kill_type) => { + let key = match kill_type { + KillType::Melee => "hud-chat-npc_melee_kill_msg", + KillType::Projectile => "hud-chat-npc_ranged_kill_msg", + KillType::Explosion => "hud-chat-npc_explosion_kill_msg", + KillType::Energy => "hud-chat-npc_energy_kill_msg", + KillType::Other => "hud-chat-npc_other_kill_msg", + &KillType::Buff(_) => unreachable!("handled above"), + }; + localization.get_msg_ctx(key, &i18n::fluent_args! { + "victim" => name_format(victim), + "victim_gender" => gender_str(victim), + "attacker" => attacker_name, + }) + }, + // Other deaths + KillSource::Environment(environment) => { + localization.get_msg_ctx("hud-chat-environment_kill_msg", &i18n::fluent_args! { + "name" => name_format(victim), + "victim_gender" => gender_str(victim), + "environment" => environment, + }) + }, + KillSource::FallDamage => { + localization.get_msg_ctx("hud-chat-fall_kill_msg", &i18n::fluent_args! { + "name" => name_format(victim), + "victim_gender" => gender_str(victim), + }) + }, + KillSource::Suicide => { + localization.get_msg_ctx("hud-chat-suicide_msg", &i18n::fluent_args! { + "name" => name_format(victim), + "victim_gender" => gender_str(victim), + }) + }, + KillSource::NonExistent(_) | KillSource::Other => { + localization.get_msg_ctx("hud-chat-default_death_msg", &i18n::fluent_args! { + "name" => name_format(victim), + "victim_gender" => gender_str(victim), + }) + }, + } + .into_owned() +} + +// determine attr for `hud-chat-died-of-buff` +fn get_buff_ident(buff: BuffKind) -> &'static str { + match buff { + BuffKind::Burning => "burning", + BuffKind::Bleeding => "bleeding", + BuffKind::Cursed => "curse", + BuffKind::Crippled => "crippled", + BuffKind::Frozen => "frozen", + BuffKind::Regeneration + | BuffKind::Saturation + | BuffKind::Potion + | BuffKind::Agility + | BuffKind::CampfireHeal + | BuffKind::EnergyRegen + | BuffKind::IncreaseMaxEnergy + | BuffKind::IncreaseMaxHealth + | BuffKind::Invulnerability + | BuffKind::ProtectingWard + | BuffKind::Frenzied + | BuffKind::Hastened + | BuffKind::Fortitude + | BuffKind::Reckless + | BuffKind::Flame + | BuffKind::Frigid + | BuffKind::Lifesteal + // | BuffKind::SalamanderAspect + | BuffKind::ImminentCritical + | BuffKind::Fury + | BuffKind::Sunderer + | BuffKind::Defiance + | BuffKind::Bloodfeast + | BuffKind::Berserk => { + tracing::error!("Player was killed by a positive buff!"); + "mysterious" + }, + BuffKind::Wet + | BuffKind::Ensnared + | BuffKind::Poisoned + | BuffKind::Parried + | BuffKind::PotionSickness + | BuffKind::Polymorphed + | BuffKind::Heatstroke => { + tracing::error!("Player was killed by a debuff that doesn't do damage!"); + "mysterious" + }, + } +} + fn insert_alias(you: bool, info: PlayerInfo, localization: &Localization) -> String { + // FIXME: this should take gender into account const YOU: &str = "hud-chat-you"; // Leave space for a mod badge icon. const MOD_SPACING: &str = " "; @@ -259,7 +293,7 @@ fn insert_alias(you: bool, info: PlayerInfo, localization: &Localization) -> Str (false, false) => info.player_alias, (false, true) => localization.get_msg(YOU).to_string(), (true, false) => format!("{}{}", MOD_SPACING, info.player_alias), - (true, true) => format!("{}{}", MOD_SPACING, &localization.get_msg(YOU),), + (true, true) => format!("{}{}", MOD_SPACING, &localization.get_msg(YOU)), } }