移除古灵阁妖精馈赠相关功能,更新配置文件和命令处理逻辑,确保代码结构更加简洁,提升可维护性。

This commit is contained in:
Zylan
2025-04-24 01:23:20 +08:00
parent 6dd0f55943
commit 4799a2bce8
7 changed files with 300 additions and 541 deletions

View File

@@ -162,7 +162,6 @@ GROUP_MODELS:
weather_report # 每日天气推送
report_reminder # 日报周报月报提醒
image_generation # AI生图
goblin_gift # 古灵阁妖精的馈赠
perplexity # perplexity
```

View File

@@ -32,18 +32,18 @@ def handle_help(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"- 新闻",
"- ask [问题]",
"",
"【决斗 & 偷袭】",
"- 决斗@XX",
"- 偷袭@XX",
"- 决斗排行/排行榜",
"- 我的战绩/决斗战绩",
"- 我的装备/查看装备",
"- 改名 [旧名] [新名]",
"",
# "【决斗 & 偷袭】",
# "- 决斗@XX",
# "- 偷袭@XX",
# "- 决斗排行/排行榜",
# "- 我的战绩/决斗战绩",
# "- 我的装备/查看装备",
# "- 改名 [旧名] [新名]",
# "",
"【提醒】",
"- 提醒xxxxx一次性、每日、每周",
"- 查看提醒/我的提醒/提醒列表",
"- 删除提醒 [ID]/all",
"- 删..提醒..",
"",
"【群聊工具】",
"- summary/总结",
@@ -56,236 +56,6 @@ def handle_help(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# 发送消息
return ctx.send_text(help_text)
def handle_duel(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "决斗" 命令
匹配: 决斗@XX 或 决斗和XX 等
"""
if not ctx.is_group:
ctx.send_text("❌ 决斗功能只支持群聊")
return True
if not match:
return False
# 获取对手名称
opponent_name_input = match.group(1).strip()
if ctx.logger:
ctx.logger.info(f"决斗指令匹配: 对手={opponent_name_input}, 发起者={ctx.sender_name}")
# 寻找群内对应的成员 (优先完全匹配,其次部分匹配)
opponent_wxid = None
opponent_name = None
# 第一次遍历:寻找完全匹配
for member_wxid, member_name in ctx.room_members.items():
if opponent_name_input == member_name:
opponent_wxid = member_wxid
opponent_name = member_name
if ctx.logger:
ctx.logger.info(f"找到完全匹配对手: {opponent_name}")
break
# 如果没有找到完全匹配,再寻找部分匹配
if not opponent_wxid:
for member_wxid, member_name in ctx.room_members.items():
if opponent_name_input in member_name:
opponent_wxid = member_wxid
opponent_name = member_name
if ctx.logger:
ctx.logger.info(f"未找到完全匹配,使用部分匹配对手: {opponent_name}")
break
if not opponent_wxid:
ctx.send_text(f"❌ 没有找到名为 {opponent_name_input} 的群成员")
return True
# 获取挑战者昵称
challenger_name = ctx.sender_name
group_id = ctx.msg.roomid
# --- 新增:决斗资格检查 (包括分数和 Boss 战) ---
try:
rank_system = DuelRankSystem(group_id)
# 获取双方玩家数据和分数
challenger_data = rank_system.get_player_data(challenger_name)
opponent_data = rank_system.get_player_data(opponent_name)
challenger_score = challenger_data.get("score", 0)
opponent_score = opponent_data.get("score", 0)
is_boss_battle = (opponent_name == "泡泡")
# 检查 Boss 战资格 (仅检查挑战者分数)
if is_boss_battle and challenger_score < 100:
funny_messages = [
f"嘿,{challenger_name}!你当前的积分 ({challenger_score}) 还没攒够挑战大魔王 '泡泡' 的勇气呢!先去决斗场练练级吧!💪",
f"勇士 {challenger_name} ({challenger_score}分),强大的 '泡泡' 觉得你还需要更多历练才能与之一战。先去赚点积分壮壮胆吧!💰",
f"({challenger_score}分) 就想挑战 Boss '泡泡'{challenger_name},你这是要去送人头吗?'泡泡' 表示太弱了,拒绝接待!🚫",
f"挑战 Boss '泡泡' 需要至少100积分作为门票{challenger_name} ({challenger_score}分) 好像还差一点点哦~ 😉",
f"'泡泡' 正在冥想,感觉到 {challenger_name} 的力量 ({challenger_score}分) 尚不足以撼动祂,让你再修炼修炼。🧘"
]
message = random.choice(funny_messages)
ctx.send_text(message)
if ctx.logger:
ctx.logger.info(f"玩家 {challenger_name} 积分 {challenger_score} 不足100阻止发起 Boss 战")
return True # 命令已处理,阻止后续逻辑
# 检查普通决斗资格 (检查双方分数)
elif not is_boss_battle and (challenger_score < 100 or opponent_score < 100):
low_score_player = ""
low_score_value = 0
if challenger_score < 100 and opponent_score < 100:
low_score_player = f"{challenger_name} ({challenger_score}分) 和 {opponent_name} ({opponent_score}分) 都"
low_score_value = min(challenger_score, opponent_score) # 不重要,仅用于日志
elif challenger_score < 100:
low_score_player = f"{challenger_name} ({challenger_score}分)"
low_score_value = challenger_score
else: # opponent_score < 100
low_score_player = f"{opponent_name} ({opponent_score}分)"
low_score_value = opponent_score
funny_messages = [
f"哎呀!{low_score_player} 的决斗积分还没到100分呢好像还没做好上场的准备哦😅",
f"等等!根据决斗场规则,{low_score_player} 的积分不足100分暂时无法参与决斗。先去打打小怪兽吧👾",
f"裁判举牌!🚩 {low_score_player} 决斗积分未满100本场决斗无效请先提升实力再来挑战",
f"看起来 {low_score_player} 还是个决斗新手积分不足100先熟悉一下场地找点低级对手练练手吧😉",
f"呜~~~ 决斗场的能量保护罩拒绝了 {low_score_player}积分不足100进入先去充点能"
]
message = random.choice(funny_messages)
ctx.send_text(message)
if ctx.logger:
ctx.logger.info(f"因玩家 {low_score_player} 积分 ({low_score_value}) 不足100阻止发起普通决斗")
return True # 命令已处理,阻止后续逻辑
except Exception as e:
if ctx.logger:
ctx.logger.error(f"检查决斗资格时出错: {e}", exc_info=True)
ctx.send_text("⚠️ 检查决斗资格时发生错误,请稍后再试。")
return True # 出错也阻止后续逻辑
# --- 决斗资格检查结束 ---
# 使用决斗管理器启动决斗 (只有通过所有检查才会执行到这里)
if ctx.robot and hasattr(ctx.robot, "duel_manager"):
duel_manager = ctx.robot.duel_manager
# 注意start_duel_thread 现在只会在资格检查通过后被调用
if not duel_manager.start_duel_thread(challenger_name, opponent_name, group_id, True):
ctx.send_text("⚠️ 目前有其他决斗正在进行中,请稍后再试!")
# 决斗管理器内部会发送消息,所以这里不需要额外发送
# 尝试触发馈赠
if hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
else:
# 如果没有决斗管理器,返回错误信息
ctx.send_text("⚠️ 决斗系统未初始化")
return False
def handle_sneak_attack(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "偷袭" 命令
匹配: 偷袭@XX 或 偷分@XX
"""
if not ctx.is_group:
ctx.send_text("❌ 偷袭功能只支持群聊哦。")
return True
if not match:
return False
# 获取目标名称
target_name = match.group(1).strip()
# 获取攻击者昵称
attacker_name = ctx.sender_name
# 调用偷袭逻辑
try:
from function.func_duel import attempt_sneak_attack
result_message = attempt_sneak_attack(attacker_name, target_name, ctx.msg.roomid)
# 发送结果
ctx.send_text(result_message)
# 尝试触发馈赠
if ctx.robot and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"执行偷袭命令出错: {e}")
ctx.send_text("⚠️ 偷袭功能出现错误")
return False
def handle_duel_rank(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "决斗排行" 命令
匹配: 决斗排行/决斗排名/排行榜
"""
if not ctx.is_group:
ctx.send_text("❌ 决斗排行榜功能只支持群聊")
return True
try:
from function.func_duel import get_rank_list
rank_list = get_rank_list(10, ctx.msg.roomid) # 获取前10名排行
ctx.send_text(rank_list)
# 尝试触发馈赠
if ctx.robot and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"获取决斗排行榜出错: {e}")
ctx.send_text("⚠️ 获取排行榜失败")
return False
def handle_duel_stats(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "决斗战绩" 命令
匹配: 决斗战绩/我的战绩/战绩查询 [名字]
"""
if not ctx.is_group:
ctx.send_text("❌ 决斗战绩查询功能只支持群聊")
return True
if not match:
return False
try:
from function.func_duel import get_player_stats
# 获取要查询的玩家
player_name = ""
if len(match.groups()) > 1 and match.group(2):
player_name = match.group(2).strip()
if not player_name: # 如果没有指定名字,则查询发送者
player_name = ctx.sender_name
stats = get_player_stats(player_name, ctx.msg.roomid)
ctx.send_text(stats)
# 尝试触发馈赠
if ctx.robot and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"查询决斗战绩出错: {e}")
ctx.send_text("⚠️ 查询战绩失败")
return False
def handle_check_equipment(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "查看装备" 命令
@@ -317,10 +87,6 @@ def handle_check_equipment(ctx: 'MessageContext', match: Optional[Match]) -> boo
ctx.send_text("\n".join(result))
# 尝试触发馈赠
if ctx.robot and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except Exception as e:
if ctx.logger:
@@ -401,10 +167,6 @@ def handle_reset_memory(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# 发送结果消息
ctx.send_text(result)
# 群聊中触发馈赠
if ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except Exception as e:
@@ -433,10 +195,6 @@ def handle_summary(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# 发送总结
ctx.send_text(summary)
# 尝试触发馈赠
if hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
else:
ctx.send_text("⚠️ 消息总结功能不可用")
@@ -468,10 +226,6 @@ def handle_clear_messages(ctx: 'MessageContext', match: Optional[Match]) -> bool
else:
ctx.send_text("⚠️ 本群没有消息历史记录")
# 尝试触发馈赠
if hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
else:
ctx.send_text("⚠️ 消息历史管理功能不可用")
@@ -513,10 +267,6 @@ def handle_news_request(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# 内容为空,说明获取彻底失败
ctx.send_text("❌ 获取新闻失败,请稍后重试或联系管理员。", sender_for_at)
# 尝试触发馈赠
if ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True # 无论结果如何,命令本身算成功处理
except Exception as e:
@@ -526,43 +276,6 @@ def handle_news_request(ctx: 'MessageContext', match: Optional[Match]) -> bool:
ctx.send_text("❌ 获取新闻时发生错误,请稍后重试。", sender_for_at)
return False # 处理失败
def handle_rename(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "改名" 命令
匹配: 改名 旧名 新名
"""
if not ctx.is_group:
ctx.send_text("❌ 改名功能只支持群聊")
return True
if not match or len(match.groups()) < 2:
ctx.send_text("❌ 改名格式不正确,请使用: 改名 旧名 新名")
return True
old_name = match.group(1)
new_name = match.group(2)
if not old_name or not new_name:
ctx.send_text("❌ 请提供有效的旧名和新名")
return True
try:
from function.func_duel import change_player_name
result = change_player_name(old_name, new_name, ctx.msg.roomid)
ctx.send_text(result)
# 尝试触发馈赠
if hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"改名出错: {e}")
ctx.send_text("⚠️ 改名失败")
return False
def handle_chitchat(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理闲聊调用AI模型生成回复
@@ -667,18 +380,10 @@ def handle_chitchat(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# 处理群聊消息
msg_data = ctx.robot.xml_processor.extract_quoted_message(ctx.msg)
q_with_info = ctx.robot.xml_processor.format_message_for_ai(msg_data, sender_name)
# 打印详细的消息数据,用于调试
if ctx.logger:
ctx.logger.info(f"【调试】群聊消息解析结果: type={ctx.msg.type}")
ctx.logger.info(f"【调试】提取的卡片信息: {msg_data}")
else:
# 处理私聊消息
msg_data = ctx.robot.xml_processor.extract_private_quoted_message(ctx.msg)
q_with_info = ctx.robot.xml_processor.format_message_for_ai(msg_data, sender_name)
# 打印详细的消息数据,用于调试
if ctx.logger:
ctx.logger.info(f"【调试】私聊消息解析结果: type={ctx.msg.type}")
ctx.logger.info(f"【调试】提取的卡片信息: {msg_data}")
if not q_with_info:
import time
@@ -702,10 +407,6 @@ def handle_chitchat(ctx: 'MessageContext', match: Optional[Match]) -> bool:
at_list = ctx.msg.sender if ctx.is_group else ""
ctx.send_text(rsp, at_list)
# 尝试触发馈赠
if ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
else:
if ctx.logger:
@@ -774,10 +475,6 @@ def handle_insult(ctx: 'MessageContext', match: Optional[Match]) -> bool:
if ctx.logger:
ctx.logger.info(f"已发送骂人消息至群 {ctx.msg.roomid},目标: {actual_target_name}")
# 尝试触发馈赠
if ctx.robot and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
except ImportError:
if ctx.logger:
@@ -883,10 +580,6 @@ def handle_perplexity_ask(ctx: 'MessageContext', match: Optional[Match]) -> bool
at_list = ctx.msg.sender if ctx.is_group else ""
ctx.send_text(rsp, at_list)
# 尝试触发馈赠
if ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
else:
if ctx.logger:
@@ -1120,10 +813,6 @@ def handle_reminder(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# 发送汇总消息
ctx.send_text("\n".join(reply_parts), at_list)
# 如果有成功设置的提醒,并且在群聊中,尝试触发馈赠
if successful_count > 0 and ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True # 命令处理流程结束
except Exception as e: # 捕获代码块顶层的其他潜在错误
@@ -1182,10 +871,6 @@ def handle_list_reminders(ctx: 'MessageContext', match: Optional[Match]) -> bool
f"{i+1}. [ID: {r['id'][:6]}] {time_display}: {r['content']}"
)
ctx.send_text("\n".join(reply_parts), at_list)
# 尝试触发馈赠(如果在群聊中)
if ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
return True
@@ -1405,14 +1090,10 @@ def handle_delete_reminder(ctx: 'MessageContext', match: Optional[Match]) -> boo
reply_msg += f"- {res['description']}: 失败原因: {res['message']}\n"
ctx.send_text(reply_msg.strip(), at_list)
if successful_deletes > 0 and ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
elif action == "delete_all":
success, message, count = ctx.robot.reminder_manager.delete_all_reminders(ctx.msg.sender)
ctx.send_text(message, at_list)
if success and count > 0 and ctx.is_group and hasattr(ctx.robot, "goblin_gift_manager"):
ctx.robot.goblin_gift_manager.try_trigger(ctx.msg)
elif action in ["clarify", "not_found", "error"]:
message_to_user = parsed_ai_response.get("message", "抱歉,我没能处理您的请求。")
@@ -1433,75 +1114,6 @@ def handle_delete_reminder(ctx: 'MessageContext', match: Optional[Match]) -> boo
ctx.logger.error(f"handle_delete_reminder AI 部分顶层错误: {e}", exc_info=True)
return True
def handle_weather(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "天气""温度" 命令
匹配: 天气 [城市名] 或 温度 [城市名]
"""
if not match:
return False
city_name = match.group(1).strip()
if not city_name:
ctx.send_text("🤔 请告诉我你想查询哪个城市的天气,例如:天气 北京")
return True
if ctx.logger:
ctx.logger.info(f"天气查询指令匹配: 城市={city_name}")
# --- 加载城市代码 ---
city_codes: Dict[str, str] = {}
city_code_path = os.path.join(os.path.dirname(__file__), '..', 'function', 'main_city.json') # 确保路径正确
try:
with open(city_code_path, 'r', encoding='utf-8') as f:
city_codes = json.load(f)
except FileNotFoundError:
if ctx.logger:
ctx.logger.error(f"城市代码文件未找到: {city_code_path}")
ctx.send_text("⚠️ 抱歉,天气功能所需的城市列表文件丢失了。")
return True
except json.JSONDecodeError:
if ctx.logger:
ctx.logger.error(f"无法解析城市代码文件: {city_code_path}")
ctx.send_text("⚠️ 抱歉,天气功能的城市列表文件格式错误。")
return True
except Exception as e:
if ctx.logger:
ctx.logger.error(f"加载城市代码时发生未知错误: {e}", exc_info=True)
ctx.send_text("⚠️ 抱歉,加载城市代码时发生错误。")
return True
# --- 城市代码加载完毕 ---
city_code = city_codes.get(city_name)
if not city_code:
# 尝试模糊匹配 (可选,如果需要)
found = False
for name, code in city_codes.items():
if city_name in name: # 如果输入的名字是城市全名的一部分
city_code = code
city_name = name # 使用找到的完整城市名
if ctx.logger:
ctx.logger.info(f"城市 '{match.group(1).strip()}' 未精确匹配,使用模糊匹配结果: {city_name} ({city_code})")
found = True
break
if not found:
ctx.send_text(f"😕 找不到城市 '{city_name}' 的天气信息,请检查城市名称是否正确。")
return True
# 获取天气信息
try:
from function.func_weather import Weather
weather_info = Weather(city_code).get_weather()
ctx.send_text(weather_info)
except Exception as e:
if ctx.logger:
ctx.logger.error(f"获取城市 {city_name}({city_code}) 天气时出错: {e}", exc_info=True)
ctx.send_text(f"😥 获取 {city_name} 天气时遇到问题,请稍后再试。")
return True
def handle_weather_forecast(ctx: 'MessageContext', match: Optional[Match]) -> bool:
"""
处理 "天气预报""预报" 命令
@@ -1569,4 +1181,291 @@ def handle_weather_forecast(ctx: 'MessageContext', match: Optional[Match]) -> bo
ctx.logger.error(f"获取城市 {city_name}({city_code}) 天气预报时出错: {e}", exc_info=True)
ctx.send_text(f"😥 获取 {city_name} 天气预报时遇到问题,请稍后再试。")
return True
return True
# def handle_duel(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# """
# 处理 "决斗" 命令
# 匹配: 决斗@XX 或 决斗和XX 等
# """
# if not ctx.is_group:
# ctx.send_text("❌ 决斗功能只支持群聊")
# return True
# if not match:
# return False
# # 获取对手名称
# opponent_name_input = match.group(1).strip()
# if ctx.logger:
# ctx.logger.info(f"决斗指令匹配: 对手={opponent_name_input}, 发起者={ctx.sender_name}")
# # 寻找群内对应的成员 (优先完全匹配,其次部分匹配)
# opponent_wxid = None
# opponent_name = None
# # 第一次遍历:寻找完全匹配
# for member_wxid, member_name in ctx.room_members.items():
# if opponent_name_input == member_name:
# opponent_wxid = member_wxid
# opponent_name = member_name
# if ctx.logger:
# ctx.logger.info(f"找到完全匹配对手: {opponent_name}")
# break
# # 如果没有找到完全匹配,再寻找部分匹配
# if not opponent_wxid:
# for member_wxid, member_name in ctx.room_members.items():
# if opponent_name_input in member_name:
# opponent_wxid = member_wxid
# opponent_name = member_name
# if ctx.logger:
# ctx.logger.info(f"未找到完全匹配,使用部分匹配对手: {opponent_name}")
# break
# if not opponent_wxid:
# ctx.send_text(f"❌ 没有找到名为 {opponent_name_input} 的群成员")
# return True
# # 获取挑战者昵称
# challenger_name = ctx.sender_name
# group_id = ctx.msg.roomid
# # --- 新增:决斗资格检查 (包括分数和 Boss 战) ---
# try:
# rank_system = DuelRankSystem(group_id)
# # 获取双方玩家数据和分数
# challenger_data = rank_system.get_player_data(challenger_name)
# opponent_data = rank_system.get_player_data(opponent_name)
# challenger_score = challenger_data.get("score", 0)
# opponent_score = opponent_data.get("score", 0)
# is_boss_battle = (opponent_name == "泡泡")
# # 检查 Boss 战资格 (仅检查挑战者分数)
# if is_boss_battle and challenger_score < 100:
# funny_messages = [
# f"嘿,{challenger_name}!你当前的积分 ({challenger_score}) 还没攒够挑战大魔王 '泡泡' 的勇气呢!先去决斗场练练级吧!💪",
# f"勇士 {challenger_name} ({challenger_score}分),强大的 '泡泡' 觉得你还需要更多历练才能与之一战。先去赚点积分壮壮胆吧!💰",
# f"({challenger_score}分) 就想挑战 Boss '泡泡'{challenger_name},你这是要去送人头吗?'泡泡' 表示太弱了,拒绝接待!🚫",
# f"挑战 Boss '泡泡' 需要至少100积分作为门票{challenger_name} ({challenger_score}分) 好像还差一点点哦~ 😉",
# f"'泡泡' 正在冥想,感觉到 {challenger_name} 的力量 ({challenger_score}分) 尚不足以撼动祂,让你再修炼修炼。🧘"
# ]
# message = random.choice(funny_messages)
# ctx.send_text(message)
# if ctx.logger:
# ctx.logger.info(f"玩家 {challenger_name} 积分 {challenger_score} 不足100阻止发起 Boss 战")
# return True # 命令已处理,阻止后续逻辑
# # 检查普通决斗资格 (检查双方分数)
# elif not is_boss_battle and (challenger_score < 100 or opponent_score < 100):
# low_score_player = ""
# low_score_value = 0
# if challenger_score < 100 and opponent_score < 100:
# low_score_player = f"{challenger_name} ({challenger_score}分) 和 {opponent_name} ({opponent_score}分) 都"
# low_score_value = min(challenger_score, opponent_score) # 不重要,仅用于日志
# elif challenger_score < 100:
# low_score_player = f"{challenger_name} ({challenger_score}分)"
# low_score_value = challenger_score
# else: # opponent_score < 100
# low_score_player = f"{opponent_name} ({opponent_score}分)"
# low_score_value = opponent_score
# funny_messages = [
# f"哎呀!{low_score_player} 的决斗积分还没到100分呢好像还没做好上场的准备哦😅",
# f"等等!根据决斗场规则,{low_score_player} 的积分不足100分暂时无法参与决斗。先去打打小怪兽吧👾",
# f"裁判举牌!🚩 {low_score_player} 决斗积分未满100本场决斗无效请先提升实力再来挑战",
# f"看起来 {low_score_player} 还是个决斗新手积分不足100先熟悉一下场地找点低级对手练练手吧😉",
# f"呜~~~ 决斗场的能量保护罩拒绝了 {low_score_player}积分不足100进入先去充点能⚡"
# ]
# message = random.choice(funny_messages)
# ctx.send_text(message)
# if ctx.logger:
# ctx.logger.info(f"因玩家 {low_score_player} 积分 ({low_score_value}) 不足100阻止发起普通决斗")
# return True # 命令已处理,阻止后续逻辑
# except Exception as e:
# if ctx.logger:
# ctx.logger.error(f"检查决斗资格时出错: {e}", exc_info=True)
# ctx.send_text("⚠️ 检查决斗资格时发生错误,请稍后再试。")
# return True # 出错也阻止后续逻辑
# # --- 决斗资格检查结束 ---
# # 使用决斗管理器启动决斗 (只有通过所有检查才会执行到这里)
# if ctx.robot and hasattr(ctx.robot, "duel_manager"):
# duel_manager = ctx.robot.duel_manager
# # 注意start_duel_thread 现在只会在资格检查通过后被调用
# if not duel_manager.start_duel_thread(challenger_name, opponent_name, group_id, True):
# ctx.send_text("⚠️ 目前有其他决斗正在进行中,请稍后再试!")
# # 决斗管理器内部会发送消息,所以这里不需要额外发送
# return True
# else:
# # 如果没有决斗管理器,返回错误信息
# ctx.send_text("⚠️ 决斗系统未初始化")
# return False
# def handle_sneak_attack(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# """
# 处理 "偷袭" 命令
# 匹配: 偷袭@XX 或 偷分@XX
# """
# if not ctx.is_group:
# ctx.send_text("❌ 偷袭功能只支持群聊哦。")
# return True
# if not match:
# return False
# # 获取目标名称
# target_name = match.group(1).strip()
# # 获取攻击者昵称
# attacker_name = ctx.sender_name
# # 调用偷袭逻辑
# try:
# from function.func_duel import attempt_sneak_attack
# result_message = attempt_sneak_attack(attacker_name, target_name, ctx.msg.roomid)
# # 发送结果
# ctx.send_text(result_message)
# return True
# except Exception as e:
# if ctx.logger:
# ctx.logger.error(f"执行偷袭命令出错: {e}")
# ctx.send_text("⚠️ 偷袭功能出现错误")
# return False
# def handle_duel_rank(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# """
# 处理 "决斗排行" 命令
# 匹配: 决斗排行/决斗排名/排行榜
# """
# if not ctx.is_group:
# ctx.send_text("❌ 决斗排行榜功能只支持群聊")
# return True
# try:
# from function.func_duel import get_rank_list
# rank_list = get_rank_list(10, ctx.msg.roomid) # 获取前10名排行
# ctx.send_text(rank_list)
# return True
# except Exception as e:
# if ctx.logger:
# ctx.logger.error(f"获取决斗排行榜出错: {e}")
# ctx.send_text("⚠️ 获取排行榜失败")
# return False
# def handle_duel_stats(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# """
# 处理 "决斗战绩" 命令
# 匹配: 决斗战绩/我的战绩/战绩查询 [名字]
# """
# if not ctx.is_group:
# ctx.send_text("❌ 决斗战绩查询功能只支持群聊")
# return True
# if not match:
# return False
# try:
# from function.func_duel import get_player_stats
# # 获取要查询的玩家
# player_name = ""
# if len(match.groups()) > 1 and match.group(2):
# player_name = match.group(2).strip()
# if not player_name: # 如果没有指定名字,则查询发送者
# player_name = ctx.sender_name
# stats = get_player_stats(player_name, ctx.msg.roomid)
# ctx.send_text(stats)
# return True
# except Exception as e:
# if ctx.logger:
# ctx.logger.error(f"查询决斗战绩出错: {e}")
# ctx.send_text("⚠️ 查询战绩失败")
# return False
# def handle_check_equipment(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# """
# 处理 "查看装备" 命令
# 匹配: 我的装备/查看装备
# """
# if not ctx.is_group:
# ctx.send_text("❌ 装备查看功能只支持群聊")
# return True
# try:
# from function.func_duel import DuelRankSystem
# player_name = ctx.sender_name
# rank_system = DuelRankSystem(ctx.msg.roomid)
# player_data = rank_system.get_player_data(player_name)
# if not player_data:
# ctx.send_text(f"⚠️ 没有找到 {player_name} 的数据")
# return True
# items = player_data.get("items", {"elder_wand": 0, "magic_stone": 0, "invisibility_cloak": 0})
# result = [
# f"🧙‍♂️ {player_name} 的魔法装备:",
# f"🪄 老魔杖: {items.get('elder_wand', 0)}次 ",
# f"💎 魔法石: {items.get('magic_stone', 0)}次",
# f"🧥 隐身衣: {items.get('invisibility_cloak', 0)}次 "
# ]
# ctx.send_text("\n".join(result))
# return True
# except Exception as e:
# if ctx.logger:
# ctx.logger.error(f"查看装备出错: {e}")
# ctx.send_text("⚠️ 查看装备失败")
# return False
# def handle_rename(ctx: 'MessageContext', match: Optional[Match]) -> bool:
# """
# 处理 "改名" 命令
# 匹配: 改名 旧名 新名
# """
# if not ctx.is_group:
# ctx.send_text("❌ 改名功能只支持群聊")
# return True
# if not match or len(match.groups()) < 2:
# ctx.send_text("❌ 改名格式不正确,请使用: 改名 旧名 新名")
# return True
# old_name = match.group(1)
# new_name = match.group(2)
# if not old_name or not new_name:
# ctx.send_text("❌ 请提供有效的旧名和新名")
# return True
# try:
# from function.func_duel import change_player_name
# result = change_player_name(old_name, new_name, ctx.msg.roomid)
# ctx.send_text(result)
# return True
# except Exception as e:
# if ctx.logger:
# ctx.logger.error(f"改名出错: {e}")
# ctx.send_text("⚠️ 改名失败")
# return False

View File

@@ -49,7 +49,7 @@ COMMANDS = [
name="perplexity_ask",
pattern=re.compile(r"^ask\s*(.+)", re.IGNORECASE | re.DOTALL),
scope="both", # 群聊和私聊都支持
need_at=True, # 需要@机器人
need_at=True, # 需要@机器人
priority=25, # 较高优先级,确保在闲聊之前处理
handler=handle_perplexity_ask,
description="使用 Perplexity AI 进行深度查询"
@@ -119,16 +119,6 @@ COMMANDS = [
description="查询指定城市未来几天的天气预报 (例如:天气预报 北京)"
),
Command(
name="weather",
pattern=re.compile(r"^(?:天气|温度)\s+(.+)$"), # 匹配 天气/温度 城市名
scope="both", # 群聊和私聊都支持
need_at=True, # 需要@机器人
priority=39, # 优先级设置在新闻命令前
handler=handle_weather,
description="查询指定城市的天气 (例如:天气 北京)"
),
Command(
name="news",
pattern=re.compile(r"^新闻$"),

View File

@@ -180,11 +180,4 @@ perplexity: # -----perplexity配置这行不填-----
trigger_keyword: ask # 触发Perplexity服务的前置词
allow_all: false # 是否允许所有群聊和用户使用Perplexity设为true时忽略下面的白名单配置
allowed_groups: [] # 允许使用Perplexity的群聊ID列表例如["123456789@chatroom", "123456789@chatroom"]
allowed_users: [] # 允许使用Perplexity的用户ID列表例如["wxid_123456789", "filehelper"]
goblin_gift: # -----古灵阁妖精的馈赠配置这行不填-----
enable: false # 是否全局启用古灵阁妖精的馈赠功能,默认关闭
probability: 0.01 # 触发概率默认为1%
min_points: 10 # 最小奖励积分
max_points: 100 # 最大奖励积分
allowed_groups: [] # 允许使用馈赠功能的群聊ID列表例如["123456789@chatroom", "123456789@chatroom"],留空表示不启用
allowed_users: [] # 允许使用Perplexity的用户ID列表例如["wxid_123456789", "filehelper"]

View File

@@ -1,102 +0,0 @@
import random
from typing import TYPE_CHECKING, Callable, Any
from wcferry import WxMsg
from function.func_duel import DuelRankSystem
if TYPE_CHECKING:
from logging import Logger
from wcferry import Wcf
from typing import Dict
class GoblinGiftManager:
"""管理古灵阁妖精的馈赠事件"""
def __init__(self, config: Any, wcf: 'Wcf', log: 'Logger', send_text_msg: Callable):
"""初始化馈赠管理器
Args:
config: 配置对象包含GOBLIN_GIFT配置项
wcf: WCF实例用于获取群聊昵称等信息
log: 日志记录器
send_text_msg: 发送文本消息的函数
"""
self.config = config
self.wcf = wcf
self.LOG = log
self.sendTextMsg = send_text_msg
def try_trigger(self, msg: WxMsg) -> None:
"""尝试触发古灵阁妖精的馈赠事件
Args:
msg: 微信消息对象
"""
# 检查配置是否存在
if not hasattr(self.config, 'GOBLIN_GIFT'):
return
# 检查全局开关
if not self.config.GOBLIN_GIFT.get('enable', False):
return
# 检查群聊白名单
allowed_groups = self.config.GOBLIN_GIFT.get('allowed_groups', [])
if not allowed_groups or msg.roomid not in allowed_groups:
return
# 只在群聊中才触发
if not msg.from_group():
return
# 获取触发概率默认1%
probability = self.config.GOBLIN_GIFT.get('probability', 0.01)
# 按概率触发
if random.random() < probability:
try:
# 获取玩家昵称
player_name = self.wcf.get_alias_in_chatroom(msg.sender, msg.roomid)
if not player_name:
player_name = msg.sender # 如果获取不到昵称用wxid代替
# 初始化对应群聊的积分系统
rank_system = DuelRankSystem(group_id=msg.roomid)
# 获取配置的积分范围默认10-100
min_points = self.config.GOBLIN_GIFT.get('min_points', 10)
max_points = self.config.GOBLIN_GIFT.get('max_points', 100)
# 随机增加积分
points_added = random.randint(min_points, max_points)
# 更新玩家数据
player_data = rank_system.get_player_data(player_name)
player_data['score'] += points_added
# 保存数据
rank_system._save_ranks()
# 准备随机馈赠消息
gift_sources = [
f"✨ 一只迷路的家养小精灵往 {player_name} 口袋里塞了什么东西!",
f"💰 古灵阁的妖精似乎格外青睐 {player_name},留下了一袋金加隆(折合积分)!",
f"🦉 一只送信的猫头鹰丢错了包裹,{player_name} 意外发现了一笔“意外之财”!",
f"🍀 {player_name} 踩到了一株幸运四叶草,好运带来了额外的积分!",
f"🍄 在禁林的边缘,{player_name} 发现了一簇闪闪发光的魔法蘑菇!",
f"{player_name} 捡到了一个有求必应屋掉出来的神秘物品!",
f"🔮 временами удача улыбается {player_name}!", # 偶尔来点不一样的语言增加神秘感
f"🎉 费尔奇打瞌睡时掉了一小袋没收来的积分,刚好被 {player_name} 捡到!",
f"📜 一张古老的藏宝图碎片指引 {player_name} 找到了一些失落的积分!",
f"🧙‍♂️ 邓布利多教授对 {player_name} 的行为表示赞赏,特批“为学院加分”!",
f"🧪 {player_name} 的魔药课作业获得了斯拉格霍恩教授的额外加分!",
f"🌟 一颗流星划过霍格沃茨上空,{player_name} 许下的愿望成真了!"
]
gift_message = random.choice(gift_sources)
final_message = f"{gift_message}\n获得积分: +{points_added} 分!"
# 发送馈赠通知 (@发送者)
self.sendTextMsg(final_message, msg.roomid, msg.sender)
self.LOG.info(f"古灵阁馈赠触发: 群 {msg.roomid}, 用户 {player_name}, 获得 {points_added} 积分")
except Exception as e:
self.LOG.error(f"触发古灵阁馈赠时出错: {e}")

View File

@@ -102,7 +102,6 @@ def handle_insult_request(
logger,
bot_wxid: str,
send_text_func: Callable[[str, str, Optional[str]], None],
trigger_goblin_gift_func: Callable[[object], None],
msg,
target_mention_name: str
) -> bool:
@@ -114,7 +113,6 @@ def handle_insult_request(
logger: 日志记录器。
bot_wxid: 机器人自身的 wxid。
send_text_func: 发送文本消息的函数 (content, receiver, at_list=None)。
trigger_goblin_gift_func: 触发哥布林馈赠的函数。
msg: 原始消息对象 (需要 .roomid 属性)。
target_mention_name: 从消息中提取的被@用户的名称。
@@ -154,9 +152,6 @@ def handle_insult_request(
send_text_func(insult_text, msg.roomid)
logger.info(f"已发送骂人消息至群 {msg.roomid},目标: {actual_target_name}")
if trigger_goblin_gift_func:
trigger_goblin_gift_func(msg)
except Exception as e:
logger.error(f"生成或发送骂人消息时出错: {e}")
send_text_func("呃,我想骂但出错了...", msg.roomid)

View File

@@ -32,7 +32,6 @@ from configuration import Config
from constants import ChatType
from job_mgmt import Job
from function.func_xml_process import XmlProcessor
from function.func_goblin_gift import GoblinGiftManager
# 导入命令路由系统
from commands.context import MessageContext
@@ -171,9 +170,6 @@ class Robot(Job):
# 初始化图像生成管理器
self.image_manager = ImageGenerationManager(self.config, self.wcf, self.LOG, self.sendTextMsg)
# 初始化古灵阁妖精馈赠管理器
self.goblin_gift_manager = GoblinGiftManager(self.config, self.wcf, self.LOG, self.sendTextMsg)
# 初始化命令路由器
self.command_router = CommandRouter(COMMANDS, robot_instance=self)
@@ -455,18 +451,7 @@ class Robot(Job):
return self.chat_models[ChatType.PERPLEXITY.value]
return None
def try_trigger_goblin_gift(self, msg: WxMsg) -> None:
"""尝试触发古灵阁妖精的馈赠事件
用户与机器人互动时,有概率获得随机积分
根据配置决定是否启用及在哪些群聊启用
Args:
msg: 微信消息对象
"""
# 调用管理器的触发方法
self.goblin_gift_manager.try_trigger(msg)
def _select_model_for_message(self, msg: WxMsg) -> None:
"""根据消息来源选择对应的AI模型