Files
NewWPSBot/Plugins/WPSCombatSystem/combat_plugin_adventure.py
2025-11-12 16:37:10 +08:00

341 lines
13 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""冒险系统插件 - PVE冒险模式"""
from __future__ import annotations
from datetime import datetime
from typing import Optional
from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig
from .combat_plugin_base import WPSCombatBase
logger: ProjectConfig = ProjectConfig()
class WPSCombatAdventure(WPSCombatBase):
"""冒险系统插件"""
def is_enable_plugin(self) -> bool:
return True
def wake_up(self) -> None:
super().wake_up()
logger.Log(
"Info",
f"{ConsoleFrontColor.GREEN}WPSCombatAdventure 插件已加载{ConsoleFrontColor.RESET}"
)
self.register_plugin("冒险")
self.register_plugin("adventure")
self.register_plugin("继续冒险")
# 恢复过期冒险
service = self.service()
service.recover_overdue_adventures()
async def callback(self, message: str, chat_id: int, user_id: int) -> Optional[str]:
"""
处理冒险命令
命令格式:
- 冒险 开始 [食物1] [食物2] ...
- 继续冒险 [食物1] [食物2] ...
"""
message = self.parse_message_after_at(message).strip()
tokens = message.split()
if not tokens:
# 默认视为继续冒险,支持直接命令 `继续冒险`
return await self._handle_continue_adventure(chat_id, user_id, [])
# 判断是开始新冒险、继续或结束
command = tokens[0].lower()
if command in ["放弃", "停止"]:
return await self._handle_finish_adventure(chat_id, user_id)
if command in ["开始", "start"]:
# 开始新冒险第1阶段
food_items = tokens[1:] if len(tokens) > 1 else []
return await self._handle_start_adventure(chat_id, user_id, food_items)
elif command in ["继续", "continue"]:
food_items = tokens[1:] if len(tokens) > 1 else []
return await self._handle_continue_adventure(chat_id, user_id, food_items)
else:
# 默认视为继续冒险tokens 即为食物列表
food_items = tokens
return await self._handle_continue_adventure(chat_id, user_id, food_items)
async def _handle_start_adventure(
self,
chat_id: int,
user_id: int,
food_items: list
) -> Optional[str]:
"""处理开始新冒险"""
service = self.service()
# 第1阶段
stage = 1
success, msg, adventure_id = service.start_adventure(
user_id=user_id,
chat_id=chat_id,
stage=stage,
food_items=food_items,
register_callback=self
)
return await self.send_markdown_message(msg, chat_id, user_id)
async def _handle_finish_adventure(
self,
chat_id: int,
user_id: int
) -> Optional[str]:
"""处理结束冒险(不再继续)"""
service = self.service()
status = service.get_player_status(user_id)
if status.get("current_adventure_id"):
_success, msg = service.abort_current_adventure(user_id)
return await self.send_markdown_message(msg, chat_id, user_id)
last_record = service.get_last_adventure_record(user_id)
if not last_record:
return await self.send_markdown_message(
" 你尚未开始冒险,可使用 `冒险 开始`。",
chat_id,
user_id
)
record_status = last_record["status"]
stage = last_record["stage"]
if record_status == "success":
return await self.send_markdown_message(
(
f"✅ 第 {stage} 阶段冒险已完成并发放奖励。\n"
"若不再继续,冒险链已自然结束;未来可随时使用 `冒险 开始` 重新开启。"
),
chat_id,
user_id
)
if record_status == "failed":
return await self.send_markdown_message(
"❌ 最近一次冒险失败,奖励已结算且需要治疗或重新开始。",
chat_id,
user_id
)
if record_status == "abandoned":
return await self.send_markdown_message(
" 上一次冒险已放弃,无需额外操作。如需重新开启,请使用 `冒险 开始`。",
chat_id,
user_id
)
return await self.send_markdown_message(
f" 最近一次冒险状态为 {record_status},无需执行放弃指令。",
chat_id,
user_id
)
async def _handle_continue_adventure(
self,
chat_id: int,
user_id: int,
food_items: list
) -> Optional[str]:
"""处理继续冒险"""
service = self.service()
# 获取当前冒险状态
status = service.get_player_status(user_id)
current_adventure_id = status.get("current_adventure_id")
if current_adventure_id:
adventure = service.get_adventure_by_id(current_adventure_id)
if not adventure:
return await self.send_markdown_message(
(
"❌ 你已经在冒险中,但未找到相关记录,请稍后重试或联系管理员。"
f"\n- 冒险ID{current_adventure_id}"
),
chat_id,
user_id
)
expected_end_str = adventure.get("expected_end_time")
try:
expected_end = datetime.fromisoformat(expected_end_str) if expected_end_str else None
except (TypeError, ValueError):
expected_end = None
if expected_end:
remaining_seconds = (expected_end - datetime.now()).total_seconds()
if remaining_seconds <= 0:
message = [
"⏳ 当前冒险已进入结算,请稍候等待系统发放结果。",
f"- 冒险ID{current_adventure_id}",
f"- 预计完成:{expected_end.strftime('%Y-%m-%d %H:%M')}"
]
else:
remaining_minutes = int((remaining_seconds + 59) // 60)
remaining_text = (
"不到 1 分钟" if remaining_minutes == 0 else f"{remaining_minutes} 分钟"
)
message = [
"⏳ 你已经在冒险中,请等待当前冒险完成。",
f"- 冒险ID{current_adventure_id}",
f"- 剩余时间:{remaining_text}",
f"- 预计完成:{expected_end.strftime('%Y-%m-%d %H:%M')}"
]
else:
message = [
"❌ 你已经在冒险中,但无法解析预计结束时间,请稍后重试。",
f"- 冒险ID{current_adventure_id}"
]
return await self.send_markdown_message("\n".join(message), chat_id, user_id)
last_record = service.get_last_adventure_record(user_id)
if not last_record:
return await self.send_markdown_message(
"❌ 你还没有完成任何冒险,请使用 `冒险 开始 [食物...]` 开始第1阶段",
chat_id,
user_id
)
if last_record["status"] == "failed":
return await self.send_markdown_message(
"❌ 最近一次冒险失败,冒险已结束。请先使用 `冒险 开始 [食物...]` 重新从第1阶段开始",
chat_id,
user_id
)
if last_record["status"] == "abandoned":
return await self.send_markdown_message(
"⚠️ 最近一次冒险已被你放弃需要重新从第1阶段开始",
chat_id,
user_id
)
if last_record["status"] != "success":
return await self.send_markdown_message(
f"❌ 最近一次冒险状态为 {last_record['status']},无法继续。请使用 `冒险 开始 [食物...]` 重新冒险",
chat_id,
user_id
)
# 下一阶段
next_stage = last_record["stage"] + 1
success, msg, adventure_id = service.start_adventure(
user_id=user_id,
chat_id=chat_id,
stage=next_stage,
food_items=food_items,
register_callback=self
)
return await self.send_markdown_message(msg, chat_id, user_id)
async def _settle_adventure_callback(
self,
adventure_id: int,
user_id: int,
chat_id: int
) -> None:
"""冒险结算回调(时钟任务)"""
service = self.service()
success, msg, rewards = service.settle_adventure(adventure_id)
# 发送结算消息
await self.send_markdown_message(msg, chat_id, user_id)
def _help_message(self) -> str:
"""帮助信息"""
return """# 🗺️ 冒险系统
**命令格式:**
- `冒险 开始 [食物1] [食物2] ...`开始第1阶段冒险
- `继续冒险 [食物1] [食物2] ...` 或 `冒险 继续 ...`:继续下一阶段
- `冒险 放弃`:结束当前冒险链(阶段奖励已结算)
- `停止冒险` / `放弃冒险`:在冒险进行中立即终止当前阶段(无奖励)
**说明:**
- 每个阶段耗时翻倍15min → 30min → 60min...
- 食物果酒是可选的可提供buff加成时间缩减、收益提升等
- 阶段结束时立即判定成功/失败并发放奖励
- 完成后可选择继续下一阶段或直接放弃
- 冒险失败会受伤需要消耗100积分治疗
**示例:**
- `冒险 开始`不使用食物开始第1阶段
- `冒险 开始 薄荷果酒`使用1个薄荷果酒时间缩减10%
- `继续冒险 银杏果酒`:继续下一阶段并使用银杏果酒
- `冒险 放弃`:冒险阶段已结算但不再继续
"""
class WPSCombatAdventureAbort(WPSCombatBase):
"""冒险放弃指令插件"""
def is_enable_plugin(self) -> bool:
return True
def wake_up(self) -> None:
super().wake_up()
logger.Log(
"Info",
f"{ConsoleFrontColor.GREEN}WPSCombatAdventureAbort 插件已加载{ConsoleFrontColor.RESET}"
)
self.register_plugin("停止冒险")
self.register_plugin("放弃冒险")
self.register_plugin("abort_adventure")
async def callback(self, message: str, chat_id: int, user_id: int) -> Optional[str]:
"""直接放弃当前冒险"""
service = self.service()
status = service.get_player_status(user_id)
if status.get("current_adventure_id"):
_success, msg = service.abort_current_adventure(user_id)
return await self.send_markdown_message(msg, chat_id, user_id)
last_record = service.get_last_adventure_record(user_id)
if not last_record:
return await self.send_markdown_message(
" 你尚未开始冒险,可使用 `冒险 开始`。",
chat_id,
user_id
)
record_status = last_record["status"]
stage = last_record["stage"]
if record_status == "success":
return await self.send_markdown_message(
(
f"✅ 第 {stage} 阶段冒险已完成并发放奖励。\n"
"若不再继续,冒险链已自然结束;未来可随时使用 `冒险 开始` 重新开启。"
),
chat_id,
user_id
)
if record_status == "failed":
return await self.send_markdown_message(
"❌ 最近一次冒险失败,奖励已结算且需要治疗或重新开始。",
chat_id,
user_id
)
if record_status == "abandoned":
return await self.send_markdown_message(
" 上一次冒险已放弃,无需额外操作。如需重新开启,请使用 `冒险 开始`。",
chat_id,
user_id
)
return await self.send_markdown_message(
f" 最近一次冒险状态为 {record_status},无需执行放弃指令。",
chat_id,
user_id
)
__all__ = ["WPSCombatAdventure", "WPSCombatAdventureAbort"]