From aef45eb9a4d7f37c459517d7aa5a63e54e3f39cc Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Fri, 7 Nov 2025 11:07:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8D=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .tasks/2025-11-03_2_werewolf-game.md | 44 +++++++++ games/werewolf.py | 128 +++++++++++++++++++++------ 2 files changed, 144 insertions(+), 28 deletions(-) diff --git a/.tasks/2025-11-03_2_werewolf-game.md b/.tasks/2025-11-03_2_werewolf-game.md index b6b5741..3fce2a3 100644 --- a/.tasks/2025-11-03_2_werewolf-game.md +++ b/.tasks/2025-11-03_2_werewolf-game.md @@ -231,6 +231,50 @@ if game_type == 'werewolf': - 状态:成功 +[2025-11-07_10:59:09] +- 已修改: + 1. games/werewolf.py - 支持在私聊中使用狼人杀技能(方案2实施) + +- 更改: + 1. 新增 _find_player_game(user_id) 方法,根据玩家ID查找其参与的游戏 + 2. 修改 _handle_skill() 方法,支持从私聊中使用技能指令 + 3. 修改 _wolf_group_chat() 方法,支持从私聊中发送狼人群聊 + 4. 修改 _private_chat() 方法,支持从私聊中发送玩家私聊 + 5. 修改 _witch_pass() 方法,支持从私聊中跳过女巫行动 + 6. 添加日志输出,显示在私聊中使用功能的情况 + 7. 实现逻辑:先尝试用当前chat_id查找游戏(群聊场景),找不到则通过user_id查找玩家游戏(私聊场景) + +- 原因: + 解决私聊中无法使用技能的问题。游戏在群里创建,但玩家需要在私聊中使用技能以保密。 + 之前的设计只能在游戏所在群使用技能,现在支持在私聊中使用,查找玩家参与的游戏并操作。 + +- 阻碍因素: + 无 + +- 状态:成功 + +[2025-11-07_11:06:58] +- 已修改: + 1. games/werewolf.py - 改为全局唯一游戏模式(不再按chat_id区分) + +- 更改: + 1. 修改 _get_game_state() 方法,查询全局唯一游戏而非根据chat_id查询 + 2. 新增 _get_game_chat_id() 方法,获取全局游戏所在的chat_id + 3. 简化 _find_player_game() 方法,使用全局游戏查询 + 4. 修改 _open_game() 方法,检查全局是否已有游戏(而非仅检查当前群) + 5. 简化所有需要查找玩家游戏的方法(_handle_skill、_wolf_group_chat、_private_chat、_witch_pass) + 6. 保持数据库兼容性:chat_id列仍然存在并记录游戏创建的群,但查询时忽略 + 7. 实现逻辑:所有查询都获取全局最新的一个狼人杀游戏,不再区分群组 + +- 原因: + Bot全局只需要一个狼人杀游戏,不同群的玩家可以参与同一个游戏。 + 简化逻辑,消除按chat_id区分的复杂性,同时保持数据库结构兼容。 + +- 阻碍因素: + 无 + +- 状态:成功 + # 最终审查 待审查阶段完成... diff --git a/games/werewolf.py b/games/werewolf.py index ae744c3..2d5f31f 100644 --- a/games/werewolf.py +++ b/games/werewolf.py @@ -138,20 +138,32 @@ class WerewolfGame(BaseGame): logger.error(f"处理狼人杀指令错误: {e}", exc_info=True) return f"❌ 处理指令出错: {str(e)}" - def _get_game_state(self, chat_id: int) -> Optional[Dict]: - """获取游戏状态 + def _get_game_state(self, chat_id: int = None) -> Optional[Dict]: + """获取游戏状态(全局唯一,忽略chat_id) Args: - chat_id: 会话ID + chat_id: 会话ID(保留参数用于兼容性,实际忽略) Returns: 游戏状态或None """ - state = self.db.get_game_state(chat_id, 0, 'werewolf') - if state: - logger.debug(f"获取游戏状态成功: chat_id={chat_id}, status={state['state_data'].get('status')}, phase={state['state_data'].get('phase')}") - return state['state_data'] - logger.warning(f"获取游戏状态失败: chat_id={chat_id}, 状态不存在") + # 查询全局唯一的狼人杀游戏(不依赖chat_id) + cursor = self.db.conn.cursor() + cursor.execute( + "SELECT chat_id, state_data FROM game_states WHERE game_type = ? AND user_id = 0 ORDER BY updated_at DESC LIMIT 1", + ('werewolf',) + ) + row = cursor.fetchone() + + if row: + state_data = json.loads(row['state_data']) if row['state_data'] else None + game_chat_id = row['chat_id'] + + if state_data: + logger.debug(f"获取全局游戏状态成功: game_chat_id={game_chat_id}, status={state_data.get('status')}, phase={state_data.get('phase')}") + return state_data + + logger.warning(f"获取游戏状态失败: 全局无进行中的游戏") return None def _save_game_state(self, chat_id: int, state_data: Dict): @@ -164,6 +176,55 @@ class WerewolfGame(BaseGame): logger.debug(f"保存游戏状态: chat_id={chat_id}, status={state_data.get('status')}, phase={state_data.get('phase')}") self.db.save_game_state(chat_id, 0, 'werewolf', state_data) + def _get_game_chat_id(self) -> Optional[int]: + """获取全局游戏所在的chat_id + + Returns: + 游戏所在的chat_id,如果没有游戏返回None + """ + cursor = self.db.conn.cursor() + cursor.execute( + "SELECT chat_id FROM game_states WHERE game_type = ? AND user_id = 0 ORDER BY updated_at DESC LIMIT 1", + ('werewolf',) + ) + row = cursor.fetchone() + + if row: + return row['chat_id'] + return None + + def _find_player_game(self, user_id: int) -> tuple[Optional[int], Optional[Dict]]: + """查找玩家参与的游戏(全局唯一游戏) + + Args: + user_id: 玩家用户ID + + Returns: + (游戏所在chat_id, 游戏状态数据) 或 (None, None) + """ + # 获取全局游戏状态 + state_data = self._get_game_state() + + if not state_data: + logger.debug(f"未找到全局游戏") + return None, None + + # 只查找进行中的游戏 + if state_data.get('status') != 'playing': + logger.debug(f"全局游戏未在进行中: status={state_data.get('status')}") + return None, None + + # 检查玩家是否在游戏中 + players = state_data.get('players', []) + for player in players: + if player.get('user_id') == user_id: + game_chat_id = self._get_game_chat_id() + logger.debug(f"找到玩家 {user_id} 的游戏: chat_id={game_chat_id}") + return game_chat_id, state_data + + logger.debug(f"玩家 {user_id} 未参与全局游戏") + return None, None + def _get_phase_description(self, phase: str) -> Dict[str, str]: """获取阶段描述信息 @@ -246,13 +307,13 @@ class WerewolfGame(BaseGame): Returns: 提示消息 """ - # 检查是否已有游戏 - state_data = self._get_game_state(chat_id) + # 检查全局是否已有游戏 + state_data = self._get_game_state() if state_data: if state_data['status'] == 'playing': - return "⚠️ 已经有游戏正在进行中!" + return "⚠️ 全局已经有游戏正在进行中!" elif state_data['status'] == 'open': - return "⚠️ 房间已存在!\n\n房间状态:等待玩家加入\n\n玩家可以输入 `.werewolf join` 加入游戏" + return "⚠️ 全局房间已存在!\n\n房间状态:等待玩家加入\n\n玩家可以输入 `.werewolf join` 加入游戏" # 创建新房间 state_data = { @@ -481,9 +542,11 @@ class WerewolfGame(BaseGame): Returns: 提示消息 """ - state_data = self._get_game_state(chat_id) + # 查找玩家参与的游戏(全局唯一) + _, state_data = self._find_player_game(user_id) + if not state_data: - return "❌ 没有正在进行的游戏!" + return "❌ 你没有参与任何进行中的游戏!" if state_data['status'] != 'playing': return "❌ 游戏未开始或已结束!" @@ -534,9 +597,11 @@ class WerewolfGame(BaseGame): Returns: 提示消息 """ - state_data = self._get_game_state(chat_id) + # 查找玩家参与的游戏(全局唯一) + _, state_data = self._find_player_game(user_id) + if not state_data: - return "❌ 没有正在进行的游戏!" + return "❌ 你没有参与任何进行中的游戏!" if state_data['status'] != 'playing': return "❌ 游戏未开始或已结束!" @@ -584,10 +649,15 @@ class WerewolfGame(BaseGame): 提示消息 """ logger.debug(f"处理技能 - chat_id: {chat_id}, user_id: {user_id}, skill: {skill}, target_id: {target_id}") - state_data = self._get_game_state(chat_id) + + # 查找玩家参与的游戏(全局唯一) + game_chat_id, state_data = self._find_player_game(user_id) + if not state_data: - logger.warning(f"技能处理失败 - 未找到游戏状态: chat_id={chat_id}") - return "❌ 没有正在进行的游戏!" + logger.warning(f"技能处理失败 - 玩家未参与任何游戏: user_id={user_id}") + return "❌ 你没有参与任何进行中的游戏!" + + logger.debug(f"找到玩家游戏: game_chat_id={game_chat_id}, user_id={user_id}") if state_data['status'] != 'playing': return "❌ 游戏未开始或已结束!" @@ -605,15 +675,15 @@ class WerewolfGame(BaseGame): if not player['alive']: return "❌ 死亡玩家无法使用技能!" - # 根据技能类型处理 + # 根据技能类型处理(使用 game_chat_id) if skill == '杀': - return await self._wolf_kill(chat_id, state_data, player, target_id) + return await self._wolf_kill(game_chat_id, state_data, player, target_id) elif skill == '验': - return await self._seer_check(chat_id, state_data, player, target_id) + return await self._seer_check(game_chat_id, state_data, player, target_id) elif skill == '救': - return await self._witch_save(chat_id, state_data, player, target_id) + return await self._witch_save(game_chat_id, state_data, player, target_id) elif skill == '毒': - return await self._witch_poison(chat_id, state_data, player, target_id) + return await self._witch_poison(game_chat_id, state_data, player, target_id) return "❌ 未知技能" @@ -817,9 +887,11 @@ class WerewolfGame(BaseGame): Returns: 提示消息 """ - state_data = self._get_game_state(chat_id) + # 查找玩家参与的游戏(全局唯一) + game_chat_id, state_data = self._find_player_game(user_id) + if not state_data: - return "❌ 没有正在进行的游戏!" + return "❌ 你没有参与任何进行中的游戏!" if state_data['status'] != 'playing': return "❌ 游戏未开始或已结束!" @@ -844,8 +916,8 @@ class WerewolfGame(BaseGame): if current_phase != 'night_witch': return f"❌ 当前不是女巫行动阶段!当前阶段:{self._get_phase_description(current_phase)['name']}" - # 自动推进到下一阶段 - next_phase_msg = self._advance_phase(chat_id, state_data) + # 自动推进到下一阶段(使用 game_chat_id) + next_phase_msg = self._advance_phase(game_chat_id, state_data) return f"✅ 女巫选择跳过,不行动{next_phase_msg}"