新增菜园陷阱

This commit is contained in:
2025-11-15 17:06:12 +08:00
parent 3a5c0b2eda
commit 5d08fa0820
7 changed files with 660 additions and 3 deletions

View File

@@ -18,7 +18,9 @@ from .garden_models import (
GARDEN_CROPS,
GARDEN_FRUITS,
GARDEN_MISC_ITEMS,
GARDEN_TRAPS_DICT,
GardenCropDefinition,
GardenTrapDefinition,
get_garden_db_models,
)
@@ -248,12 +250,134 @@ class GardenService:
# endregion
# region Steal
def _is_theft_banned(self, user_id: int) -> Tuple[bool, Optional[str]]:
"""检查用户是否被禁止偷盗
Returns:
(是否被禁止, 如果被禁止则返回解封时间字符串否则为None)
"""
cursor = self._db.conn.cursor()
cursor.execute(
"SELECT banned_until FROM garden_theft_ban WHERE user_id = ?",
(user_id,),
)
row = cursor.fetchone()
if not row:
return False, None
banned_until_str = row["banned_until"]
banned_until = _parse_local_iso(banned_until_str)
now = _local_now()
if banned_until > now:
return True, banned_until_str
else:
# 已过期,删除记录
cursor.execute("DELETE FROM garden_theft_ban WHERE user_id = ?", (user_id,))
self._db.conn.commit()
return False, None
def _ban_theft(self, user_id: int, ban_hours: int) -> str:
"""禁止用户偷盗一定时间
Returns:
解封时间字符串
"""
banned_until = _local_now() + timedelta(hours=ban_hours)
banned_until_str = banned_until.isoformat()
cursor = self._db.conn.cursor()
cursor.execute(
"""
INSERT INTO garden_theft_ban (user_id, banned_until)
VALUES (?, ?)
ON CONFLICT(user_id) DO UPDATE SET banned_until = excluded.banned_until
""",
(user_id, banned_until_str),
)
self._db.conn.commit()
return banned_until_str
def _check_trap(self, plot: Dict[str, object], thief_id: int) -> Optional[Dict[str, object]]:
"""检查并触发陷阱
Returns:
如果触发陷阱返回陷阱信息字典否则返回None
"""
trap_item_id = plot.get("trap_item_id")
if not trap_item_id:
return None
# 检查陷阱耐久度
trap_durability = int(plot.get("trap_durability", 0))
if trap_durability <= 0:
return None
trap = GARDEN_TRAPS_DICT.get(trap_item_id)
if not trap:
return None
# 检查触发概率
if random.random() > trap.trigger_rate:
return None
# 触发陷阱:设置禁令
banned_until_str = self._ban_theft(thief_id, trap.ban_hours)
# 减少耐久度
new_durability = trap_durability - 1
user_id = int(plot["user_id"])
plot_index = int(plot["plot_index"])
cursor = self._db.conn.cursor()
if new_durability <= 0:
# 耐久度归零,移除陷阱
cursor.execute(
"""
UPDATE garden_plots SET trap_item_id = NULL, trap_config = NULL, trap_durability = 0
WHERE user_id = ? AND plot_index = ?
""",
(user_id, plot_index),
)
else:
# 更新耐久度
cursor.execute(
"""
UPDATE garden_plots SET trap_durability = ?
WHERE user_id = ? AND plot_index = ?
""",
(new_durability, user_id, plot_index),
)
self._db.conn.commit()
return {
"trap": trap,
"fine_points": trap.fine_points,
"ban_hours": trap.ban_hours,
"banned_until": banned_until_str,
"durability": new_durability,
"durability_exhausted": new_durability <= 0,
"trigger_message": trap.trigger_message.format(
fine=trap.fine_points,
hours=trap.ban_hours,
),
}
def steal(self, *, thief_id: int, owner_id: int, plot_index: int) -> Dict[str, object]:
plot = self.get_plot(owner_id, plot_index)
if not plot:
raise ValueError("目标地块不存在")
if int(plot["is_mature"]) != 1:
raise ValueError("目标作物尚未成熟")
# 检查是否被禁止偷盗
is_banned, banned_until_str = self._is_theft_banned(thief_id)
if is_banned:
banned_until = _parse_local_iso(banned_until_str)
now = _local_now()
remaining_hours = (banned_until - now).total_seconds() / 3600
raise ValueError(f"你已被禁止偷盗,解封时间:{self.format_display_time(banned_until_str)}(剩余约{int(remaining_hours)}小时)")
crop = GARDEN_CROPS.get(plot["seed_id"])
if not crop:
raise ValueError("未知作物")
@@ -264,6 +388,10 @@ class GardenService:
theft_users = set(json.loads(plot["theft_users"]))
if thief_id in theft_users:
raise ValueError("你已经偷取过该作物")
# 检查陷阱(在偷盗之前检查)
trap_result = self._check_trap(plot, thief_id)
theft_users.add(thief_id)
remaining -= 1
cursor = self._db.conn.cursor()
@@ -280,12 +408,61 @@ class GardenService:
),
)
self._db.conn.commit()
return {
result = {
"crop": crop,
"stolen_quantity": 1,
"remaining": remaining,
"chat_id": plot["chat_id"],
"trap_result": trap_result,
}
return result
# endregion
# region Trap
def place_trap(self, *, user_id: int, plot_index: int, trap_item_id: str) -> None:
"""在地块上放置陷阱"""
plot = self.get_plot(user_id, plot_index)
if not plot:
raise ValueError("目标地块不存在")
trap = GARDEN_TRAPS_DICT.get(trap_item_id)
if not trap:
raise ValueError("未知陷阱物品")
# 构建陷阱配置JSON格式
trap_config = json.dumps({
"item_id": trap.item_id,
"display_name": trap.display_name,
"tier": trap.tier,
})
cursor = self._db.conn.cursor()
cursor.execute(
"""
UPDATE garden_plots SET trap_item_id = ?, trap_config = ?, trap_durability = ?
WHERE user_id = ? AND plot_index = ?
""",
(trap_item_id, trap_config, trap.durability, user_id, plot_index),
)
self._db.conn.commit()
def remove_trap(self, *, user_id: int, plot_index: int) -> None:
"""移除地块上的陷阱"""
plot = self.get_plot(user_id, plot_index)
if not plot:
raise ValueError("目标地块不存在")
cursor = self._db.conn.cursor()
cursor.execute(
"""
UPDATE garden_plots SET trap_item_id = NULL, trap_config = NULL, trap_durability = 0
WHERE user_id = ? AND plot_index = ?
""",
(user_id, plot_index),
)
self._db.conn.commit()
# endregion