diff --git a/append_i18n.py b/append_i18n.py new file mode 100644 index 0000000..bca52a1 --- /dev/null +++ b/append_i18n.py @@ -0,0 +1,77 @@ +import os + +zh_content = """ + +# Action: Play Extended +msgid "action_reading" +msgstr "读书" + +msgid "action_tea_tasting" +msgstr "品茶" + +msgid "action_traveling" +msgstr "游历" + +msgid "action_zither_playing" +msgstr "抚琴" + +msgid "action_tea_party" +msgstr "茶会" + +msgid "action_chess" +msgstr "下棋" + +msgid "{avatar} starts {action}" +msgstr "{avatar} 开始{action}" + +msgid "{avatar} finished {action}." +msgstr "{avatar} 完成了{action}。" + +msgid "gained {val} cultivation" +msgstr "若有所悟,修为增加 {val}" + +msgid "breakthrough probability increased by {val:.1%}" +msgstr "心境提升,突破概率增加 {val:.1%}" +""" + +en_content = """ + +# Action: Play Extended +msgid "action_reading" +msgstr "Reading" + +msgid "action_tea_tasting" +msgstr "Tea Tasting" + +msgid "action_traveling" +msgstr "Traveling" + +msgid "action_zither_playing" +msgstr "Playing Zither" + +msgid "action_tea_party" +msgstr "Tea Party" + +msgid "action_chess" +msgstr "Chess" + +msgid "{avatar} starts {action}" +msgstr "{avatar} starts {action}" + +msgid "{avatar} finished {action}." +msgstr "{avatar} finished {action}." + +msgid "gained {val} cultivation" +msgstr "gained {val} cultivation" + +msgid "breakthrough probability increased by {val:.1%}" +msgstr "breakthrough probability increased by {val:.1%}" +""" + +with open('src/i18n/locales/zh_CN/LC_MESSAGES/messages.po', 'a', encoding='utf-8') as f: + f.write(zh_content) + +with open('src/i18n/locales/en_US/LC_MESSAGES/messages.po', 'a', encoding='utf-8') as f: + f.write(en_content) + +print("Appended translations successfully.") diff --git a/src/classes/action/__init__.py b/src/classes/action/__init__.py index 4c85051..662663f 100644 --- a/src/classes/action/__init__.py +++ b/src/classes/action/__init__.py @@ -22,7 +22,7 @@ from .move_away_from_region import MoveAwayFromRegion from .escape import Escape from .cultivate import Cultivate from .breakthrough import Breakthrough -from .play import Play +from .play import Reading, TeaTasting, Traveling, ZitherPlaying from .hunt import Hunt from .harvest import Harvest from .sell import Sell @@ -58,7 +58,10 @@ register_action(actual=True)(MoveAwayFromRegion) register_action(actual=False)(Escape) register_action(actual=True)(Cultivate) register_action(actual=True)(Breakthrough) -register_action(actual=True)(Play) +register_action(actual=True)(Reading) +register_action(actual=True)(TeaTasting) +register_action(actual=True)(Traveling) +register_action(actual=True)(ZitherPlaying) register_action(actual=True)(Hunt) register_action(actual=True)(Harvest) register_action(actual=True)(Sell) @@ -97,7 +100,10 @@ __all__ = [ "Escape", "Cultivate", "Breakthrough", - "Play", + "Reading", + "TeaTasting", + "Traveling", + "ZitherPlaying", "Hunt", "Harvest", "Sell", @@ -116,5 +122,3 @@ __all__ = [ "Mine", "Retreat", ] - - diff --git a/src/classes/action/play.py b/src/classes/action/play.py index a38ab21..a8e489b 100644 --- a/src/classes/action/play.py +++ b/src/classes/action/play.py @@ -1,44 +1,68 @@ from __future__ import annotations +import random +from typing import TYPE_CHECKING from src.i18n import t -from src.classes.action import TimedAction +from src.classes.action.action import TimedAction +from src.classes.action_runtime import ActionStatus from src.classes.event import Event +from src.utils.config import CONFIG +if TYPE_CHECKING: + from src.classes.avatar import Avatar + from src.classes.world import World -class Play(TimedAction): - """ - 消遣动作,持续半年时间 - """ - - # 多语言 ID - ACTION_NAME_ID = "play_action_name" - DESC_ID = "play_description" +class BasePlayAction(TimedAction): + """消遣动作基类""" + duration_months = 1 REQUIREMENTS_ID = "play_requirements" - - # 不需要翻译的常量 - EMOJI = "🪁" - PARAMS = {} - duration_months = 6 + def __init__(self, avatar: Avatar, world: World): + super().__init__(avatar, world) + + def _try_trigger_benefit(self) -> str: + """尝试触发额外收益 (突破概率)""" + prob = CONFIG.play.base_benefit_probability if hasattr(CONFIG, 'play') else 0.05 + + if random.random() < prob: + rate = 0.2 + self.avatar.add_breakthrough_rate(rate) + return t("breakthrough probability increased by {val:.1%}", val=rate) + return "" def _execute(self) -> None: - """ - 进行消遣活动 - """ - # 消遣的具体逻辑可以在这里实现 - # 比如增加心情值、减少压力等 - pass - - def can_start(self) -> tuple[bool, str]: - return True, "" + pass # 具体逻辑由子类实现或只需记录事件 def start(self) -> Event: - content = t("{avatar} begins leisure activities", avatar=self.avatar.name) - return Event(self.world.month_stamp, content, related_avatars=[self.avatar.id]) - - # TimedAction 已统一 step 逻辑 + # 通用开始事件 + return Event(self.world.month_stamp, t("{avatar} starts {action}", avatar=self.avatar.name, action=self.get_action_name()), related_avatars=[self.avatar.id]) async def finish(self) -> list[Event]: - return [] + # 结算时尝试触发收益 + benefit_msg = self._try_trigger_benefit() + content = t("{avatar} finished {action}.", avatar=self.avatar.name, action=self.get_action_name()) + if benefit_msg: + content += f" {benefit_msg}" + + return [Event(self.world.month_stamp, content, related_avatars=[self.avatar.id])] +# 具体动作实现 +class Reading(BasePlayAction): + ACTION_NAME_ID = "action_reading" + DESC_ID = "action_reading_desc" + EMOJI = "📖" +class TeaTasting(BasePlayAction): + ACTION_NAME_ID = "action_tea_tasting" + DESC_ID = "action_tea_tasting_desc" + EMOJI = "🍵" + +class Traveling(BasePlayAction): + ACTION_NAME_ID = "action_traveling" + DESC_ID = "action_traveling_desc" + EMOJI = "🧳" + +class ZitherPlaying(BasePlayAction): + ACTION_NAME_ID = "action_zither_playing" + DESC_ID = "action_zither_playing_desc" + EMOJI = "🎵" diff --git a/src/classes/ai.py b/src/classes/ai.py index 8dc6431..fa8ba3b 100644 --- a/src/classes/ai.py +++ b/src/classes/ai.py @@ -103,9 +103,9 @@ class LLMAI(AI): # 更新情绪 from src.classes.emotions import EmotionType - raw_emotion = r.get("current_emotion", "平静") + raw_emotion = r.get("current_emotion", "emotion_calm") try: - # 尝试通过 value (中文) 获取枚举 + # 尝试通过 value 获取枚举 avatar.emotion = EmotionType(raw_emotion) except ValueError: avatar.emotion = EmotionType.CALM diff --git a/src/classes/avatar/core.py b/src/classes/avatar/core.py index 4ac6ef3..b1fa675 100644 --- a/src/classes/avatar/core.py +++ b/src/classes/avatar/core.py @@ -127,6 +127,18 @@ class Avatar( # 关系交互计数器: key=target_id, value={"count": 0, "checked_times": 0} relation_interaction_states: dict[str, dict[str, int]] = field(default_factory=lambda: defaultdict(lambda: {"count": 0, "checked_times": 0})) + def add_breakthrough_rate(self, rate: float, duration: int = 1) -> None: + """ + 增加突破成功率(临时效果) + """ + self.temporary_effects.append({ + "source": "play_benefit", + "effects": {"extra_breakthrough_success_rate": rate}, + "start_month": int(self.world.month_stamp), + "duration": duration + }) + self.recalc_effects() + # ========== 宗门相关 ========== def consume_elixir(self, elixir: Elixir) -> bool: @@ -333,7 +345,8 @@ class Avatar( action = self.current_action.action # 使用 get_action_name() 获取翻译后的动作名称 return action.get_action_name() - return "思考" + from src.i18n import t + return t("action_thinking") def __post_init__(self): """在Avatar创建后自动初始化tile和HP""" diff --git a/src/classes/emotions.py b/src/classes/emotions.py index 3105279..a7c6532 100644 --- a/src/classes/emotions.py +++ b/src/classes/emotions.py @@ -1,16 +1,16 @@ from enum import Enum class EmotionType(Enum): - CALM = "平静" - HAPPY = "开心" - ANGRY = "愤怒" - SAD = "悲伤" - FEARFUL = "恐惧" - SURPRISED = "惊讶" - ANTICIPATING = "期待" - DISGUSTED = "厌恶" - CONFUSED = "疑惑" - TIRED = "疲惫" + CALM = "emotion_calm" + HAPPY = "emotion_happy" + ANGRY = "emotion_angry" + SAD = "emotion_sad" + FEARFUL = "emotion_fearful" + SURPRISED = "emotion_surprised" + ANTICIPATING = "emotion_anticipating" + DISGUSTED = "emotion_disgusted" + CONFUSED = "emotion_confused" + TIRED = "emotion_tired" # 情绪对应的 Emoji 配置 EMOTION_EMOJIS = { diff --git a/src/classes/mutual_action/__init__.py b/src/classes/mutual_action/__init__.py index b179a15..608cc82 100644 --- a/src/classes/mutual_action/__init__.py +++ b/src/classes/mutual_action/__init__.py @@ -10,6 +10,7 @@ from .impart import Impart from .gift import Gift from .spar import Spar from .occupy import Occupy +from .play import TeaParty, Chess from src.classes.action.registry import register_action __all__ = [ @@ -23,6 +24,8 @@ __all__ = [ "Gift", "Spar", "Occupy", + "TeaParty", + "Chess", ] # 注册 mutual actions(均为实际动作) @@ -35,5 +38,5 @@ register_action(actual=True)(Impart) register_action(actual=True)(Gift) register_action(actual=True)(Spar) register_action(actual=True)(Occupy) - - +register_action(actual=True)(TeaParty) +register_action(actual=True)(Chess) diff --git a/src/classes/mutual_action/play.py b/src/classes/mutual_action/play.py new file mode 100644 index 0000000..721a538 --- /dev/null +++ b/src/classes/mutual_action/play.py @@ -0,0 +1,53 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +import random + +from src.classes.mutual_action.mutual_action import MutualAction +from src.i18n import t +from src.utils.config import CONFIG + +if TYPE_CHECKING: + from src.classes.avatar import Avatar + from src.classes.world import World + +def try_trigger_play_benefit(avatar: Avatar) -> str: + """ + 尝试触发消遣收益 (复用单人消遣的逻辑) + """ + prob = CONFIG.play.base_benefit_probability if hasattr(CONFIG, 'play') else 0.05 + + if random.random() < prob: + rate = 0.2 + avatar.add_breakthrough_rate(rate) + return t("breakthrough probability increased by {val:.1%}", val=rate) + return "" + +class TeaParty(MutualAction): + """茶会:双人互动""" + ACTION_NAME_ID = "action_tea_party" + DESC_ID = "action_tea_party_desc" + STORY_PROMPT_ID = "action_tea_party_story_prompt" + REQUIREMENTS_ID = "play_requirements" + EMOJI = "🍵" + FEEDBACK_ACTIONS = ["Accept", "Reject"] + + def _settle_feedback(self, target_avatar: Avatar, feedback_name: str) -> None: + if feedback_name == "Accept": + # 尝试给双方触发收益 + try_trigger_play_benefit(self.avatar) + try_trigger_play_benefit(target_avatar) + +class Chess(MutualAction): + """下棋:双人互动""" + ACTION_NAME_ID = "action_chess" + DESC_ID = "action_chess_desc" + STORY_PROMPT_ID = "action_chess_story_prompt" + REQUIREMENTS_ID = "play_requirements" + EMOJI = "♟️" + FEEDBACK_ACTIONS = ["Accept", "Reject"] + + def _settle_feedback(self, target_avatar: Avatar, feedback_name: str) -> None: + if feedback_name == "Accept": + # 尝试给双方触发收益 + try_trigger_play_benefit(self.avatar) + try_trigger_play_benefit(target_avatar) diff --git a/src/i18n/locales/en_US/LC_MESSAGES/messages.mo b/src/i18n/locales/en_US/LC_MESSAGES/messages.mo index 3f255f7..956b99c 100644 Binary files a/src/i18n/locales/en_US/LC_MESSAGES/messages.mo and b/src/i18n/locales/en_US/LC_MESSAGES/messages.mo differ diff --git a/src/i18n/locales/en_US/LC_MESSAGES/messages.po b/src/i18n/locales/en_US/LC_MESSAGES/messages.po index 84c0e01..bac80e6 100644 --- a/src/i18n/locales/en_US/LC_MESSAGES/messages.po +++ b/src/i18n/locales/en_US/LC_MESSAGES/messages.po @@ -1,2205 +1,1447 @@ # English translations for cultivation-world-simulator. - # Copyright (C) 2024 - # This file is distributed under the same license as the project. - # - msgid "" - msgstr "" - "Project-Id-Version: cultivation-world-simulator 1.0\n" - "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2024-01-20 00:00+0000\n" - "PO-Revision-Date: 2024-01-20 00:00+0000\n" - "Last-Translator: \n" - "Language-Team: English\n" - "Language: en_US\n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=UTF-8\n" - "Content-Transfer-Encoding: 8bit\n" - # Battle messages - msgid "{winner} defeated {loser}, dealing {damage} damage. {loser} was fatally wounded and perished." - msgstr "{winner} defeated {loser}, dealing {damage} damage. {loser} was fatally wounded and perished." - msgid "{winner} defeated {loser}. {loser} took {loser_dmg} damage, {winner} also took {winner_dmg} damage." - msgstr "{winner} defeated {loser}. {loser} took {loser_dmg} damage, {winner} also took {winner_dmg} damage." - # Fortune messages - msgid "Encountered fortune ({theme}), {result}" - msgstr "Encountered fortune ({theme}), {result}" - msgid "Found weapon '{weapon}', {exchange_result}" - msgstr "Found weapon '{weapon}', {exchange_result}" - msgid "Found auxiliary equipment '{auxiliary}', {exchange_result}" - msgstr "Found auxiliary equipment '{auxiliary}', {exchange_result}" - msgid "Comprehended technique '{technique}', {exchange_result}" - msgstr "Comprehended technique '{technique}', {exchange_result}" - msgid "{name} obtained {amount} spirit stones" - msgstr "{name} obtained {amount} spirit stones" - msgid "{name} cultivation increased by {exp} points" - msgstr "{name} cultivation increased by {exp} points" - msgid "{apprentice} became disciple of {master}" - msgstr "{apprentice} became disciple of {master}" - # Misfortune messages - msgid "Encountered misfortune ({theme}), {result}" - msgstr "Encountered misfortune ({theme}), {result}" - msgid "{name} lost {amount} spirit stones" - msgstr "{name} lost {amount} spirit stones" - msgid "{name} took {damage} damage, HP remaining {current}/{max}" - msgstr "{name} took {damage} damage, HP remaining {current}/{max}" - msgid "{name} cultivation regressed by {amount} points" - msgstr "{name} cultivation regressed by {amount} points" - # Death reasons - msgid "Killed by {killer}" - msgstr "Killed by {killer}" - msgid "Died from severe injuries" - msgstr "Died from severe injuries" - msgid "Died of old age" - msgstr "Died of old age" - # Item exchange - general - msgid "decided to equip it" - msgstr "decided to equip it" - msgid "decided to keep current equipment" - msgstr "decided to keep current equipment" - msgid "decided to learn it" - msgstr "decided to learn it" - msgid "decided to keep current technique" - msgstr "decided to keep current technique" - # Item exchange - detailed messages - msgid "{name} obtained {grade}{label} '{item_name}' and equipped it." - msgstr "{name} obtained {grade}{label} '{item_name}' and equipped it." - msgid "{name} equipped {grade}{label} '{item_name}'." - msgstr "{name} equipped {grade}{label} '{item_name}'." - msgid "{name} sold the newly obtained {item_name}, earning {price} spirit stones." - msgstr "{name} sold the newly obtained {item_name}, earning {price} spirit stones." - msgid "{name} discarded {item_name}." - msgstr "{name} discarded {item_name}." - # Fortune - discovery intro messages - msgid "You discovered a {realm} weapon '{weapon}' during the fortune." - msgstr "You discovered a {realm} weapon '{weapon}' during the fortune." - msgid " But you already have '{current_weapon}'." - msgstr " But you already have '{current_weapon}'." - msgid "You discovered a {realm} auxiliary equipment '{auxiliary}' during the fortune." - msgstr "You discovered a {realm} auxiliary equipment '{auxiliary}' during the fortune." - msgid " But you already have '{current_auxiliary}'." - msgstr " But you already have '{current_auxiliary}'." - msgid "You comprehended superior technique '{technique}' during the fortune." - msgstr "You comprehended superior technique '{technique}' during the fortune." - msgid " This conflicts with your current technique '{current_technique}'." - msgstr " This conflicts with your current technique '{current_technique}'." - # Battle - action descriptions - msgid "defeated" - msgstr "defeated" - # Single choice - context and options - msgid "Current situation: {context}\n\n{choices}" - msgstr "Current situation: {context}\n\n{choices}" - msgid "New {label}: {info}" - msgstr "New {label}: {info}" - msgid "Current {label}: {info}" - msgstr "Current {label}: {info}" - msgid "(Choosing to replace will sell the old {label})" - msgstr "(Choosing to replace will sell the old {label})" - msgid "Equip new {label} '{new_name}'" - msgstr "Equip new {label} '{new_name}'" - msgid ", sell old {label} '{old_name}'" - msgstr ", sell old {label} '{old_name}'" - msgid ", replace old {label} '{old_name}'" - msgstr ", replace old {label} '{old_name}'" - msgid "Sell new {label} '{new_name}' for spirit stones, keep current" - msgstr "Sell new {label} '{new_name}' for spirit stones, keep current" - msgid "Discard '{new_name}'" - msgstr "Discard '{new_name}'" - msgid ", keep current '{old_name}'" - msgstr ", keep current '{old_name}'" - # Labels - msgid "weapon" - msgstr "weapon" - msgid "auxiliary" - msgstr "auxiliary equipment" - msgid "technique" - msgstr "technique" - msgid "elixir" - msgstr "elixir" - # Alignment - msgid "righteous" - msgstr "Righteous" - msgid "neutral" - msgstr "Neutral" - msgid "evil" - msgstr "Evil" - msgid "Righteous alignment follows the principles of helping the weak, maintaining order, and vanquishing evil." - msgstr "Righteous alignment follows the principles of helping the weak, maintaining order, and vanquishing evil." - msgid "Neutral alignment follows the principles of going with the flow, seeking benefit and avoiding harm, valuing self-cultivation and balance, and not easily taking sides." - msgstr "Neutral alignment follows the principles of going with the flow, seeking benefit and avoiding harm, valuing self-cultivation and balance, and not easily taking sides." - msgid "Evil alignment follows the principles of survival of the fittest, prioritizing self-interest above all, disdaining rules, and venerating power and fear. Acts ruthlessly, often resorting to murder and plunder." - msgstr "Evil alignment follows the principles of survival of the fittest, prioritizing self-interest above all, disdaining rules, and venerating power and fear. Acts ruthlessly, often resorting to murder and plunder." - # Gender - msgid "male" - msgstr "Male" - msgid "female" - msgstr "Female" - # Essence Type - msgid "gold_essence" - msgstr "Gold" - msgid "wood_essence" - msgstr "Wood" - msgid "water_essence" - msgstr "Water" - msgid "fire_essence" - msgstr "Fire" - msgid "earth_essence" - msgstr "Earth" - # Realm - msgid "qi_refinement" - msgstr "Qi Refinement" - msgid "foundation_establishment" - msgstr "Foundation Establishment" - msgid "core_formation" - msgstr "Core Formation" - msgid "nascent_soul" - msgstr "Nascent Soul" - # Stage - msgid "early_stage" - msgstr "Early Stage" - msgid "middle_stage" - msgstr "Middle Stage" - msgid "late_stage" - msgstr "Late Stage" - # Weapon Type - msgid "sword" - msgstr "Sword" - msgid "saber" - msgstr "Saber" - msgid "spear" - msgstr "Spear" - msgid "staff" - msgstr "Staff" - msgid "fan" - msgstr "Fan" - msgid "whip" - msgstr "Whip" - msgid "zither" - msgstr "Zither" - msgid "flute" - msgstr "Flute" - msgid "hidden_weapon" - msgstr "Hidden Weapon" - # Technique Attribute - msgid "gold_attribute" - msgstr "Gold" - msgid "wood_attribute" - msgstr "Wood" - msgid "water_attribute" - msgstr "Water" - msgid "fire_attribute" - msgstr "Fire" - msgid "earth_attribute" - msgstr "Earth" - msgid "ice_attribute" - msgstr "Ice" - msgid "wind_attribute" - msgstr "Wind" - msgid "dark_attribute" - msgstr "Dark" - msgid "thunder_attribute" - msgstr "Thunder" - msgid "evil_attribute" - msgstr "Evil" - # Technique Grade - msgid "lower_grade" - msgstr "Inferior Grade" - msgid "middle_grade" - msgstr "Medium Grade" - msgid "upper_grade" - msgstr "Superior Grade" - # Sect Rank - msgid "patriarch" - msgstr "Patriarch" - msgid "elder" - msgstr "Elder" - msgid "inner_disciple" - msgstr "Inner Disciple" - msgid "outer_disciple" - msgstr "Outer Disciple" - # Relation - msgid "parent" - msgstr "Parent" - msgid "child" - msgstr "Child" - msgid "sibling" - msgstr "Sibling" - msgid "kin" - msgstr "Kin" - msgid "master" - msgstr "Master" - msgid "apprentice" - msgstr "Apprentice" - msgid "lovers" - msgstr "Lovers" - msgid "friend" - msgstr "Friend" - msgid "enemy" - msgstr "Enemy" - # Root Element - msgid "gold_element" - msgstr "Gold" - msgid "wood_element" - msgstr "Wood" - msgid "water_element" - msgstr "Water" - msgid "fire_element" - msgstr "Fire" - msgid "earth_element" - msgstr "Earth" - # Action: Assassinate - msgid "assassinate_action_name" - msgstr "Assassinate" - msgid "assassinate_description" - msgstr "Assassinate the target; if failed, turns into combat" - msgid "assassinate_requirements" - msgstr "No restrictions; cooldown required" - msgid "assassinate_story_prompt_success" - msgstr "This is about a successful assassination. No need to describe the combat process, focus on how the assassin lurked, approached, and delivered the fatal, silent strike. The target didn't even have time to react before perishing." - msgid "assassinate_story_prompt_fail" - msgstr "This is about a failed assassination. The assassin attempted to kill the target, but was keenly detected. Both sides then erupted into fierce direct confrontation. Do not mention specific HP values." - msgid "{avatar} lurks in the shadows, attempting to assassinate {target}..." - msgstr "{avatar} lurks in the shadows, attempting to assassinate {target}..." - msgid "{avatar} assassinated successfully! {target} fell without any defense." - msgstr "{avatar} assassinated successfully! {target} fell without any defense." - msgid "Assassination failed! Both sides engaged in fierce battle." - msgstr "Assassination failed! Both sides engaged in fierce battle." - # Action: Attack - msgid "attack_action_name" - msgstr "Initiate Battle" - msgid "attack_description" - msgstr "Attack the target and engage in combat" - msgid "attack_requirements" - msgstr "No restrictions" - msgid "attack_story_prompt" - msgstr "Do not mention specific HP, damage points, or any numerical expressions. The battle should reflect both sides' techniques, cultivation realms, equipment, etc." - msgid "Missing target parameter" - msgstr "Missing target parameter" - msgid "Target does not exist" - msgstr "Target does not exist" - msgid "Target is already dead" - msgstr "Target is already dead" - msgid "{attacker} initiates battle against {target} (Power: {attacker} {att_power} vs {target} {def_power})" - msgstr "{attacker} initiates battle against {target} (Power: {attacker} {att_power} vs {target} {def_power})" - # Action: Breakthrough - msgid "breakthrough_action_name" - msgstr "Breakthrough" - msgid "breakthrough_description" - msgstr "Attempt to breakthrough realm (success increases max lifespan, failure reduces it; higher realm, lower success rate)" - msgid "breakthrough_requirements" - msgstr "Character must be at bottleneck; cannot execute consecutively" - msgid "Not at bottleneck, cannot breakthrough" - msgstr "Not at bottleneck, cannot breakthrough" - msgid "{avatar} begins attempting breakthrough" - msgstr "{avatar} begins attempting breakthrough" - msgid "Breakthrough succeeded" - msgstr "Breakthrough succeeded" - msgid "Breakthrough failed" - msgstr "Breakthrough failed" - msgid "{avatar} breakthrough result: {result}" - msgstr "{avatar} breakthrough result: {result}" - msgid "succeeded" - msgstr "succeeded" - msgid "failed" - msgstr "failed" - msgid "{avatar} encountered {calamity} tribulation, breakthrough {result}" - msgstr "{avatar} encountered {calamity} tribulation, breakthrough {result}" - # Action: Cultivate - msgid "cultivate_action_name" - msgstr "Cultivate" - msgid "cultivate_description" - msgstr "Cultivate to increase cultivation. Best effect in cultivation areas (cave dwellings) with matching essence, otherwise very poor effect" - msgid "cultivate_requirements" - msgstr "Character not at bottleneck; if in cave dwelling area, it must be unowned or belong to oneself" - msgid "Cultivation has reached bottleneck, cannot continue cultivating" - msgstr "Cultivation has reached bottleneck, cannot continue cultivating" - msgid "This cave dwelling has been occupied by {name}, cannot cultivate" - msgstr "This cave dwelling has been occupied by {name}, cannot cultivate" - msgid "excellent progress" - msgstr "excellent progress" - msgid "slow progress (essence mismatch)" - msgstr "slow progress (essence mismatch)" - msgid "slow progress (sparse essence)" - msgstr "slow progress (sparse essence)" - msgid "{avatar} begins cultivating at {location}, {efficiency}" - msgstr "{avatar} begins cultivating at {location}, {efficiency}" - # Action: Escape - msgid "escape_action_name" - msgstr "Escape" - msgid "escape_description" - msgstr "Escape from opponent (success rate based)" - msgid "escape_requirements" - msgstr "No restrictions" - msgid "{avatar} attempted to escape from {target}: {result}" - msgstr "{avatar} attempted to escape from {target}: {result}" - msgid "{avatar} attempts to escape from {target}" - msgstr "{avatar} attempts to escape from {target}" - # Action: SelfHeal - msgid "self_heal_action_name" - msgstr "Self Heal" - msgid "self_heal_description" - msgstr "Heal injuries through meditation; can fully recover at sect headquarters" - msgid "self_heal_requirements" - msgstr "Current HP not full" - msgid "Missing HP information" - msgstr "Missing HP information" - msgid "Current HP is full" - msgstr "Current HP is full" - msgid "wilderness" - msgstr "wilderness" - msgid "{avatar} begins resting and healing at {location}" - msgstr "{avatar} begins resting and healing at {location}" - msgid "{avatar} healing completed (recovered {amount} HP, current HP {hp})" - msgstr "{avatar} healing completed (recovered {amount} HP, current HP {hp})" - # Action: Buy - msgid "buy_action_name" - msgstr "Buy" - msgid "buy_description" - msgstr "Buy items/equipment/elixirs in town" - msgid "buy_requirements" - msgstr "In town and have enough money" - msgid "Can only execute in city areas" - msgstr "Can only execute in city areas" - msgid "Unknown item: {name}" - msgstr "Unknown item: {name}" - msgid "{region} does not sell {item}" - msgstr "{region} does not sell {item}" - msgid "This area has no shop" - msgstr "This area has no shop" - msgid "bought" - msgstr "bought" - msgid "bought and consumed" - msgstr "bought and consumed" - msgid "bought and equipped" - msgstr "bought and equipped" - msgid " (and sold old {item} at reduced price)" - msgstr " (and sold old {item} at reduced price)" - msgid "{avatar} spent {price} spirit stones in town, {action} {item}{suffix}" - msgstr "{avatar} spent {price} spirit stones in town, {action} {item}{suffix}" - # Action: Sell - msgid "sell_action_name" - msgstr "Sell" - msgid "sell_description" - msgstr "Sell all possessed items of a certain type, or current equipment in town" - msgid "sell_requirements" - msgstr "In town and possess sellable items/equipment" - msgid "Do not possess item/equipment: {name}" - msgstr "Do not possess item/equipment: {name}" - msgid "Do not possess material: {name}" - msgstr "Do not possess material: {name}" - msgid "Do not possess equipment: {name}" - msgstr "Do not possess equipment: {name}" - msgid "Cannot sell this type: {name}" - msgstr "Cannot sell this type: {name}" - msgid "{avatar} sold {item} in town" - msgstr "{avatar} sold {item} in town" - # Action: Harvest - msgid "harvest_action_name" - msgstr "Harvest" - msgid "harvest_description" - msgstr "Harvest plants in current area to obtain plant materials" - msgid "harvest_requirements" - msgstr "In normal area with plants, and avatar's realm must be greater than or equal to plant's realm" - msgid "{avatar} begins harvesting at {location}" - msgstr "{avatar} begins harvesting at {location}" - msgid "{avatar} finished harvesting, obtained: {materials}" - msgstr "{avatar} finished harvesting, obtained: {materials}" - # Action: Mine - msgid "mine_action_name" - msgstr "Mine" - msgid "mine_description" - msgstr "Mine ore veins in current area to obtain ore materials" - msgid "mine_requirements" - msgstr "In normal area with ore veins, and avatar's realm must be greater than or equal to vein's realm" - msgid "{avatar} begins mining at {location}" - msgstr "{avatar} begins mining at {location}" - msgid "{avatar} finished mining, obtained: {materials}" - msgstr "{avatar} finished mining, obtained: {materials}" - # Action: Hunt - msgid "hunt_action_name" - msgstr "Hunt" - msgid "hunt_description" - msgstr "Hunt animals in current area to obtain animal materials" - msgid "hunt_requirements" - msgstr "In normal area with animals, and avatar's realm must be greater than or equal to animal's realm" - msgid "{avatar} begins hunting at {location}" - msgstr "{avatar} begins hunting at {location}" - msgid "{avatar} finished hunting, obtained: {materials}" - msgstr "{avatar} finished hunting, obtained: {materials}" - # Action: Refine - msgid "refine_action_name" - msgstr "Refine Elixir" - msgid "refine_description" - msgstr "Consume materials to attempt refining elixirs" - msgid "refine_requirements" - msgstr "Possess 3 materials of the same realm" - msgid "Target realm not specified" - msgstr "Target realm not specified" - msgid "Invalid realm: {realm}" - msgstr "Invalid realm: {realm}" - msgid "Insufficient materials, need {cost} {realm}-tier materials, currently have {count}" - msgstr "Insufficient materials, need {cost} {realm}-tier materials, currently have {count}" - msgid "{avatar} begins attempting to refine {realm}-tier elixir" - msgstr "{avatar} begins attempting to refine {realm}-tier elixir" - msgid "{avatar} failed to refine {realm}-tier elixir, all materials turned to ash" - msgstr "{avatar} failed to refine {realm}-tier elixir, all materials turned to ash" - msgid "Refining succeeded! Obtained {realm} elixir '{item}'" - msgstr "Refining succeeded! Obtained {realm} elixir '{item}'" - msgid "{avatar} successfully refined {realm}-tier elixir '{item}'" - msgstr "{avatar} successfully refined {realm}-tier elixir '{item}'" - # Action: Cast - msgid "cast_action_name" - msgstr "Cast Treasure" - msgid "cast_description" - msgstr "Consume materials to attempt casting treasures" - msgid "cast_requirements" - msgstr "Possess 5 materials of the same realm" - msgid "{avatar} begins attempting to cast {realm}-tier treasure" - msgstr "{avatar} begins attempting to cast {realm}-tier treasure" - msgid "{avatar} failed to cast {realm}-tier treasure, all materials turned to ash" - msgstr "{avatar} failed to cast {realm}-tier treasure, all materials turned to ash" - msgid "Casting succeeded! Obtained {realm} {label} '{item}'" - msgstr "Casting succeeded! Obtained {realm} {label} '{item}'" - msgid "{avatar} successfully cast {realm}-tier {label} '{item}'" - msgstr "{avatar} successfully cast {realm}-tier {label} '{item}'" - # Action: HelpMortals - msgid "help_mortals_action_name" - msgstr "Aid Mortals" - msgid "help_mortals_description" - msgstr "Help mortals in town, consumes small amount of spirit stones" - msgid "help_mortals_requirements" - msgstr "Only in city areas, character alignment must be 'righteous', and have enough spirit stones" - msgid "Only righteous alignment can execute" - msgstr "Only righteous alignment can execute" - msgid "Insufficient spirit stones" - msgstr "Insufficient spirit stones" - msgid "{avatar} begins helping mortals in town" - msgstr "{avatar} begins aiding mortals in town" - # Action: PlunderMortals - msgid "plunder_mortals_action_name" - msgstr "Plunder Mortals" - msgid "plunder_mortals_description" - msgstr "Plunder mortals in town to obtain small amount of spirit stones" - msgid "plunder_mortals_requirements" - msgstr "Only in city areas, and character alignment must be 'evil'" - msgid "Only evil alignment can execute" - msgstr "Only evil alignment can execute" - msgid "{avatar} begins plundering mortals in town" - msgstr "{avatar} begins plundering mortals in town" - # Action: DevourMortals - msgid "devour_mortals_action_name" - msgstr "Devour Mortals" - msgid "devour_mortals_description" - msgstr "Devour mortals to significantly increase combat power" - msgid "devour_mortals_requirements" - msgstr "Possess Ten Thousand Souls Banner" - msgid "Forbidden illegal action (missing Ten Thousand Souls Banner or permission)" - msgstr "Forbidden illegal action (missing Ten Thousand Souls Banner or permission)" - msgid "{avatar} begins devouring mortals in town" - msgstr "{avatar} begins devouring mortals in town" - # Action: Play - msgid "play_action_name" - msgstr "Leisure" - msgid "play_description" - msgstr "Leisure activities to relax body and mind" - msgid "play_requirements" - -msgstr "No restrictions" - +msgstr "Target within interaction range" msgid "{avatar} begins leisure activities" - msgstr "{avatar} begins leisure activities" - # Action: NurtureWeapon - msgid "nurture_weapon_action_name" - msgstr "Nurture Weapon" - msgid "nurture_weapon_description" - msgstr "Nurture weapon to increase weapon proficiency" - msgid "nurture_weapon_requirements" - msgstr "No restrictions" - msgid "{avatar} nurturing {old_weapon}, the weapon's spirituality greatly increased, evolved into {new_weapon}!" - msgstr "{avatar} nurturing {old_weapon}, the weapon's spirituality greatly increased, evolved into {new_weapon}!" - msgid "{avatar} begins nurturing {weapon}" - msgstr "{avatar} begins nurturing {weapon}" - msgid "{avatar} finished nurturing {weapon}, proficiency increased to {proficiency}%" - msgstr "{avatar} finished nurturing {weapon}, proficiency increased to {proficiency}%" - # Action: Catch - msgid "catch_action_name" - msgstr "Tame Beast" - msgid "catch_description" - msgstr "Attempt to tame a spirit beast to become your own. Can only have one spirit beast, but can replace lower grade with higher grade" - msgid "catch_requirements" - msgstr "Only Hundred Beasts Sect; in normal area with animals; target animal realm not higher than character" - msgid "Not currently in normal area" - msgstr "Not currently in normal area" - msgid "Current area {region} has no animals" - msgstr "Current area {region} has no animals" - msgid "Animal realms in current area exceed character realm" - msgstr "Animal realms in current area exceed character realm" - msgid "{avatar} attempts to tame spirit beast at {location}" - msgstr "{avatar} attempts to tame spirit beast at {location}" - msgid "{avatar} failed to tame spirit beast" - msgstr "{avatar} failed to tame spirit beast" - msgid "{avatar} successfully tamed spirit beast, {realm} realm {beast} became their spirit beast" - msgstr "{avatar} successfully tamed spirit beast, {realm} realm {beast} became their spirit beast" - # Direction names - msgid "north" - msgstr "North" - msgid "south" - msgstr "South" - msgid "east" - msgstr "East" - msgid "west" - msgstr "West" - # Action: MoveToDirection - msgid "move_to_direction_action_name" - msgstr "Move & Explore" - msgid "move_to_direction_description" - msgstr "Explore unknown areas in a direction" - msgid "move_to_direction_requirements" - msgstr "No restrictions" - msgid "Invalid direction: {direction}" - msgstr "Invalid direction: {direction}" - msgid "{avatar} begins moving toward {direction}" - msgstr "{avatar} begins moving toward {direction}" - msgid "{avatar} finished moving toward {direction}" - msgstr "{avatar} finished moving toward {direction}" - # Action: MoveToRegion - msgid "move_to_region_action_name" - msgstr "Move to Region" - msgid "move_to_region_description" - msgstr "Move to a specific region" - msgid "move_to_region_requirements" - msgstr "No restrictions" - msgid "Cannot resolve region: {region}" - msgstr "Cannot resolve region: {region}" - msgid "[{region}] is another sect's territory, you are not a disciple of that sect" - msgstr "[{region}] is another sect's territory, you are not a disciple of that sect" - msgid "{avatar} begins moving toward {region}" - msgstr "{avatar} begins moving toward {region}" - msgid "{avatar} attempted to move but target is invalid" - msgstr "{avatar} attempted to move but target is invalid" - # Action: MoveToAvatar - msgid "move_to_avatar_action_name" - msgstr "Move to Character" - msgid "move_to_avatar_description" - msgstr "Move to a specific character's location" - msgid "move_to_avatar_requirements" - msgstr "No restrictions" - msgid "{avatar} begins moving toward {target}" - msgstr "{avatar} begins moving toward {target}" - # Action: MoveAwayFromAvatar - msgid "move_away_from_avatar_action_name" - msgstr "Move Away from Character" - msgid "move_away_from_avatar_description" - msgstr "Continuously move away from specified character" - msgid "move_away_from_avatar_requirements" - msgstr "No restrictions" - msgid "{avatar} begins moving away from {target}" - msgstr "{avatar} begins moving away from {target}" - # Action: MoveAwayFromRegion - msgid "move_away_from_region_action_name" - msgstr "Leave Region" - msgid "move_away_from_region_description" - msgstr "Leave specified region" - msgid "move_away_from_region_requirements" - msgstr "No restrictions" - msgid "{avatar} begins leaving {region}" - msgstr "{avatar} begins leaving {region}" - # Action: Move (Base) - msgid "move_action_name" - msgstr "Move" - msgid "move_description" - msgstr "Move to a relative position" - # MutualAction Base - msgid "mutual_action_name" - msgstr "Mutual Action" - msgid "mutual_action_requirements" - msgstr "Target within interaction range" - msgid "Cannot initiate interaction with self" - msgstr "Cannot initiate interaction with self" - msgid "{initiator} initiates {action} with {target}" - msgstr "{initiator} initiates {action} with {target}" - msgid "{target} feedback to {initiator}: {feedback}" - msgstr "{target} feedback to {initiator}: {feedback}" - # Feedback labels - msgid "feedback_accept" - msgstr "Accept" - msgid "feedback_reject" - msgstr "Reject" - msgid "feedback_move_away_from_avatar" - msgstr "Attempt to move away" - msgid "feedback_move_away_from_region" - msgstr "Attempt to leave area" - msgid "feedback_escape" - msgstr "Escape" - msgid "feedback_attack" - msgstr "Attack" - # Action: DualCultivation - msgid "dual_cultivation_action_name" - msgstr "Dual Cultivation" - msgid "dual_cultivation_description" - msgstr "Cultivation through intimacy, target can accept or reject" - msgid "dual_cultivation_requirements" - msgstr "Target within interaction range; cannot execute consecutively" - msgid "dual_cultivation_story_prompt" - msgstr "Two cultivators develop feelings during dual cultivation. Describe an elegant and subtle dual cultivation experience with implied romance, reflecting their personalities, realm differences, and sweet romantic moments. Do not mention numerical experience values." - msgid "{initiator} invites {target} for dual cultivation" - msgstr "{initiator} invites {target} for dual cultivation" - # MutualAction: Attack - msgid "mutual_attack_action_name" - msgstr "Attack" - msgid "mutual_attack_description" - msgstr "Attack the target" - msgid "mutual_attack_requirements" - msgstr "Target within interaction range; cannot execute consecutively" - msgid "Target not within interaction range" - msgstr "Target not within interaction range" - # MutualAction: DriveAway - msgid "drive_away_action_name" - msgstr "Drive Away" - msgid "drive_away_description" - msgstr "Intimidate opponent to leave this place with force" - msgid "drive_away_requirements" - msgstr "Target within interaction range; cannot execute consecutively" - msgid "Cannot drive away in wilderness" - msgstr "Cannot drive away in wilderness" - # MutualAction: Conversation - msgid "conversation_action_name" - msgstr "Conversation" - msgid "conversation_description" - msgstr "Have an exchange conversation with opponent" - msgid "conversation_requirements" - msgstr "Target within interaction range" - msgid "{avatar1} conversation with {avatar2}: {content}" - msgstr "{avatar1} conversation with {avatar2}: {content}" - # MutualAction: Talk - msgid "talk_action_name" - msgstr "Talk" - msgid "talk_description" - msgstr "Initiate a talk with someone, cannot be self" - msgid "talk_requirements" - msgstr "Target within interaction range" - msgid "feedback_talk" - msgstr "Talk" - msgid "{target} accepted {initiator}'s talk invitation" - msgstr "{target} accepted {initiator}'s talk invitation" - msgid "{target} rejected {initiator}'s talk invitation" - msgstr "{target} rejected {initiator}'s talk invitation" - # MutualAction: Spar - msgid "spar_action_name" - msgstr "Spar" - msgid "spar_description" - msgstr "Spar with target, stop at the right moment (greatly increases weapon proficiency, no damage)" - msgid "spar_requirements" - msgstr "Target within interaction range; cannot execute consecutively" - msgid "spar_story_prompt" - msgstr "This is a friendly sparring between two people, stopping at the right moment, without real harm. Focus on describing the exquisite moves of both sides and their mutual inspiration. Do not include bloody or severe injury descriptions." - msgid "{winner} gained slight advantage in sparring, defeated {loser}. ({winner} proficiency +{w_gain}, {loser} proficiency +{l_gain})" - msgstr "{winner} gained slight advantage in sparring, defeated {loser}. ({winner} proficiency +{w_gain}, {loser} proficiency +{l_gain})" - msgid "{initiator} challenges {target} to spar" - msgstr "{initiator} challenges {target} to spar" - # MutualAction: Gift - msgid "gift_action_name" - msgstr "Gift" - msgid "gift_description" - msgstr "Gift spirit stones or items to opponent" - msgid "gift_requirements" - msgstr "Initiator possesses the item; target within interaction range" - msgid "spirit stones" - msgstr "spirit stones" - msgid "Item not found: {name}" - msgstr "Item not found: {name}" - msgid "Insufficient spirit stones (current: {current}, need: {need})" - msgstr "Insufficient spirit stones (current: {current}, need: {need})" - msgid "Item not equipped: {name}" - msgstr "Item not equipped: {name}" - msgid "Insufficient item: {name}" - msgstr "Insufficient item: {name}" - msgid "Gift you {item}" - msgstr "Gift you {item}" - msgid "{initiator} attempts to gift {item} to {target}" - msgstr "{initiator} attempts to gift {item} to {target}" - msgid "{initiator} successfully gifted {item} to {target}" - msgstr "{initiator} successfully gifted {item} to {target}" - # MutualAction: Impart - msgid "impart_action_name" - msgstr "Impart Knowledge" - msgid "impart_description" - msgstr "Master imparts cultivation experience to apprentice, apprentice can gain large amount of cultivation" - msgid "impart_requirements" - msgstr "Initiator is target's master; master level > apprentice level + 20; target within interaction range; cannot execute consecutively" - msgid "Target is not your apprentice" - msgstr "Target is not your apprentice" - msgid "Level difference insufficient, need 20 levels (current gap: {diff} levels)" - msgstr "Level difference insufficient, need 20 levels (current gap: {diff} levels)" - msgid "{master} imparts cultivation knowledge to apprentice {apprentice}" - msgstr "{master} imparts cultivation knowledge to apprentice {apprentice}" - # MutualAction: Occupy - msgid "occupy_action_name" - msgstr "Seize Cave Dwelling" - msgid "occupy_description" - msgstr "Occupy or seize cave dwelling" - msgid "occupy_requirements" - msgstr "Target within interaction range; cannot execute consecutively" - msgid "occupy_story_prompt" - msgstr "This is a battle for cave dwelling. Do not mention specific HP or damage values." - msgid "feedback_yield" - msgstr "Yield" - msgid "Cannot find region: {region}" - msgstr "Cannot find region: {region}" - msgid "{region} is not a cultivation area, cannot occupy" - msgstr "{region} is not a cultivation area, cannot occupy" - msgid "Already the owner of this cave dwelling" - msgstr "Already the owner of this cave dwelling" - msgid "{initiator} attempts to seize {region} from {host}" - msgstr "{initiator} attempts to seize {region} from {host}" - msgid "{initiator} forced {target} to yield {region}" - msgstr "{initiator} forced {target} to yield {region}" - msgid "{initiator} attempted to seize {target}'s cave dwelling {region}, {target} rejected and engaged in battle" - msgstr "{initiator} attempted to seize {target}'s cave dwelling {region}, {target} rejected and engaged in battle" - msgid ", successfully seized {region}" - msgstr ", successfully seized {region}" - msgid ", defended {region}" - msgstr ", defended {region}" - # ============================================================================ # Effect System @@ -2507,7 +1749,6 @@ msgstr "Elixir [{name}]" # ============================================================================ - # Field Labels (info_dict keys) msgid "Name" @@ -2777,7 +2018,6 @@ msgstr "{name}, Nickname: {nickname}, Realm: {realm}, Relation: {relation}, Sect # ============================================================================ - # Status Text msgid "Auction is in progress..." @@ -2857,7 +2097,6 @@ msgstr "Select the most interesting aspect or bidding moment to describe, no nee # ============================================================================ - # Fortune Themes msgid "fortune_theme_wandered_into_cave" @@ -3486,37 +2725,31 @@ msgstr "Retreat Insight" # ============================================================================ - msgid "Sect Headquarters" msgstr "Sect Headquarters" - msgid "Normal Region" msgstr "Normal Region" - msgid "Cave Dwelling" msgstr "Cave Dwelling" - msgid "Ruins" msgstr "Ruins" - msgid "City Region" msgstr "City Region" - # ============================================================================ # Simulator & Event Translations @@ -3524,37 +2757,31 @@ msgstr "City Region" # ============================================================================ - msgid "{avatar_name} passed by {region_name}, found it ownerless, and occupied it." msgstr "{avatar_name} passed by {region_name}, found it ownerless, and occupied it." - msgid "{avatar_name} deliberated and redefined their long-term objective: {objective}" msgstr "{avatar_name} deliberated and redefined their long-term objective: {objective}" - msgid "{avatar_name} determined their long-term objective: {objective}" msgstr "{avatar_name} determined their long-term objective: {objective}" - msgid "world_creation_phenomenon" msgstr "The world is born, celestial phenomena descend! {name}: {desc}." - msgid "phenomenon_change" msgstr "{old_name} dissipates, celestial phenomena reappear! {new_name}: {new_desc}." - # ============================================================================ # Map & Region & Others (New) @@ -3562,175 +2789,127 @@ msgstr "{old_name} dissipates, celestial phenomena reappear! {new_name}: {new_de # ============================================================================ - msgid "Cultivate Region (can cultivate to increase cultivation)" msgstr "Cultivate Region (can cultivate to increase cultivation)" - msgid "Normal Region (can hunt, gather, mine)" msgstr "Normal Region (can hunt, gather, mine)" - msgid "City Region (can trade)" msgstr "City Region (can trade)" - msgid "Sect Headquarters (sect disciples heal faster here)" msgstr "Sect Headquarters (sect disciples heal faster here)" - msgid " (Distance: {months} months)" msgstr " (Distance: {months} months)" - msgid "No special resources" msgstr "No special resources" - msgid " (Resource Distribution: {species_info})" msgstr " (Resource Distribution: {species_info})" - msgid "Normal Region: {name} - {desc} | Resource Distribution: {species_info}" msgstr "Normal Region: {name} - {desc} | Resource Distribution: {species_info}" - msgid " ({essence_type} Essence: {essence_density})" msgstr " ({essence_type} Essence: {essence_density})" - msgid "Cultivate Region: {name} ({essence_type} Essence: {essence_density}) - {desc}" msgstr "Cultivate Region: {name} ({essence_type} Essence: {essence_density}) - {desc}" - msgid " ({store_info})" msgstr " ({store_info})" - msgid " | {store_info}" msgstr " | {store_info}" - msgid "City Region: {name} - {desc}{desc_part}" msgstr "City Region: {name} - {desc}{desc_part}" - msgid "{value} Spirit Stones" msgstr "{value} Spirit Stones" - msgid " ({desc})" msgstr " ({desc})" - msgid "\nEffect: {effect_desc}" msgstr "\nEffect: {effect_desc}" - msgid "{names} ({price} Spirit Stones)" msgstr "{names} ({price} Spirit Stones)" - msgid "Sell: " msgstr "Sell: " - -msgid "平静" - +msgid "emotion_calm" msgstr "Calm" - - -msgid "开心" - +msgid "emotion_happy" msgstr "Happy" - - -msgid "愤怒" - +msgid "emotion_angry" msgstr "Angry" - - -msgid "悲伤" - +msgid "emotion_sad" msgstr "Sad" - - -msgid "恐惧" - +msgid "emotion_fearful" msgstr "Fearful" - - -msgid "惊讶" - +msgid "emotion_surprised" msgstr "Surprised" - - -msgid "期待" - +msgid "emotion_anticipating" msgstr "Anticipating" - - -msgid "厌恶" - +msgid "emotion_disgusted" msgstr "Disgusted" - - -msgid "疑惑" - +msgid "emotion_confused" msgstr "Confused" - - -msgid "疲惫" - +msgid "emotion_tired" msgstr "Tired" - # ============================================================================ # Relation & Root & Appearance & Sect (Refined) @@ -3738,19 +2917,16 @@ msgstr "Tired" # ============================================================================ - msgid "Unknown reason" msgstr "Unknown reason" - msgid "{name} (Deceased: {reason})" msgstr "{name} (Deceased: {reason})" - # Relations msgid "relation_father" @@ -3758,49 +2934,41 @@ msgid "relation_father" msgstr "Father" - msgid "relation_mother" msgstr "Mother" - msgid "relation_son" msgstr "Son" - msgid "relation_daughter" msgstr "Daughter" - msgid "relation_older_brother" msgstr "Older Brother" - msgid "relation_younger_brother" msgstr "Younger Brother" - msgid "relation_older_sister" msgstr "Older Sister" - msgid "relation_younger_sister" msgstr "Younger Sister" - # Root Keys msgid "root_gold" @@ -3808,407 +2976,51 @@ msgid "root_gold" msgstr "Gold Root" - msgid "root_wood" msgstr "Wood Root" - msgid "root_water" msgstr "Water Root" - msgid "root_fire" msgstr "Fire Root" - msgid "root_earth" msgstr "Earth Root" - msgid "root_thunder" msgstr "Thunder Root" - msgid "root_ice" msgstr "Ice Root" - msgid "root_wind" msgstr "Wind Root" - msgid "root_dark" msgstr "Dark Root" - msgid "root_heaven" msgstr "Heaven Root" - -# Sect Ranks Keys - - - -# Appearance Keys - -msgid "appearance_1_name" - -msgstr "Hideous" - -msgid "appearance_1_desc_male" - -msgstr "You are very ugly, with uncoordinated features, and people often avoid you." - -msgid "appearance_1_desc_female" - -msgstr "You are very ugly, with uncoordinated features, and people often stay away." - - - -msgid "appearance_2_name" - -msgstr "Ugly" - -msgid "appearance_2_desc_male" - -msgstr "Your features are rough, with a collapsed nose bridge and a slightly protruding chin." - -msgid "appearance_2_desc_female" - -msgstr "Your features are rough, with high cheekbones and messy lip lines." - - - -msgid "appearance_3_name" - -msgstr "Crude" - -msgid "appearance_3_desc_male" - -msgstr "Your appearance is crude and not pleasing to the eye." - -msgid "appearance_3_desc_female" - -msgstr "Your appearance is crude, with a slightly mean expression." - - - -msgid "appearance_4_name" - -msgstr "Plain" - -msgid "appearance_4_desc_male" - -msgstr "You look ordinary, with faint features, dressed simply and unobtrusively." - -msgid "appearance_4_desc_female" - -msgstr "You look ordinary, with a faint complexion, dressed simply and not standing out." - - - -msgid "appearance_5_name" - -msgstr "Delicate" - -msgid "appearance_5_desc_male" - -msgstr "You have delicate features and look pleasing to the eye." - -msgid "appearance_5_desc_female" - -msgstr "You have delicate features and look quite attractive." - - - -msgid "appearance_6_name" - -msgstr "Refined" - -msgid "appearance_6_desc_male" - -msgstr "You have exquisite features and a dignified temperament." - -msgid "appearance_6_desc_female" - -msgstr "You have exquisite features and a gentle temperament." - - - -msgid "appearance_7_name" - -msgstr "Handsome" - -msgid "appearance_7_desc_male" - -msgstr "You are very handsome and turn heads wherever you go." - -msgid "appearance_7_desc_female" - -msgstr "You are very beautiful and eye-catching." - - - -msgid "appearance_8_name" - -msgstr "Alluring" - -msgid "appearance_8_desc_male" - -msgstr "Your appearance is outstanding and eye-catching wherever you go." - -msgid "appearance_8_desc_female" - -msgstr "You are stunningly beautiful." - - - -msgid "appearance_9_name" - -msgstr "Stunning" - -msgid "appearance_9_desc_male" - -msgstr "Your looks and temperament are top-notch, often attracting attention." - -msgid "appearance_9_desc_female" - -msgstr "You are breathtakingly beautiful, unforgettable at first sight." - - - -msgid "appearance_10_name" - -msgstr "Breathtaking" - -msgid "appearance_10_desc_male" - -msgstr "You are so beautiful that you seem not of this world." - -msgid "appearance_10_desc_female" - -msgstr "You are breathtakingly beautiful, remembered at a glance." - - - -# ============================================================================ - -# Relation & Root & Appearance & Sect (New) - -# ============================================================================ - - - -msgid "comma_separator" - -msgstr ", " - - - -msgid "semicolon_separator" - -msgstr "; " - - - -msgid "{label}: {names}" - -msgstr "{label}: {names}" - - - -msgid "{root_name} ({elements})" - -msgstr "{root_name} ({elements})" - - - -msgid "{sect} {rank}" - -msgstr "{sect} {rank}" - - - -# Spirit Root - -msgid "金灵根" - -msgstr "Gold Root" - - - -msgid "木灵根" - -msgstr "Wood Root" - - - -msgid "水灵根" - -msgstr "Water Root" - - - -msgid "火灵根" - -msgstr "Fire Root" - - - -msgid "土灵根" - -msgstr "Earth Root" - - - -msgid "雷灵根" - -msgstr "Thunder Root" - - - -msgid "冰灵根" - -msgstr "Ice Root" - - - -msgid "风灵根" - -msgstr "Wind Root" - - - -msgid "暗灵根" - -msgstr "Dark Root" - - - -msgid "天灵根" - -msgstr "Heaven Root" - - - -# Sect Ranks - -msgid "掌门" - -msgstr "Patriarch" - - - -msgid "长老" - -msgstr "Elder" - - - -msgid "内门弟子" - -msgstr "Inner Disciple" - - - -msgid "外门弟子" - -msgstr "Outer Disciple" - - - -# Appearance - -msgid "奇丑" - -msgstr "Hideous" - - - -msgid "丑陋" - -msgstr "Ugly" - - - -msgid "粗陋" - -msgstr "Crude" - - - -msgid "寒素" - -msgstr "Plain" - - - -msgid "清秀" - -msgstr "Delicate" - - - -msgid "秀致" - -msgstr "Refined" - - - -msgid "俊美" - -msgstr "Handsome" - - - -msgid "倾城" - -msgstr "Alluring" - - - -msgid "绝色" - -msgstr "Stunning" - - - -msgid "惊艳" - -msgstr "Breathtaking" - - - -msgid "你长得很俊,回头率很高。" - -msgstr "You are very handsome and turn heads." - - - -msgid "你长得很美,很抢眼。" - -msgstr "You are very beautiful and eye-catching." - - - # ============================================================================ # Additional (New) @@ -4216,169 +3028,351 @@ msgstr "You are very beautiful and eye-catching." # ============================================================================ +msgid "action_thinking" + +msgstr "Thinking" + msgid "{alignment}: {description}" msgstr "{alignment}: {description}" - msgid "{name} ({realm})" msgstr "{name} ({realm})" - msgid "{name}: {desc} ({realm})" msgstr "{name}: {desc} ({realm})" - msgid "{realm} {stage} (Level {level}) {status}" msgstr "{realm} {stage} (Level {level}) {status}" - msgid "{realm} {stage} (Level {level}). At bottleneck: {status}" msgstr "{realm} {stage} (Level {level}). At bottleneck: {status}" - msgid "Unknown character" msgstr "Unknown character" - msgid "{name} ({desc}{effect})" msgstr "{name} ({desc}{effect})" - msgid "{name} has ascended to a cultivator." msgstr "{name} has ascended to a cultivator." - msgid "old_age" msgstr "Old Age" - msgid "battle" msgstr "Battle" - msgid "serious_injury" msgstr "Serious Injury" - msgid "(Unknown technique)" msgstr "(Unknown technique)" - - - - msgid "(Alignment: {alignment}, Style: {style}, Headquarters: {hq_name}){effect}" msgstr "(Alignment: {alignment}, Style: {style}, Headquarters: {hq_name}){effect}" - msgid "Drops: {materials}" msgstr "Drops: {materials}" - msgid "[{name}] ({realm})" msgstr "[{name}] ({realm})" - msgid "{name} ({attribute}) {grade}" msgstr "{name} ({attribute}) {grade}" - msgid "{name} ({attribute}) {grade} {desc}{effect}" msgstr "{name} ({attribute}) {grade} {desc}{effect}" - msgid "{name} ({attribute}·{grade})" msgstr "{name} ({attribute}·{grade})" - msgid "{name} ({type}·{realm}, {desc}){effect}" msgstr "{name} ({type}·{realm}, {desc}){effect}" - msgid "date_format_year_month" + msgstr "Year {year} Month {month}" + msgid "sect_headquarters_desc_format" + msgstr "({sect_name} HQ)" + msgid "Current World Phenomenon" + msgstr "Current World Phenomenon" + msgid "phenomenon_format" + msgstr "{name}: {desc}" + msgid "Wilderness" + msgstr "Wilderness" + msgid "relation_rule_establish_title" + msgstr "[Establish Relation Rules]" + msgid "relation_rule_cancel_title" + msgstr "[Cancel Relation Rules]" + msgid "relation_rule_lovers_add" + msgstr "[Dao Companion] Requires opposite genders. Must be mutual deep recognition and affection." + msgid "relation_rule_friend_add" + msgstr "[Friend] Friendly interactions (chat, spar without killing, heal). No substantial conflict of interest." + msgid "relation_rule_enemy_add" + msgstr "[Enemy] Substantial harm occurred (injury, theft, humiliation). Single severe harm or multiple minor frictions." + msgid "relation_rule_master_add" + msgstr "[Master] Realm must be significantly higher than apprentice (e.g. Golden Core vs Qi Refinement)." + msgid "relation_rule_apprentice_add" + msgstr "[Apprentice] Relative to Master, usually established automatically with Master relation." + msgid "relation_rule_lovers_cancel" + msgstr "[Break Up] Conflict, emotional breakdown, severe betrayal." + msgid "relation_rule_friend_cancel" + msgstr "[Break Off] Conflict of interest, betrayal, or estrangement due to lack of interaction." + msgid "relation_rule_enemy_cancel" + msgstr "[Reconcile] One side initiates kindness and is accepted, or shared life-and-death experience, or hatred fades." + msgid "relation_rule_master_cancel" + msgstr "[Expel/Betray] Apprentice is rebellious or Master is unable to teach." + msgid "relation_rule_apprentice_cancel" + msgstr "[End Apprenticeship] Same as above." + msgid "History" + msgstr "History" + msgid "When alignment is {align}" + msgstr "When alignment is {align}" + msgid "When using {weapon_type}" + msgstr "When using {weapon_type}" + +# Action: Play Extended +msgid "action_reading" +msgstr "Reading" + +msgid "action_tea_tasting" +msgstr "Tea Tasting" + +msgid "action_traveling" +msgstr "Traveling" + +msgid "action_zither_playing" +msgstr "Playing Zither" + +msgid "action_tea_party" +msgstr "Tea Party" + +msgid "action_chess" +msgstr "Chess" + +msgid "{avatar} starts {action}" +msgstr "{avatar} starts {action}" + +msgid "{avatar} finished {action}." +msgstr "{avatar} finished {action}." + +msgid "gained {val} cultivation" +msgstr "Gained {val} cultivation." + +msgid "breakthrough probability increased by {val:.1%}" +msgstr "Breakthrough probability increased by {val:.1%}." + +# Automatically added missing keys +msgid "appearance_1_name" +msgstr "Hideous" + +msgid "appearance_1_desc_male" +msgstr "You are very ugly, with discordant features, often drawing stares." + +msgid "appearance_1_desc_female" +msgstr "You are very ugly, with discordant features, making people avoid you." + +msgid "appearance_2_name" +msgstr "Ugly" + +msgid "appearance_2_desc_male" +msgstr "Your appearance is crude, with some features appearing quite abrupt." + +msgid "appearance_2_desc_female" +msgstr "Your appearance is crude, with some features appearing quite abrupt." + +msgid "appearance_3_name" +msgstr "Coarse" + +msgid "appearance_3_desc_male" +msgstr "Your appearance is mediocre and not very pleasant to look at." + +msgid "appearance_3_desc_female" +msgstr "Your appearance is mediocre and not very pleasant to look at." + +msgid "appearance_4_name" +msgstr "Plain" + +msgid "appearance_4_desc_male" +msgstr "You look very ordinary, easily lost in a crowd." + +msgid "appearance_4_desc_female" +msgstr "You look very ordinary, easily lost in a crowd." + +msgid "appearance_5_name" +msgstr "Delicate" + +msgid "appearance_5_desc_male" +msgstr "You have delicate features and are quite pleasant to look at." + +msgid "appearance_5_desc_female" +msgstr "You have delicate features and are quite pleasant to look at." + +msgid "appearance_6_name" +msgstr "Elegant" + +msgid "appearance_6_desc_male" +msgstr "You have regular features and look very energetic." + +msgid "appearance_6_desc_female" +msgstr "You have regular features and look very energetic." + +msgid "appearance_7_name" +msgstr "Handsome/Beautiful" + +msgid "appearance_7_desc_male" +msgstr "You are very handsome, with a high head-turning rate." + +msgid "appearance_7_desc_female" +msgstr "You are very beautiful and eye-catching." + +msgid "appearance_8_name" +msgstr "Stunning" + +msgid "appearance_8_desc_male" +msgstr "You have an outstanding appearance and are eye-catching wherever you go." + +msgid "appearance_8_desc_female" +msgstr "You are so beautiful that it's stunning." + +msgid "appearance_9_name" +msgstr "Exquisite" + +msgid "appearance_9_desc_male" +msgstr "Both your looks and aura are top-tier, often attracting side glances." + +msgid "appearance_9_desc_female" +msgstr "Your beauty is breathtaking, almost unforgettable at first sight." + +msgid "appearance_10_name" +msgstr "Breathtaking" + +msgid "appearance_10_desc_male" +msgstr "You are so beautiful that you seem otherworldly." + +msgid "appearance_10_desc_female" +msgstr "Your beauty is so breathtaking that one remembers you at a single glance." + +msgid "comma_separator" +msgstr ", " + +msgid "semicolon_separator" +msgstr "; " + +msgid "{label}: {names}" +msgstr "{label}: {names}" + +msgid "{root_name} ({elements})" +msgstr "{root_name} ({elements})" + +msgid "{sect} {rank}" +msgstr "{sect} {rank}" + +msgid "action_reading_desc" +msgstr "Read ancient books to gain knowledge." + +msgid "action_tea_tasting_desc" +msgstr "Taste fine tea and cultivate a peaceful mind." + +msgid "action_traveling_desc" +msgstr "Travel around to experience the world." + +msgid "action_zither_playing_desc" +msgstr "Play the zither and nurture your temperament." + +msgid "action_tea_party_desc" +msgstr "Share tea with friends." + +msgid "action_chess_desc" +msgstr "Play chess to sharpen your mind." + +msgid "action_tea_party_story_prompt" +msgstr "Two people are holding an elegant tea party." + +msgid "action_chess_story_prompt" +msgstr "Two people are playing chess." diff --git a/src/i18n/locales/zh_CN/LC_MESSAGES/messages.mo b/src/i18n/locales/zh_CN/LC_MESSAGES/messages.mo index bf52406..48ddf74 100644 Binary files a/src/i18n/locales/zh_CN/LC_MESSAGES/messages.mo and b/src/i18n/locales/zh_CN/LC_MESSAGES/messages.mo differ diff --git a/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po b/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po index 1e4b929..cdbc483 100644 --- a/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po +++ b/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po @@ -726,7 +726,7 @@ msgid "play_description" msgstr "消遣,放松身心" msgid "play_requirements" -msgstr "无限制" +msgstr "目标在交互范围内" msgid "{avatar} begins leisure activities" msgstr "{avatar} 开始消遣" @@ -1853,34 +1853,34 @@ msgstr "{names}({price}灵石)" msgid "Sell: " msgstr "出售:" -msgid "平静" +msgid "emotion_calm" msgstr "平静" -msgid "开心" +msgid "emotion_happy" msgstr "开心" -msgid "愤怒" +msgid "emotion_angry" msgstr "愤怒" -msgid "悲伤" +msgid "emotion_sad" msgstr "悲伤" -msgid "恐惧" +msgid "emotion_fearful" msgstr "恐惧" -msgid "惊讶" +msgid "emotion_surprised" msgstr "惊讶" -msgid "期待" +msgid "emotion_anticipating" msgstr "期待" -msgid "厌恶" +msgid "emotion_disgusted" msgstr "厌恶" -msgid "疑惑" +msgid "emotion_confused" msgstr "疑惑" -msgid "疲惫" +msgid "emotion_tired" msgstr "疲惫" # ============================================================================ @@ -2041,91 +2041,13 @@ msgstr "{root_name}({elements})" msgid "{sect} {rank}" msgstr "{sect}{rank}" -# 灵根 -msgid "金灵根" -msgstr "金灵根" - -msgid "木灵根" -msgstr "木灵根" - -msgid "水灵根" -msgstr "水灵根" - -msgid "火灵根" -msgstr "火灵根" - -msgid "土灵根" -msgstr "土灵根" - -msgid "雷灵根" -msgstr "雷灵根" - -msgid "冰灵根" -msgstr "冰灵根" - -msgid "风灵根" -msgstr "风灵根" - -msgid "暗灵根" -msgstr "暗灵根" - -msgid "天灵根" -msgstr "天灵根" - -# 宗门职位 -msgid "掌门" -msgstr "掌门" - -msgid "长老" -msgstr "长老" - -msgid "内门弟子" -msgstr "内门弟子" - -msgid "外门弟子" -msgstr "外门弟子" - -# 外貌 -msgid "奇丑" -msgstr "奇丑" - -msgid "丑陋" -msgstr "丑陋" - -msgid "粗陋" -msgstr "粗陋" - -msgid "寒素" -msgstr "寒素" - -msgid "清秀" -msgstr "清秀" - -msgid "秀致" -msgstr "秀致" - -msgid "俊美" -msgstr "俊美" - -msgid "倾城" -msgstr "倾城" - -msgid "绝色" -msgstr "绝色" - -msgid "惊艳" -msgstr "惊艳" - -msgid "你长得很俊,回头率很高。" -msgstr "你长得很俊,回头率很高。" - -msgid "你长得很美,很抢眼。" -msgstr "你长得很美,很抢眼。" - # ============================================================================ # Additional (New) # ============================================================================ +msgid "action_thinking" +msgstr "思考" + msgid "{alignment}: {description}" msgstr "{alignment}:{description}" @@ -2245,3 +2167,58 @@ msgstr "当阵营为{align}时" msgid "When using {weapon_type}" msgstr "当使用{weapon_type}时" + +# Action: Play Extended +msgid "action_reading" +msgstr "读书" + +msgid "action_tea_tasting" +msgstr "品茶" + +msgid "action_traveling" +msgstr "游历" + +msgid "action_zither_playing" +msgstr "抚琴" + +msgid "action_tea_party" +msgstr "茶会" + +msgid "action_chess" +msgstr "下棋" + +msgid "{avatar} starts {action}" +msgstr "{avatar} 开始{action}" + +msgid "{avatar} finished {action}." +msgstr "{avatar} 完成了{action}。" + +msgid "gained {val} cultivation" +msgstr "若有所悟,修为增加 {val}" + +msgid "breakthrough probability increased by {val:.1%}" +msgstr "心境提升,突破概率增加 {val:.1%}" + +msgid "action_reading_desc" +msgstr "研读古籍,增长见闻。" + +msgid "action_tea_tasting_desc" +msgstr "品味清茶,静心养性。" + +msgid "action_traveling_desc" +msgstr "游历四方,感悟天地。" + +msgid "action_zither_playing_desc" +msgstr "抚琴奏乐,陶冶情操。" + +msgid "action_tea_party_desc" +msgstr "与友共品清茶。" + +msgid "action_chess_desc" +msgstr "对弈博弈,磨砺心智。" + +msgid "action_tea_party_story_prompt" +msgstr "两人正在举行一场雅致的茶会。" + +msgid "action_chess_story_prompt" +msgstr "两人正在对弈下棋。" diff --git a/src/sim/load/avatar_load_mixin.py b/src/sim/load/avatar_load_mixin.py index 58b366a..e922714 100644 --- a/src/sim/load/avatar_load_mixin.py +++ b/src/sim/load/avatar_load_mixin.py @@ -158,7 +158,7 @@ class AvatarLoadMixin: # 恢复情绪 from src.classes.emotions import EmotionType - emotion_str = data.get("emotion", "平静") + emotion_str = data.get("emotion", "emotion_calm") try: avatar.emotion = EmotionType(emotion_str) except ValueError: diff --git a/static/config.yml b/static/config.yml index 03b08cd..eeec99b 100644 --- a/static/config.yml +++ b/static/config.yml @@ -59,3 +59,6 @@ frontend: cloud_freq: low system: language: zh-CN + +play: + base_benefit_probability: 0.05 diff --git a/static/locales/en-US/game_configs/persona.csv b/static/locales/en-US/game_configs/persona.csv index f6b3a64..eedd9cc 100644 --- a/static/locales/en-US/game_configs/persona.csv +++ b/static/locales/en-US/game_configs/persona.csv @@ -71,3 +71,9 @@ id,key,name,exclusion_keys,desc,rarity,condition,effects 69,DEVOTED,Devoted,LUSTFUL;ROMANTIC;HEARTLESS,"You are devoted in love, once committed, you will not change.",N,, 70,ROMANTIC,Romantic,DESIRELESS;HEARTLESS;DEVOTED,"You are easily moved by emotions, full of longing for beautiful feelings.",N,, 71,HEARTLESS,Heartless,DEVOTED;ROMANTIC;FRIENDLY,"You are indifferent to emotions, not easily moved.",N,, +1001,PLAYFUL,Playful,RATIONAL;CULTIVATION_OBSESSED,"Indulging in fun, not thinking about progress.",N,, +1002,BOOKWORM,Bookworm,RASH,"Addicted to books.",R,, +1003,TEA_LOVER,Tea Lover,,"Can't go a day without tea.",R,, +1004,MUSICIAN,Musician,,"Good at playing the zither.",R,, +1005,TRAVELER,Traveler,HOMEBODY,"Reading ten thousand books is not as good as traveling ten thousand miles.",R,, +1006,CHESS_PLAYER,Chess Player,,"Good chess players live long.",R,, \ No newline at end of file diff --git a/static/locales/en-US/templates/long_term_objective.txt b/static/locales/en-US/templates/long_term_objective.txt index 1b9874a..1ebd9dd 100644 --- a/static/locales/en-US/templates/long_term_objective.txt +++ b/static/locales/en-US/templates/long_term_objective.txt @@ -21,5 +21,5 @@ Requirements: - The goal should fit the character's status and the Xianxia worldview. - Do not fabricate information that has not appeared. - It can be grand or specific. -- Primarily refer to character traits and personality, while considering sect, alignment, interpersonal relationships, historical events, etc. +- Primarily refer to character traits and personality, while considering sect, alignment, interpersonal relationships, historical events, etc. It can be related to cultivation, interpersonal relationships, personality, pastimes, self-cultivation, sects, or production activities. - "thinking" should provide a detailed analysis; "long_term_objective" should only return the goal content itself, but don't mention how long it will take to complete. diff --git a/static/locales/zh-CN/game_configs/persona.csv b/static/locales/zh-CN/game_configs/persona.csv index b4a4780..de5d000 100644 --- a/static/locales/zh-CN/game_configs/persona.csv +++ b/static/locales/zh-CN/game_configs/persona.csv @@ -71,3 +71,9 @@ id,key,name,exclusion_keys,desc,rarity,condition,effects 69,DEVOTED,专情,LUSTFUL;ROMANTIC;HEARTLESS,你对爱情专一,一旦认定便不会改变。,N,, 70,ROMANTIC,多情,DESIRELESS;HEARTLESS;DEVOTED,你容易动情,对美好的感情充满向往。,N,, 71,HEARTLESS,薄情,DEVOTED;ROMANTIC;FRIENDLY,你对感情淡漠,不会轻易动心。,N,, +1001,PLAYFUL,贪玩,RATIONAL;CULTIVATION_OBSESSED,沉迷玩乐,不思进取。,N,, +1002,BOOKWORM,书痴,RASH,嗜书如命。,R,, +1003,TEA_LOVER,茶痴,,宁可三日无食,不可一日无茶。,R,, +1004,MUSICIAN,琴师,,善抚琴。,R,, +1005,TRAVELER,游历者,HOMEBODY,读万卷书不如行万里路。,R,, +1006,CHESS_PLAYER,棋痴,,善弈者长生。,R,, \ No newline at end of file diff --git a/static/locales/zh-CN/templates/long_term_objective.txt b/static/locales/zh-CN/templates/long_term_objective.txt index 51763d1..bb9b90c 100644 --- a/static/locales/zh-CN/templates/long_term_objective.txt +++ b/static/locales/zh-CN/templates/long_term_objective.txt @@ -21,5 +21,5 @@ - 目标要符合角色身份和修仙世界观 - 不要虚构未出现的信息 - 可以是宏大的也可以是具体的 -- 主要参考角色特质和性格,兼顾宗门、阵营、人际关系、历史事件等 +- 主要参考角色特质和性格,兼顾宗门、阵营、人际关系、历史事件等。可以和修炼相关、也可以和人际关系、性格、消遣、修养、宗门、生产活动相关。 - thinking要详细分析,long_term_objective只返回目标内容本身,但别提多久完成 \ No newline at end of file diff --git a/tests/test_action_play.py b/tests/test_action_play.py new file mode 100644 index 0000000..af8f999 --- /dev/null +++ b/tests/test_action_play.py @@ -0,0 +1,93 @@ +import pytest +from unittest.mock import MagicMock, patch +import asyncio + +from src.classes.action.play import Reading, TeaTasting, Traveling, ZitherPlaying +from src.classes.mutual_action.play import TeaParty, Chess +from src.classes.event import Event +from src.utils.config import CONFIG + +class TestActionPlay: + + @pytest.fixture + def play_avatar(self, dummy_avatar): + """配置一个适合消遣的角色""" + # 确保没有初始临时效果 + dummy_avatar.temporary_effects = [] + return dummy_avatar + + def test_single_play_action_instantiation(self, play_avatar): + """测试单人消遣动作实例化""" + world = play_avatar.world + actions = [Reading, TeaTasting, Traveling, ZitherPlaying] + + for action_cls in actions: + action = action_cls(play_avatar, world) + assert action.duration_months == 1 + assert action.can_start()[0] is True + + @patch('src.classes.action.play.random.random') + def test_single_play_benefit_trigger(self, mock_random, play_avatar): + """测试单人消遣触发收益""" + # mock random < 0.05 to trigger benefit + # CONFIG.play.base_benefit_probability is 0.05 + mock_random.return_value = 0.01 + + action = Reading(play_avatar, play_avatar.world) + + # Execute finish (async) + events = asyncio.run(action.finish()) + + # Check event content + assert len(events) == 1 + # 检查是否包含突破概率提升的描述 (英文或中文,取决于环境,这里假设 conftest 强制了中文) + # conftest.py force_chinese_language fixture sets language to zh-CN + # "breakthrough probability increased by 20.0%" -> zh-CN: "心境提升,突破概率增加 20.0%" + # Let's check for "20.0%" to be safe across languages if translation fails, + # or check the translation key if possible. But here we get the formatted string. + assert "20.0%" in events[0].content + + # Check effect applied + # Need to check if temporary_effects has the entry + assert len(play_avatar.temporary_effects) == 1 + effect = play_avatar.temporary_effects[0] + assert effect["source"] == "play_benefit" + assert effect["effects"]["extra_breakthrough_success_rate"] == 0.2 + assert effect["duration"] == 1 + + @patch('src.classes.action.play.random.random') + def test_single_play_no_benefit(self, mock_random, play_avatar): + """测试单人消遣未触发收益""" + # mock random >= 0.05 + mock_random.return_value = 0.1 + + action = Reading(play_avatar, play_avatar.world) + + events = asyncio.run(action.finish()) + + assert len(events) == 1 + assert "20.0%" not in events[0].content + assert len(play_avatar.temporary_effects) == 0 + + @patch('src.classes.mutual_action.play.random.random') + def test_mutual_play_benefit(self, mock_random, play_avatar): + """测试双人消遣触发收益""" + # Setup target avatar + target_avatar = MagicMock() + target_avatar.name = "Friend" + # MagicMock doesn't have temporary_effects list by default, but add_breakthrough_rate is called on it + + # mock random < 0.05 + mock_random.return_value = 0.01 + + action = TeaParty(play_avatar, play_avatar.world) + + # Simulate feedback "Accept" + action._settle_feedback(target_avatar, "Accept") + + # Check initiator benefit + assert len(play_avatar.temporary_effects) == 1 + assert play_avatar.temporary_effects[0]["effects"]["extra_breakthrough_success_rate"] == 0.2 + + # Check target benefit + target_avatar.add_breakthrough_rate.assert_called_with(0.2) diff --git a/tests/test_ai.py b/tests/test_ai.py index 56734e2..cae88f5 100644 --- a/tests/test_ai.py +++ b/tests/test_ai.py @@ -21,7 +21,7 @@ Testing Strategy: "AvatarName": { "action_name_params_pairs": [["cultivate", {"duration": 10}]], "avatar_thinking": "...", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } results = await ai._decide(world, [avatar]) @@ -67,7 +67,7 @@ class TestLLMAIDecide: ], "avatar_thinking": "I should cultivate to get stronger.", "short_term_objective": "Reach Foundation Establishment", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -96,7 +96,7 @@ class TestLLMAIDecide: ], "avatar_thinking": "Time to rest after cultivation.", "short_term_objective": "Recover energy", - "current_emotion": "疲惫" + "current_emotion": "emotion_tired" } } @@ -124,7 +124,7 @@ class TestLLMAIDecide: ], "avatar_thinking": "Just cultivating.", "short_term_objective": "Get stronger", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -155,7 +155,7 @@ class TestLLMAIDecide: ], "avatar_thinking": "Mixed formats.", "short_term_objective": "Test edge cases", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -201,7 +201,7 @@ class TestLLMAIDecide: "action_name_params_pairs": [["cultivate", {}]], "avatar_thinking": "Should not be used.", "short_term_objective": "Not for test avatar", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -224,7 +224,7 @@ class TestLLMAIDecide: ], "avatar_thinking": "All invalid.", "short_term_objective": "Test", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -258,15 +258,15 @@ class TestLLMAIEmotionUpdate: async def test_decide_updates_emotion_with_valid_value(self, mock_world, test_avatar): """Test that valid emotion string updates avatar.emotion correctly.""" emotions_to_test = [ - ("开心", EmotionType.HAPPY), - ("愤怒", EmotionType.ANGRY), - ("悲伤", EmotionType.SAD), - ("恐惧", EmotionType.FEARFUL), - ("惊讶", EmotionType.SURPRISED), - ("期待", EmotionType.ANTICIPATING), - ("厌恶", EmotionType.DISGUSTED), - ("疑惑", EmotionType.CONFUSED), - ("疲惫", EmotionType.TIRED), + ("emotion_happy", EmotionType.HAPPY), + ("emotion_angry", EmotionType.ANGRY), + ("emotion_sad", EmotionType.SAD), + ("emotion_fearful", EmotionType.FEARFUL), + ("emotion_surprised", EmotionType.SURPRISED), + ("emotion_anticipating", EmotionType.ANTICIPATING), + ("emotion_disgusted", EmotionType.DISGUSTED), + ("emotion_confused", EmotionType.CONFUSED), + ("emotion_tired", EmotionType.TIRED), ] ai = LLMAI() @@ -329,7 +329,7 @@ class TestLLMAIEmotionUpdate: mock_llm.return_value = mock_response await ai._decide(mock_world, [test_avatar]) - # Default is "平静" which maps to CALM. + # Default is "emotion_calm" which maps to CALM. assert test_avatar.emotion == EmotionType.CALM @@ -419,7 +419,7 @@ class TestLLMAIBatchProcessing: "action_name_params_pairs": [["cultivate", {"duration": 10}]], "avatar_thinking": "A is cultivating.", "short_term_objective": "A's goal", - "current_emotion": "开心" + "current_emotion": "emotion_happy" } } else: @@ -428,7 +428,7 @@ class TestLLMAIBatchProcessing: "action_name_params_pairs": [["move", {"target_x": 2, "target_y": 2}]], "avatar_thinking": "B is moving.", "short_term_objective": "B's goal", - "current_emotion": "愤怒" + "current_emotion": "emotion_angry" } } @@ -492,7 +492,7 @@ class TestAIDecideWrapper: "action_name_params_pairs": [["cultivate", {}]], "avatar_thinking": "Testing.", "short_term_objective": "Test", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -539,7 +539,7 @@ class TestLLMAIThinkingFieldVariants: "action_name_params_pairs": [["cultivate", {}]], "thinking": "Using thinking field.", # Not avatar_thinking "short_term_objective": "Test", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -561,7 +561,7 @@ class TestLLMAIThinkingFieldVariants: "avatar_thinking": "Preferred field.", "thinking": "Fallback field.", "short_term_objective": "Test", - "current_emotion": "平静" + "current_emotion": "emotion_calm" } } @@ -581,7 +581,7 @@ class TestLLMAIThinkingFieldVariants: test_avatar.name: { "action_name_params_pairs": [["cultivate", {}]], # No avatar_thinking, thinking, or short_term_objective - "current_emotion": "平静" + "current_emotion": "emotion_calm" } }