add refine action
This commit is contained in:
@@ -37,6 +37,7 @@ from .switch_weapon import SwitchWeapon
|
||||
from .assassinate import Assassinate
|
||||
from .move_to_direction import MoveToDirection
|
||||
from .cast import Cast
|
||||
from .refine import Refine
|
||||
from .buy import Buy
|
||||
from .mine import Mine
|
||||
|
||||
@@ -72,6 +73,7 @@ register_action(actual=True)(SwitchWeapon)
|
||||
register_action(actual=True)(Assassinate)
|
||||
register_action(actual=True)(MoveToDirection)
|
||||
register_action(actual=True)(Cast)
|
||||
register_action(actual=True)(Refine)
|
||||
register_action(actual=True)(Buy)
|
||||
register_action(actual=True)(Mine)
|
||||
# Talk 已移动到 mutual_action 模块,在那里注册
|
||||
@@ -110,6 +112,7 @@ __all__ = [
|
||||
"Assassinate",
|
||||
"MoveToDirection",
|
||||
"Cast",
|
||||
"Refine",
|
||||
"Buy",
|
||||
"Mine",
|
||||
]
|
||||
|
||||
@@ -33,7 +33,7 @@ class Cast(TimedAction):
|
||||
Realm.Nascent_Soul: 0.1,
|
||||
}
|
||||
|
||||
DOABLES_REQUIREMENTS = f"拥有{COST}个同境界矿石材料"
|
||||
DOABLES_REQUIREMENTS = f"拥有{COST}个同境界材料"
|
||||
PARAMS = {"target_realm": "目标境界名称('练气'、'筑基'、'金丹'、'元婴')"}
|
||||
IS_MAJOR = False
|
||||
|
||||
@@ -49,12 +49,12 @@ class Cast(TimedAction):
|
||||
def _count_materials(self, realm: Realm) -> int:
|
||||
"""
|
||||
统计符合条件的材料数量。
|
||||
注意:仅统计 Item 类的直接实例,且必须在 ORE_ITEM_IDS 中。
|
||||
注意:统计所有 Item 类的直接实例,不限于矿石。
|
||||
"""
|
||||
count = 0
|
||||
for item, qty in self.avatar.items.items():
|
||||
# 增加判断:item.id 必须在 ORE_ITEM_IDS 中
|
||||
if type(item).__name__ == "Item" and item.realm == realm and item.id in ORE_ITEM_IDS:
|
||||
# 只要是 Item 实例且境界符合即可
|
||||
if type(item).__name__ == "Item" and item.realm == realm:
|
||||
count += qty
|
||||
return count
|
||||
|
||||
@@ -91,7 +91,7 @@ class Cast(TimedAction):
|
||||
for item, qty in self.avatar.items.items():
|
||||
if to_deduct <= 0:
|
||||
break
|
||||
if type(item).__name__ == "Item" and item.realm == self.target_realm and item.id in ORE_ITEM_IDS:
|
||||
if type(item).__name__ == "Item" and item.realm == self.target_realm:
|
||||
take = min(qty, to_deduct)
|
||||
items_to_modify.append((item, take))
|
||||
to_deduct -= take
|
||||
|
||||
175
src/classes/action/refine.py
Normal file
175
src/classes/action/refine.py
Normal file
@@ -0,0 +1,175 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from typing import Optional, TYPE_CHECKING, List
|
||||
|
||||
from src.classes.action import TimedAction
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.event import Event
|
||||
from src.classes.elixir import get_random_elixir_by_realm
|
||||
from src.classes.single_choice import handle_item_exchange
|
||||
from src.utils.resolution import resolve_query
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.classes.avatar import Avatar
|
||||
|
||||
class Refine(TimedAction):
|
||||
"""
|
||||
炼丹动作:消耗同阶材料,尝试炼制同阶丹药。
|
||||
持续时间:3个月
|
||||
"""
|
||||
ACTION_NAME = "炼丹"
|
||||
EMOJI = "💊"
|
||||
DESC = "消耗材料尝试炼制丹药"
|
||||
|
||||
COST = 3
|
||||
SUCCESS_RATES = {
|
||||
Realm.Qi_Refinement: 0.4,
|
||||
Realm.Foundation_Establishment: 0.3,
|
||||
Realm.Core_Formation: 0.2,
|
||||
Realm.Nascent_Soul: 0.1,
|
||||
}
|
||||
|
||||
DOABLES_REQUIREMENTS = f"拥有{COST}个同境界材料"
|
||||
PARAMS = {"target_realm": "目标境界名称('练气'、'筑基'、'金丹'、'元婴')"}
|
||||
IS_MAJOR = False
|
||||
|
||||
duration_months = 2
|
||||
|
||||
def __init__(self, avatar: Avatar, world):
|
||||
super().__init__(avatar, world)
|
||||
self.target_realm: Optional[Realm] = None
|
||||
|
||||
def _get_cost(self) -> int:
|
||||
return self.COST
|
||||
|
||||
def _count_materials(self, realm: Realm) -> int:
|
||||
"""
|
||||
统计符合条件的材料数量。
|
||||
注意:统计所有 Item 类的直接实例,不限于矿石。
|
||||
"""
|
||||
count = 0
|
||||
for item, qty in self.avatar.items.items():
|
||||
# 只要是 Item 实例且境界符合即可
|
||||
if type(item).__name__ == "Item" and item.realm == realm:
|
||||
count += qty
|
||||
return count
|
||||
|
||||
def can_start(self, target_realm: str) -> tuple[bool, str]:
|
||||
if not target_realm:
|
||||
return False, "未指定目标境界"
|
||||
|
||||
res = resolve_query(target_realm, expected_types=[Realm])
|
||||
if not res.is_valid:
|
||||
return False, f"无效的境界: {target_realm}"
|
||||
|
||||
realm = res.obj
|
||||
|
||||
cost = self._get_cost()
|
||||
count = self._count_materials(realm)
|
||||
|
||||
if count < cost:
|
||||
return False, f"材料不足,需要 {cost} 个{target_realm}阶材料,当前拥有 {count} 个"
|
||||
|
||||
return True, ""
|
||||
|
||||
def start(self, target_realm: str) -> Event:
|
||||
res = resolve_query(target_realm, expected_types=[Realm])
|
||||
if res.is_valid:
|
||||
self.target_realm = res.obj
|
||||
|
||||
cost = self._get_cost()
|
||||
|
||||
# 扣除材料逻辑
|
||||
to_deduct = cost
|
||||
items_to_modify = []
|
||||
|
||||
# 再次遍历寻找材料进行扣除
|
||||
for item, qty in self.avatar.items.items():
|
||||
if to_deduct <= 0:
|
||||
break
|
||||
if type(item).__name__ == "Item" and item.realm == self.target_realm:
|
||||
take = min(qty, to_deduct)
|
||||
items_to_modify.append((item, take))
|
||||
to_deduct -= take
|
||||
|
||||
for item, take in items_to_modify:
|
||||
self.avatar.remove_item(item, take)
|
||||
|
||||
realm_val = self.target_realm.value if self.target_realm else target_realm
|
||||
return Event(
|
||||
self.world.month_stamp,
|
||||
f"{self.avatar.name} 开始尝试炼制{realm_val}阶丹药。",
|
||||
related_avatars=[self.avatar.id]
|
||||
)
|
||||
|
||||
def _execute(self) -> None:
|
||||
# 持续过程中无特殊逻辑
|
||||
pass
|
||||
|
||||
async def finish(self) -> list[Event]:
|
||||
if self.target_realm is None:
|
||||
return []
|
||||
|
||||
# 1. 计算成功率
|
||||
base_rate = self.SUCCESS_RATES.get(self.target_realm, 0.1)
|
||||
# 获取额外成功率(例如来自特质或功法)
|
||||
extra_rate = float(self.avatar.effects.get("extra_refine_success_rate", 0.0))
|
||||
success_rate = base_rate + extra_rate
|
||||
|
||||
events = []
|
||||
|
||||
# 2. 判定结果
|
||||
if random.random() > success_rate:
|
||||
# 失败
|
||||
fail_event = Event(
|
||||
self.world.month_stamp,
|
||||
f"{self.avatar.name} 炼制{self.target_realm.value}阶丹药失败,所有材料化为灰烬。",
|
||||
related_avatars=[self.avatar.id],
|
||||
is_major=False
|
||||
)
|
||||
events.append(fail_event)
|
||||
return events
|
||||
|
||||
# 3. 成功:生成物品
|
||||
new_item = get_random_elixir_by_realm(self.target_realm)
|
||||
if new_item is None:
|
||||
# 理论上不应该发生,除非该境界没有配置丹药
|
||||
fail_event = Event(
|
||||
self.world.month_stamp,
|
||||
f"{self.avatar.name} 炼制成功,但似乎没有产生任何已知的丹药。",
|
||||
related_avatars=[self.avatar.id],
|
||||
is_major=False
|
||||
)
|
||||
events.append(fail_event)
|
||||
return events
|
||||
|
||||
# 4. 决策:保留还是卖出
|
||||
base_desc = f"炼丹成功!获得了{self.target_realm.value}丹药『{new_item.name}』。"
|
||||
|
||||
# 事件1:炼丹成功
|
||||
events.append(Event(
|
||||
self.world.month_stamp,
|
||||
f"{self.avatar.name} 成功炼制{self.target_realm.value}丹药『{new_item.name}』。",
|
||||
related_avatars=[self.avatar.id],
|
||||
is_major=True
|
||||
))
|
||||
|
||||
_, result_text = await handle_item_exchange(
|
||||
avatar=self.avatar,
|
||||
new_item=new_item,
|
||||
item_type="elixir",
|
||||
context_intro=base_desc,
|
||||
can_sell_new=True
|
||||
)
|
||||
|
||||
# 事件2:处置结果
|
||||
events.append(Event(
|
||||
self.world.month_stamp,
|
||||
result_text,
|
||||
related_avatars=[self.avatar.id],
|
||||
is_major=True
|
||||
))
|
||||
|
||||
return events
|
||||
|
||||
@@ -16,6 +16,7 @@ from .consts import (
|
||||
EXTRA_FORTUNE_PROBABILITY,
|
||||
EXTRA_MISFORTUNE_PROBABILITY,
|
||||
EXTRA_CAST_SUCCESS_RATE,
|
||||
EXTRA_REFINE_SUCCESS_RATE,
|
||||
EXTRA_WEAPON_PROFICIENCY_GAIN,
|
||||
EXTRA_WEAPON_UPGRADE_CHANCE,
|
||||
EXTRA_MAX_LIFESPAN,
|
||||
|
||||
@@ -219,6 +219,18 @@ EXTRA_CAST_SUCCESS_RATE = "extra_cast_success_rate"
|
||||
- 大量: 0.2+ (+20%)
|
||||
"""
|
||||
|
||||
EXTRA_REFINE_SUCCESS_RATE = "extra_refine_success_rate"
|
||||
"""
|
||||
额外炼丹成功率
|
||||
类型: float
|
||||
结算: src/classes/action/refine.py
|
||||
说明: 炼丹(Refine)动作的成功率加成。
|
||||
数值参考:
|
||||
- 微量: 0.05 (+5%)
|
||||
- 中量: 0.1 (+10%)
|
||||
- 大量: 0.2+ (+20%)
|
||||
"""
|
||||
|
||||
# --- 兵器相关 ---
|
||||
EXTRA_WEAPON_PROFICIENCY_GAIN = "extra_weapon_proficiency_gain"
|
||||
"""
|
||||
@@ -430,6 +442,7 @@ ALL_EFFECTS = [
|
||||
|
||||
# 铸造相关
|
||||
"extra_cast_success_rate", # float - 额外铸造成功率
|
||||
"extra_refine_success_rate", # float - 额外炼丹成功率
|
||||
|
||||
# 兵器相关
|
||||
"extra_weapon_proficiency_gain", # float - 额外兵器熟练度增长倍率
|
||||
|
||||
@@ -28,6 +28,7 @@ EFFECT_DESC_MAP = {
|
||||
"realm_suppression_bonus": "境界压制",
|
||||
"cultivate_duration_reduction": "修炼时长缩减",
|
||||
"extra_cast_success_rate": "铸造成功率",
|
||||
"extra_refine_success_rate": "炼丹成功率",
|
||||
}
|
||||
|
||||
ACTION_DESC_MAP = {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import copy
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Union
|
||||
from typing import Dict, List, Union, Optional
|
||||
|
||||
from src.utils.df import game_configs, get_str, get_int
|
||||
from src.classes.effect import load_effect_from_str, format_effects_to_text
|
||||
@@ -188,4 +190,10 @@ elixirs_by_id, elixirs_by_name = _load_elixirs()
|
||||
|
||||
def get_elixirs_by_realm(realm: Realm) -> List[Elixir]:
|
||||
"""获取指定境界的所有丹药"""
|
||||
return [e for e in elixirs_by_id.values() if e.realm == realm]
|
||||
return [e for e in elixirs_by_id.values() if e.realm == realm]
|
||||
|
||||
|
||||
def get_random_elixir_by_realm(realm: Realm) -> Optional[Elixir]:
|
||||
"""获取指定境界的随机丹药"""
|
||||
candidates = get_elixirs_by_realm(realm)
|
||||
return copy.deepcopy(random.choice(candidates))
|
||||
|
||||
Reference in New Issue
Block a user