Files
NewWPSBot/Plugins/WPSGardenSystem/garden_plugin_base.py

279 lines
9.8 KiB
Python
Raw Normal View History

2025-11-10 01:15:17 +08:00
"""Shared base class for garden plugins."""
from __future__ import annotations
import json
from typing import List, Optional, Type
from PWF.Convention.Runtime.Architecture import Architecture
from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig
from PWF.CoreModules.plugin_interface import DatabaseModel
from Plugins.WPSAPI import WPSAPI
from Plugins.WPSBackpackSystem import (
BackpackItemTier,
WPSBackpackSystem,
)
from Plugins.WPSStoreSystem import WPSStoreSystem
from Plugins.WPSConfigSystem import WPSConfigAPI
from Plugins.WPSFortuneSystem import WPSFortuneSystem
from Plugins.WPSAlchemyGame import WPSAlchemyGame
from .garden_models import (
GARDEN_CROPS,
GARDEN_FRUITS,
GARDEN_MISC_ITEMS,
GardenCropDefinition,
get_garden_db_models,
)
from .garden_service import GardenService
class WPSGardenBase(WPSAPI):
_service: GardenService | None = None
_initialized: bool = False
@classmethod
def service(cls) -> GardenService:
if cls._service is None:
cls._service = GardenService()
cls._service.recover_overdue_plots()
return cls._service
def dependencies(self) -> List[Type]:
return [
WPSConfigAPI,
WPSBackpackSystem,
WPSStoreSystem,
WPSFortuneSystem,
WPSAlchemyGame,
]
def register_db_model(self) -> List[DatabaseModel]:
return get_garden_db_models()
def wake_up(self) -> None:
if WPSGardenBase._initialized:
return
WPSGardenBase._initialized = True
logger: ProjectConfig = Architecture.Get(ProjectConfig)
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
store: WPSStoreSystem = Architecture.Get(WPSStoreSystem)
alchemy: WPSAlchemyGame = Architecture.Get(WPSAlchemyGame)
service = self.service()
for crop in GARDEN_CROPS.values():
seed_name = f"{crop.display_name}的种子"
fruit_name = f"{crop.display_name}的果实"
# 支持所有tier等级common, rare, epic, legendary
tier_map = {
"common": BackpackItemTier.COMMON,
"rare": BackpackItemTier.RARE,
"epic": BackpackItemTier.EPIC,
"legendary": BackpackItemTier.LEGENDARY,
}
tier = tier_map.get(crop.tier.lower(), BackpackItemTier.RARE)
2025-11-10 22:30:16 +08:00
seed_desc = f"{crop.display_name}的种子,可在菜园种植获取相应作物。"
fruit_desc = f"{crop.display_name}成熟后的果实,可食用或售出换取积分。"
self._safe_register_item(backpack, crop.seed_id, seed_name, tier, seed_desc)
self._safe_register_item(backpack, crop.fruit_id, fruit_name, tier, fruit_desc)
2025-11-10 01:15:17 +08:00
if crop.extra_reward and crop.extra_reward.kind == "item" and crop.extra_item_id:
wood_name = f"{crop.display_name}的木材"
2025-11-10 22:30:16 +08:00
wood_desc = f"{crop.display_name}加工所得的木材,可用于特定任务或制作。"
self._safe_register_item(
backpack,
crop.extra_item_id,
wood_name,
BackpackItemTier.RARE,
2025-11-10 22:30:16 +08:00
wood_desc,
)
if crop.wine_item_id and crop.wine_tier:
wine_tier = getattr(BackpackItemTier, crop.wine_tier.upper(), BackpackItemTier.RARE)
wine_name = f"{crop.display_name}的果酒"
2025-11-10 22:30:16 +08:00
wine_desc = f"{crop.display_name}酿制的果酒,饮用后可触发战斗增益。"
self._safe_register_item(
backpack,
crop.wine_item_id,
wine_name,
wine_tier,
2025-11-10 22:30:16 +08:00
wine_desc,
)
2025-11-10 01:15:17 +08:00
self._safe_register_mode(
store,
crop,
limit_amount=service.config.seed_store_limit,
)
if crop.wine_item_id and crop.wine_tier:
wine_price = crop.seed_price * service.config.sale_multiplier * 5
self._safe_register_wine_mode(
store,
crop.wine_item_id,
wine_price,
limit_amount=service.config.seed_store_limit,
)
2025-11-10 01:15:17 +08:00
self._safe_register_recipe(alchemy, crop)
for item_id, meta in GARDEN_MISC_ITEMS.items():
self._safe_register_item(
backpack,
item_id,
meta["name"],
BackpackItemTier.COMMON,
2025-11-10 22:30:16 +08:00
meta.get("description", ""),
2025-11-10 01:15:17 +08:00
)
logger.Log(
"Info",
f"{ConsoleFrontColor.GREEN}WPSGarden 系统完成物品与商店初始化{ConsoleFrontColor.RESET}",
)
# region Helpers
def _safe_register_item(
self,
backpack: WPSBackpackSystem,
item_id: str,
name: str,
tier: BackpackItemTier,
2025-11-10 22:30:16 +08:00
description: str,
2025-11-10 01:15:17 +08:00
) -> None:
try:
2025-11-10 22:30:16 +08:00
backpack.register_item(item_id, name, tier, description)
2025-11-10 01:15:17 +08:00
except Exception:
pass
def _safe_register_mode(
self,
store: WPSStoreSystem,
crop: GardenCropDefinition,
*,
limit_amount: int,
) -> None:
try:
store.register_mode(
item_id=crop.seed_id,
price=crop.seed_price,
limit_amount=limit_amount,
)
except Exception:
pass
def _safe_register_wine_mode(
self,
store: WPSStoreSystem,
item_id: str,
price: int,
*,
limit_amount: int,
) -> None:
try:
store.register_mode(
item_id=item_id,
price=price,
limit_amount=limit_amount,
)
except Exception:
pass
2025-11-10 01:15:17 +08:00
def _safe_register_recipe(
self,
alchemy: WPSAlchemyGame,
crop: GardenCropDefinition,
) -> None:
try:
if not crop.wine_item_id:
return
success_rate = 0.75
2025-11-10 01:15:17 +08:00
alchemy.register_recipe(
(crop.fruit_id, crop.fruit_id, crop.fruit_id),
crop.wine_item_id,
2025-11-10 01:15:17 +08:00
"garden_item_rot_fruit",
success_rate,
)
except Exception:
pass
async def _clock_mark_mature(self, user_id: int, chat_id: int, plot_index: int) -> None:
service = self.service()
plot = service.get_plot(user_id, plot_index)
if not plot:
return
if int(plot["is_mature"]) == 1:
return
service.mark_mature(user_id, plot_index)
crop = GARDEN_CROPS.get(plot["seed_id"])
if crop is None:
return
message = (
"# 🌾 作物成熟提醒\n"
f"- 地块 {plot_index}{crop.display_name} 已成熟,记得收获!"
)
await self.send_markdown_message(message, chat_id, user_id)
def _format_timestamp(self, ts: str) -> str:
return self.service().format_display_time(ts)
def resolve_seed_id(self, keyword: str) -> Optional[GardenCropDefinition]:
key = keyword.strip().lower()
for crop in GARDEN_CROPS.values():
if crop.seed_id.lower() == key:
return crop
if crop.display_name.lower() == key:
return crop
if f"{crop.display_name}的种子".lower() == key:
return crop
return None
def resolve_fruit_id(self, keyword: str) -> Optional[GardenCropDefinition]:
key = keyword.strip().lower()
for crop in GARDEN_FRUITS.values():
if crop.fruit_id.lower() == key:
return crop
if crop.display_name.lower() == key:
return crop
if f"{crop.display_name}的果实".lower() == key:
return crop
return None
def format_garden_overview(self, user_id: int) -> str:
service = self.service()
plots = service.list_plots(user_id)
config = service.config
lines = ["# 🌱 菜园概览"]
if not plots:
lines.append("> 尚未种植任何作物,使用 `种植 <种子>` 开始耕种。")
else:
for plot in plots:
crop = GARDEN_CROPS.get(plot["seed_id"], None)
name = crop.display_name if crop else plot["seed_id"]
idx = plot["plot_index"]
is_mature = bool(plot["is_mature"])
mature_at = plot["mature_at"]
formatted_time = self._format_timestamp(mature_at)
if is_mature:
remaining = plot["remaining_fruit"]
theft_users = len(json.loads(plot["theft_users"])) if plot.get("theft_users") else 0
status = f"✅ 已成熟(成熟于 {formatted_time}"
lines.append(
f"- 地块 {idx}{name}{status}|剩余果实 {remaining}|被偷次数 {theft_users}"
)
else:
status = f"⌛ 生长中,预计成熟 {formatted_time}"
lines.append(f"- 地块 {idx}{name}{status}")
available = config.max_plots - len(plots)
if available > 0:
lines.append(f"\n> 尚有 {available} 块空地可用。")
lines.append(
"\n---\n- `种植 <种子>`:消耗种子种下作物\n"
"- `收获 <地块序号>`:收成成熟作物\n"
"- `偷取 <用户> <地块序号>`:从他人成熟作物中偷取果实\n"
"- `铲除 <地块序号>`:立即清空指定地块\n"
"- `菜园 售出 <果实> <数量>`:出售果实换取积分"
)
return "\n".join(lines)
# endregion
__all__ = ["WPSGardenBase"]