add more fortunes
This commit is contained in:
@@ -27,6 +27,8 @@ class FortuneKind(Enum):
|
||||
TREASURE = "treasure"
|
||||
TECHNIQUE = "technique"
|
||||
FIND_MASTER = "find_master"
|
||||
SPIRIT_STONE = "spirit_stone" # 灵石奇遇
|
||||
CULTIVATION = "cultivation" # 修为奇遇
|
||||
|
||||
|
||||
F_TREASURE_THEMES: list[str] = [
|
||||
@@ -53,6 +55,25 @@ F_FIND_MASTER_THEMES: list[str] = [
|
||||
"通过考验",
|
||||
]
|
||||
|
||||
F_SPIRIT_STONE_THEMES: list[str] = [
|
||||
"偶遇灵矿",
|
||||
"洞府遗财",
|
||||
"击杀妖兽",
|
||||
"交易获利",
|
||||
"赌石得宝",
|
||||
"拾遗藏宝",
|
||||
]
|
||||
|
||||
F_CULTIVATION_THEMES: list[str] = [
|
||||
"顿悟玄机",
|
||||
"古碑感悟",
|
||||
"服食灵药",
|
||||
"秘境修炼",
|
||||
"前辈灌顶",
|
||||
"灵泉淬体",
|
||||
"传承记忆",
|
||||
]
|
||||
|
||||
|
||||
def _has_master(avatar: Avatar) -> bool:
|
||||
"""检查是否已有师傅"""
|
||||
@@ -139,6 +160,18 @@ def _can_get_master(avatar: Avatar) -> bool:
|
||||
return _find_potential_master(avatar) is not None
|
||||
|
||||
|
||||
def _can_get_spirit_stone(avatar: Avatar) -> bool:
|
||||
"""检查是否可以获得灵石奇遇"""
|
||||
# 任何人都可以获得灵石
|
||||
return True
|
||||
|
||||
|
||||
def _can_get_cultivation(avatar: Avatar) -> bool:
|
||||
"""检查是否可以获得修为奇遇"""
|
||||
# 只有未达到瓶颈的人才能获得修为
|
||||
return not avatar.cultivation_progress.is_in_bottleneck()
|
||||
|
||||
|
||||
def _choose_kind(avatar: Avatar) -> FortuneKind:
|
||||
"""
|
||||
从所有可能的奇遇中随机选择一个。
|
||||
@@ -158,6 +191,14 @@ def _choose_kind(avatar: Avatar) -> FortuneKind:
|
||||
if _can_get_master(avatar):
|
||||
possible_kinds.append(FortuneKind.FIND_MASTER)
|
||||
|
||||
# 灵石奇遇:任何人都可以
|
||||
if _can_get_spirit_stone(avatar):
|
||||
possible_kinds.append(FortuneKind.SPIRIT_STONE)
|
||||
|
||||
# 修为奇遇:未达到瓶颈的人可以
|
||||
if _can_get_cultivation(avatar):
|
||||
possible_kinds.append(FortuneKind.CULTIVATION)
|
||||
|
||||
if not possible_kinds:
|
||||
return None
|
||||
|
||||
@@ -171,6 +212,10 @@ def _pick_theme(kind: FortuneKind) -> str:
|
||||
return random.choice(F_TECHNIQUE_THEMES)
|
||||
elif kind == FortuneKind.FIND_MASTER:
|
||||
return random.choice(F_FIND_MASTER_THEMES)
|
||||
elif kind == FortuneKind.SPIRIT_STONE:
|
||||
return random.choice(F_SPIRIT_STONE_THEMES)
|
||||
elif kind == FortuneKind.CULTIVATION:
|
||||
return random.choice(F_CULTIVATION_THEMES)
|
||||
return ""
|
||||
|
||||
|
||||
@@ -235,6 +280,39 @@ def _get_fortune_technique_for_avatar(avatar: Avatar) -> Optional[Technique]:
|
||||
return random.choices(candidates, weights=weights, k=1)[0]
|
||||
|
||||
|
||||
def _get_spirit_stone_amount(avatar: Avatar) -> int:
|
||||
"""根据境界返回灵石数量(相当于一年狩猎售卖的收入)"""
|
||||
from src.classes.cultivation import Realm
|
||||
|
||||
realm_ranges = {
|
||||
Realm.Qi_Refinement: (20, 30),
|
||||
Realm.Foundation_Establishment: (100, 150),
|
||||
Realm.Core_Formation: (200, 300),
|
||||
Realm.Nascent_Soul: (400, 600),
|
||||
}
|
||||
range_tuple = realm_ranges.get(
|
||||
avatar.cultivation_progress.realm,
|
||||
(20, 30) # 默认值
|
||||
)
|
||||
return random.randint(*range_tuple)
|
||||
|
||||
|
||||
def _get_cultivation_exp(avatar: Avatar) -> int:
|
||||
"""根据境界返回修为经验(相当于一年修炼的收益)"""
|
||||
from src.classes.cultivation import Realm
|
||||
|
||||
realm_exp = {
|
||||
Realm.Qi_Refinement: 600,
|
||||
Realm.Foundation_Establishment: 800,
|
||||
Realm.Core_Formation: 1000,
|
||||
Realm.Nascent_Soul: 1200,
|
||||
}
|
||||
return realm_exp.get(
|
||||
avatar.cultivation_progress.realm,
|
||||
600 # 默认值
|
||||
)
|
||||
|
||||
|
||||
async def try_trigger_fortune(avatar: Avatar) -> list[Event]:
|
||||
"""
|
||||
在月度结算阶段尝试触发奇遇。
|
||||
@@ -244,10 +322,14 @@ async def try_trigger_fortune(avatar: Avatar) -> list[Event]:
|
||||
* 法宝奇遇:无法宝(不限散修/宗门)
|
||||
* 功法奇遇:功法非上品(不限散修/宗门,但宗门弟子只能获得本宗门或无宗门功法)
|
||||
* 拜师奇遇:无师傅且世界中有合适的师傅(优先同宗门,不能拜敌对阵营)
|
||||
* 灵石奇遇:任何人都可以触发
|
||||
* 修为奇遇:未达到瓶颈的人可以触发
|
||||
- 结果:
|
||||
* 法宝:世界唯一且不可重复
|
||||
* 功法:可重复,优先上品,需与灵根兼容,宗门弟子受宗门限制
|
||||
* 拜师:建立师徒关系
|
||||
* 灵石:根据境界获得灵石(相当于一年狩猎售卖收入)
|
||||
* 修为:根据境界增加修为经验(相当于一年修炼收益)
|
||||
- 故事:仅给出主旨主题,由 LLM 自由发挥生成短故事。
|
||||
"""
|
||||
base_prob = float(getattr(CONFIG.game, "fortune_probability", 0.0))
|
||||
@@ -298,6 +380,16 @@ async def try_trigger_fortune(avatar: Avatar) -> list[Event]:
|
||||
related_avatars.append(master.id)
|
||||
actors_for_story = [avatar, master] # 拜师奇遇需要两个人的信息
|
||||
|
||||
elif kind == FortuneKind.SPIRIT_STONE:
|
||||
amount = _get_spirit_stone_amount(avatar)
|
||||
avatar.magic_stone.value += amount
|
||||
res_text = f"{avatar.name} 获得灵石 {amount} 枚"
|
||||
|
||||
elif kind == FortuneKind.CULTIVATION:
|
||||
exp_gain = _get_cultivation_exp(avatar)
|
||||
avatar.cultivation_progress.add_exp(exp_gain)
|
||||
res_text = f"{avatar.name} 修为增长 {exp_gain} 点"
|
||||
|
||||
# 生成故事(异步,等待完成)
|
||||
event_text = f"遭遇奇遇({theme}),{res_text}"
|
||||
story_prompt = "请据此写100~150字小故事。"
|
||||
|
||||
@@ -7,6 +7,7 @@ from .conversation import Conversation
|
||||
from .dual_cultivation import DualCultivation
|
||||
from .talk import Talk
|
||||
from .impart import Impart
|
||||
from .gift_spirit_stone import GiftSpiritStone
|
||||
from src.classes.action.registry import register_action
|
||||
|
||||
__all__ = [
|
||||
@@ -17,6 +18,7 @@ __all__ = [
|
||||
"DualCultivation",
|
||||
"Talk",
|
||||
"Impart",
|
||||
"GiftSpiritStone",
|
||||
]
|
||||
|
||||
# 注册 mutual actions(均为实际动作)
|
||||
@@ -26,5 +28,6 @@ register_action(actual=True)(Conversation)
|
||||
register_action(actual=True)(DualCultivation)
|
||||
register_action(actual=True)(Talk)
|
||||
register_action(actual=True)(Impart)
|
||||
register_action(actual=True)(GiftSpiritStone)
|
||||
|
||||
|
||||
|
||||
124
src/classes/mutual_action/gift_spirit_stone.py
Normal file
124
src/classes/mutual_action/gift_spirit_stone.py
Normal file
@@ -0,0 +1,124 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .mutual_action import MutualAction
|
||||
from src.classes.event import Event
|
||||
from src.utils.config import CONFIG
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.classes.avatar import Avatar
|
||||
|
||||
|
||||
class GiftSpiritStone(MutualAction):
|
||||
"""赠送灵石:向目标赠送灵石。
|
||||
|
||||
- 发起方灵石必须足够(至少100灵石)
|
||||
- 目标在交互范围内
|
||||
- 目标可以选择 接受 或 拒绝
|
||||
- 若接受:发起方扣除100灵石,目标获得100灵石
|
||||
"""
|
||||
|
||||
ACTION_NAME = "赠送灵石"
|
||||
COMMENT = "向对方赠送灵石,一次赠送100灵石"
|
||||
DOABLES_REQUIREMENTS = "发起者至少有100灵石;目标在交互范围内"
|
||||
PARAMS = {"target_avatar": "AvatarName"}
|
||||
FEEDBACK_ACTIONS = ["Accept", "Reject"]
|
||||
STORY_PROMPT: str | None = "描绘一段赠送灵石的场景,体现赠送者的慷慨和接受者的反应。80~120字。"
|
||||
|
||||
# 默认赠送数量
|
||||
GIFT_AMOUNT = 100
|
||||
|
||||
def _get_template_path(self) -> Path:
|
||||
return CONFIG.paths.templates / "mutual_action.txt"
|
||||
|
||||
def _can_start(self, target: "Avatar") -> tuple[bool, str]:
|
||||
"""检查赠送灵石的启动条件"""
|
||||
# 检查发起者的灵石是否足够
|
||||
if self.avatar.magic_stone < self.GIFT_AMOUNT:
|
||||
return False, f"灵石不足(当前:{self.avatar.magic_stone},需要:{self.GIFT_AMOUNT})"
|
||||
|
||||
return True, ""
|
||||
|
||||
def start(self, target_avatar: "Avatar|str") -> Event:
|
||||
target = self._get_target_avatar(target_avatar)
|
||||
target_name = target.name if target is not None else str(target_avatar)
|
||||
rel_ids = [self.avatar.id]
|
||||
if target is not None:
|
||||
rel_ids.append(target.id)
|
||||
event = Event(
|
||||
self.world.month_stamp,
|
||||
f"{self.avatar.name} 向 {target_name} 赠送 {self.GIFT_AMOUNT} 灵石",
|
||||
related_avatars=rel_ids
|
||||
)
|
||||
# 仅写入历史
|
||||
self.avatar.add_event(event, to_sidebar=False)
|
||||
if target is not None:
|
||||
target.add_event(event, to_sidebar=False)
|
||||
# 记录开始文本用于故事生成
|
||||
self._start_event_content = event.content
|
||||
# 初始化内部标记
|
||||
self._gift_success = False
|
||||
return event
|
||||
|
||||
def _settle_feedback(self, target_avatar: "Avatar", feedback_name: str) -> None:
|
||||
fb = str(feedback_name).strip()
|
||||
if fb == "Accept":
|
||||
# 接受则当场结算灵石转移
|
||||
self._apply_gift(target_avatar)
|
||||
self._gift_success = True
|
||||
else:
|
||||
# 拒绝
|
||||
self._gift_success = False
|
||||
|
||||
def _apply_gift(self, target: "Avatar") -> None:
|
||||
"""执行灵石转移"""
|
||||
# 从发起者扣除灵石
|
||||
self.avatar.magic_stone -= self.GIFT_AMOUNT
|
||||
# 目标获得灵石
|
||||
target.magic_stone += self.GIFT_AMOUNT
|
||||
|
||||
def finish(self, target_avatar: "Avatar|str") -> list[Event]:
|
||||
target = self._get_target_avatar(target_avatar)
|
||||
events: list[Event] = []
|
||||
success = self._gift_success
|
||||
if target is None:
|
||||
return events
|
||||
|
||||
if success:
|
||||
result_text = f"{self.avatar.name} 赠送了 {self.GIFT_AMOUNT} 灵石给 {target.name}({self.avatar.name} 灵石:{self.avatar.magic_stone + self.GIFT_AMOUNT} → {self.avatar.magic_stone},{target.name} 灵石:{target.magic_stone - self.GIFT_AMOUNT} → {target.magic_stone})"
|
||||
result_event = Event(
|
||||
self.world.month_stamp,
|
||||
result_text,
|
||||
related_avatars=[self.avatar.id, target.id]
|
||||
)
|
||||
events.append(result_event)
|
||||
|
||||
# 生成赠送小故事
|
||||
from src.classes.story_teller import StoryTeller
|
||||
start_text = self._start_event_content or result_event.content
|
||||
story = StoryTeller.tell_from_actors(
|
||||
start_text,
|
||||
result_text,
|
||||
self.avatar,
|
||||
target,
|
||||
prompt=self.STORY_PROMPT
|
||||
)
|
||||
story_event = Event(
|
||||
self.world.month_stamp,
|
||||
story,
|
||||
related_avatars=[self.avatar.id, target.id]
|
||||
)
|
||||
events.append(story_event)
|
||||
else:
|
||||
result_text = f"{target.name} 婉拒了 {self.avatar.name} 的灵石赠送"
|
||||
result_event = Event(
|
||||
self.world.month_stamp,
|
||||
result_text,
|
||||
related_avatars=[self.avatar.id, target.id]
|
||||
)
|
||||
events.append(result_event)
|
||||
|
||||
return events
|
||||
|
||||
Reference in New Issue
Block a user