新增菜园系统
This commit is contained in:
222
Plugins/WPSGardenSystem/garden_plugin_base.py
Normal file
222
Plugins/WPSGardenSystem/garden_plugin_base.py
Normal file
@@ -0,0 +1,222 @@
|
||||
"""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 = BackpackItemTier.COMMON if crop.tier == "common" else BackpackItemTier.RARE
|
||||
self._safe_register_item(backpack, crop.seed_id, seed_name, tier)
|
||||
self._safe_register_item(backpack, crop.fruit_id, fruit_name, tier)
|
||||
if crop.extra_reward and crop.extra_reward.kind == "item" and crop.extra_item_id:
|
||||
wood_name = f"{crop.display_name}的木材"
|
||||
self._safe_register_item(backpack, crop.extra_item_id, wood_name, BackpackItemTier.RARE)
|
||||
|
||||
self._safe_register_mode(
|
||||
store,
|
||||
crop,
|
||||
limit_amount=service.config.seed_store_limit,
|
||||
)
|
||||
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,
|
||||
)
|
||||
|
||||
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,
|
||||
) -> None:
|
||||
try:
|
||||
backpack.register_item(item_id, name, tier)
|
||||
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_recipe(
|
||||
self,
|
||||
alchemy: WPSAlchemyGame,
|
||||
crop: GardenCropDefinition,
|
||||
) -> None:
|
||||
try:
|
||||
success_rate = 0.75 if crop.tier == "common" else 0.6
|
||||
alchemy.register_recipe(
|
||||
(crop.fruit_id, crop.fruit_id, crop.fruit_id),
|
||||
crop.seed_id,
|
||||
"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"]
|
||||
Reference in New Issue
Block a user