diff --git a/.tasks/2025-10-31_1_change-adventure-time-to-seconds.md b/.tasks/2025-10-31_1_change-adventure-time-to-seconds.md new file mode 100644 index 0000000..b1a31b4 --- /dev/null +++ b/.tasks/2025-10-31_1_change-adventure-time-to-seconds.md @@ -0,0 +1,80 @@ +# 背景 +文件名:2025-10-31_1_change-adventure-time-to-seconds.md +创建于:2025-10-31_17:30:37 +创建者:admin +主分支:main +任务分支:main +Yolo模式:Off + +# 任务描述 +将冒险系统的计时单位从分钟更改为秒。需要修改所有相关的时间计算、验证逻辑、显示文本和帮助信息。 + +## 后续需求 +支持时间格式输入(如 `1h30m10s`),并在显示时按时分秒格式显示,避免只显示秒数过于冗余。 + +# 项目概览 +修改 `games/adventure.py` 文件,将冒险时间单位从分钟改为秒。 + +# 分析 +当前代码中所有时间相关逻辑都以分钟为单位: +- 默认值:1分钟 +- 参数验证:至少1分钟 +- 时间计算:`cost_time * 60` 转换为秒 +- 显示文本:所有提示信息都显示"分钟" +- 奖励计算:倍率 × 分钟数 +- 放弃冒险:按分钟计算已消耗时间 + +需要将所有相关逻辑改为秒为单位。 + +# 提议的解决方案 +将所有时间单位从分钟改为秒: +1. 修改默认值和参数验证 +2. 移除时间计算中的 `* 60` 转换 +3. 更新所有显示文本 +4. 简化剩余时间显示逻辑(直接显示秒) +5. 更新帮助信息 + +# 当前执行步骤:"已完成" + +# 任务进度 + +## 2025-10-31_17:32:32 +- 已修改:games/adventure.py +- 更改: + 1. 修改默认值注释:从"1分钟"改为"1秒" + 2. 修改函数文档:cost_time参数从"(分钟)"改为"(秒)" + 3. 修改参数验证:错误提示从"至少需要1分钟"改为"至少需要1秒" + 4. 移除时间转换:将`end_time = start_time + saved_cost_time * 60`改为`end_time = start_time + saved_cost_time` + 5. 更新显示文本:所有"分钟"改为"秒"(冒险结果、冒险进行中、冒险开始、冒险放弃) + 6. 简化剩余时间显示:移除分钟/秒的转换逻辑,直接显示秒数 + 7. 修改放弃冒险逻辑:时间计算改为直接使用秒数(elapsed_seconds),移除分钟转换 + 8. 更新帮助信息:所有"分钟"改为"秒" +- 原因:将冒险系统计时单位从分钟改为秒,使时间控制更精确 +- 阻碍因素:无 +- 状态:成功 + +## 2025-10-31_17:35:06 +- 已修改:games/adventure.py +- 更改: + 1. 添加 `re` 模块导入,用于正则表达式解析 + 2. 新增 `_parse_time_string` 方法:解析时间格式字符串,支持以下格式: + - 纯数字(按秒):`60` -> 60秒 + - 时分秒组合:`1h30m10s` -> 5410秒 + - 分钟秒组合:`30m10s` -> 1810秒 + - 只有小时:`1h` -> 3600秒 + - 只有分钟:`30m` -> 1800秒 + - 只有秒:`10s` -> 10秒 + 3. 新增 `_format_time` 方法:将秒数格式化为 "X时X分X秒" 格式,自动省略为0的部分 + 4. 修改 `handle` 方法:使用 `_parse_time_string` 解析时间参数,提供格式错误提示 + 5. 更新所有时间显示位置: + - 冒险结果:使用 `_format_time` 格式化消耗时间 + - 冒险进行中:使用 `_format_time` 格式化剩余时间和总时长 + - 冒险开始:使用 `_format_time` 格式化持续时间 + - 冒险放弃:使用 `_format_time` 格式化已计入时间 + 6. 更新帮助信息:添加时间格式说明和示例 +- 原因:支持更灵活的时间输入格式,提升用户体验;时间显示按时分秒格式,避免冗长的秒数显示 +- 阻碍因素:无 +- 状态:待确认 + +# 最终审查 + diff --git a/games/adventure.py b/games/adventure.py index b30d180..e229244 100644 --- a/games/adventure.py +++ b/games/adventure.py @@ -2,6 +2,7 @@ import random import time import logging +import re from datetime import datetime from games.base import BaseGame from utils.parser import CommandParser @@ -22,19 +23,86 @@ class AdventureGame(BaseGame): # 奖品池配置 self.prize_pool: List[Tuple[int, float, str]] = [ # (权重, 倍率, 描述) - (500, 0.5, "少量积分"), - (350, 1, "中等积分"), + (300, 1, "少量积分"), + (250, 2, "中等积分"), (200, 2, "大量积分"), - (100, 5, "丰厚积分"), - (50, 10, "丰厚积分"), - (10, 100, "🌟 巨额积分"), - (1, 1000, "💎 传说积分"), + (150, 5, "丰厚积分"), + (100, 10, "丰厚积分"), + (50, 100, "🌟 巨额积分"), + (10, 1000, "💎 传说积分"), ] self.total_weight: int = 0 for weight,_,_ in self.prize_pool: self.total_weight += weight + def _parse_time_string(self, time_str: str) -> int: + """解析时间字符串,支持 h/m/s 格式 + + 支持的格式示例: + - "1h30m10s" -> 5410秒 + - "30m" -> 1800秒 + - "10s" -> 10秒 + - "1h30m" -> 5400秒 + - "3600" -> 3600秒(纯数字,按秒处理) + + Args: + time_str: 时间字符串 + + Returns: + 解析后的秒数,如果解析失败返回None + """ + if not time_str: + return None + + # 如果是纯数字,直接返回 + if time_str.isdigit(): + return int(time_str) + + # 使用正则表达式匹配 h/m/s 格式,确保整个字符串匹配 + pattern = r'^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$' + match = re.match(pattern, time_str.lower()) + + if not match: + return None + + hours = int(match.group(1) or 0) + minutes = int(match.group(2) or 0) + seconds = int(match.group(3) or 0) + + # 如果所有值都是0,返回None + if hours == 0 and minutes == 0 and seconds == 0: + return None + + total_seconds = hours * 3600 + minutes * 60 + seconds + return total_seconds + + def _format_time(self, seconds: int) -> str: + """将秒数格式化为 "X时X分X秒" 格式 + + Args: + seconds: 秒数 + + Returns: + 格式化的时间字符串,如 "1时30分10秒"、"30分10秒"、"10秒" + """ + if seconds < 0: + seconds = 0 + + hours = seconds // 3600 + minutes = (seconds % 3600) // 60 + secs = seconds % 60 + + parts = [] + if hours > 0: + parts.append(f"{hours}时") + if minutes > 0: + parts.append(f"{minutes}分") + if secs > 0 or not parts: + parts.append(f"{secs}秒") + + return "".join(parts) + async def handle(self, command: str, chat_id: int, user_id: int) -> str: """处理冒险相关指令 @@ -60,12 +128,16 @@ class AdventureGame(BaseGame): if args in ['abandon', '放弃']: return await self._abandon_adventure(chat_id, user_id) - # 默认:冒险耗时1分钟 + # 默认:冒险耗时1秒 else: # 解析消耗时间 - cost_time = 1 # 默认消耗1分钟 - if args.isdigit(): - cost_time = int(args) + cost_time = 1 # 默认消耗1秒 + if args: + parsed_time = self._parse_time_string(args) + if parsed_time is not None: + cost_time = parsed_time + else: + return f"❌ 时间格式错误!请使用以下格式:\n- 纯数字(秒):`.adventure 60`\n- 时分秒格式:`.adventure 1h30m10s`\n- 分钟秒格式:`.adventure 30m10s`\n- 只有秒:`.adventure 10s`" return await self._perform_adventure(chat_id, user_id, cost_time) @@ -79,14 +151,14 @@ class AdventureGame(BaseGame): Args: chat_id: 会话ID(使用0作为用户级标识) user_id: 用户ID - cost_time: 消耗时间(分钟) + cost_time: 消耗时间(秒) Returns: 抽奖结果消息 """ # 参数验证 if cost_time < 1: - return "❌ 冒险时间至少需要1分钟!" + return "❌ 冒险时间至少需要1秒!" # 查询冒险状态(使用chat_id=0表示用户级状态) state = self.db.get_game_state(0, user_id, 'adventure') @@ -98,7 +170,7 @@ class AdventureGame(BaseGame): state_data = state['state_data'] start_time = state_data.get('start_time', 0) saved_cost_time = state_data.get('cost_time', 1) - end_time = start_time + saved_cost_time * 60 + end_time = start_time + saved_cost_time remaining_seconds = end_time - current_time # 情况1.1:冒险已完成(时间已到或过期) @@ -120,8 +192,9 @@ class AdventureGame(BaseGame): updated_points = self.db.get_user_points(user_id) # 格式化输出 + time_str = self._format_time(saved_cost_time) text = f"## ⚡️ 冒险结果\n\n" - text += f"**消耗时间**: {saved_cost_time} 分钟\n\n" + text += f"**消耗时间**: {time_str}\n\n" text += f"**{reward['description']}**: 获得 {reward_points} 积分\n\n" text += f"**当前积分**: {updated_points['points']} 分\n\n" text += "---\n\n" @@ -130,17 +203,12 @@ class AdventureGame(BaseGame): return text # 情况1.2:冒险未完成,返回等待提示 - remaining_minutes = remaining_seconds // 60 - remaining_secs = remaining_seconds % 60 - - if remaining_minutes > 0: - wait_msg = f"{remaining_minutes} 分 {remaining_secs} 秒" - else: - wait_msg = f"{remaining_secs} 秒" + wait_msg = self._format_time(remaining_seconds) + saved_time_str = self._format_time(saved_cost_time) text = f"## ⚡️ 冒险进行中\n\n" text += f"你正在进行一次冒险,还需等待 **{wait_msg}** 才能完成。\n\n" - text += f"**当前冒险时长**: {saved_cost_time} 分钟\n\n" + text += f"**当前冒险时长**: {saved_time_str}\n\n" text += "---\n\n" text += "💡 提示:冒险期间无法进行炼金,请耐心等待!" @@ -162,12 +230,13 @@ class AdventureGame(BaseGame): self.db.save_game_state(0, user_id, 'adventure', state_data) # 计算预计完成时间 - end_time = current_time + cost_time * 60 + end_time = current_time + cost_time end_datetime = datetime.fromtimestamp(end_time) end_time_str = end_datetime.strftime('%H:%M:%S') + cost_time_str = self._format_time(cost_time) text = f"## ⚡️ 冒险开始\n\n" - text += f"你已经开始了冒险之旅,本次冒险将持续 **{cost_time}** 分钟。\n\n" + text += f"你已经开始了冒险之旅,本次冒险将持续 **{cost_time_str}**。\n\n" text += f"**预计完成时间**: {end_time_str}\n\n" text += "---\n\n" text += "💡 提示:冒险期间无法进行炼金,完成后使用 `.adventure` 获取奖励!" @@ -200,9 +269,8 @@ class AdventureGame(BaseGame): current_time = int(time.time()) elapsed_seconds = max(0, current_time - int(start_time)) - elapsed_minutes = elapsed_seconds // 60 - if elapsed_minutes < 1: - elapsed_minutes = 1 + if elapsed_seconds < 1: + elapsed_seconds = 1 # 计算最低倍率 try: @@ -211,7 +279,7 @@ class AdventureGame(BaseGame): # 兜底:若奖池异常,按0.5处理 min_multiplier = 0.5 - reward_points = int(min_multiplier * elapsed_minutes) + reward_points = int(min_multiplier * elapsed_seconds) if reward_points < 0: reward_points = 0 @@ -224,8 +292,9 @@ class AdventureGame(BaseGame): updated_points = self.db.get_user_points(user_id) # 输出 + elapsed_time_str = self._format_time(elapsed_seconds) text = f"## ⚡️ 冒险放弃\n\n" - text += f"**已计入时间**: {elapsed_minutes} 分钟\n\n" + text += f"**已计入时间**: {elapsed_time_str}\n\n" text += f"**最低倍率**: {min_multiplier} 倍\n\n" text += f"**获得积分**: {reward_points} 分\n\n" text += f"**当前积分**: {updated_points['points']} 分\n\n" @@ -272,9 +341,12 @@ class AdventureGame(BaseGame): """ text = f"## ⚡️ 冒险系统\n\n" text += f"### 基础用法\n" - text += f"- `.adventure` - 消耗1分钟进行冒险\n" - text += f"- `.adventure time` - 消耗time分钟进行冒险, 最少一分钟\n" - + text += f"- `.adventure` - 消耗1秒进行冒险\n" + text += f"- `.adventure 60` - 消耗60秒进行冒险\n" + text += f"- `.adventure 1h30m10s` - 消耗1小时30分10秒进行冒险\n" + text += f"- `.adventure 30m` - 消耗30分钟进行冒险\n" + text += f"- `.adventure 10s` - 消耗10秒进行冒险\n\n" + text += f"**时间格式说明**:支持时分秒组合,如 `1h30m10s`、`30m`、`10s`,也支持纯数字(按秒计算)。\n\n" text += f"### 其他功能\n" text += f"- `.adventure abandon` - 放弃当前冒险,按最低倍率结算已冒险时间\n" text += f"- `.adventure 放弃` - 放弃当前冒险,按最低倍率结算已冒险时间\n"