Files
abot/plugins/point_trade/main.py

814 lines
40 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from loguru import logger
import re
from datetime import datetime
from typing import Dict, Any, List, Optional, Tuple
import xml.etree.ElementTree as ET
from db.connection import DBConnectionManager
from db.points_db import PointsDBOperator
from base.plugin_common.message_plugin_interface import MessagePluginInterface
from base.plugin_common.plugin_interface import PluginStatus
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.revoke.message_auto_revoke import MessageAutoRevoke
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
import mysql.connector.pooling
from utils.wechat.contact_manager import ContactManager
from wechat_ipad import WechatAPIClient
from wechat_ipad.models.message import WxMessage
class PointTradePlugin(MessagePluginInterface):
"""积分交易插件"""
# 功能权限常量
FEATURE_KEY = "POINT_TRADE"
FEATURE_DESCRIPTION = "💱 积分交易功能 [积分交易, 积分转账, 我的积分, 积分排行, 打劫, 保释]"
@property
def name(self) -> str:
return "积分交易"
@property
def version(self) -> str:
return "1.0.0"
@property
def description(self) -> str:
return "提供积分交易功能,支持用户之间的积分转账"
@property
def author(self) -> str:
return "水牛"
@property
def command_prefix(self) -> Optional[str]:
return "" # 不需要前缀,直接匹配命令
@property
def commands(self) -> List[str]:
return self._commands
@property
def feature_key(self) -> Optional[str]:
return self.FEATURE_KEY
@property
def feature_description(self) -> Optional[str]:
return self.FEATURE_DESCRIPTION
def __init__(self):
super().__init__()
self.db_pool = None
self.bot: WechatAPIClient = None
self.revoke: MessageAutoRevoke = None
# 注册功能权限
self.feature = self.register_feature()
def initialize(self, context: Dict[str, Any]) -> bool:
"""初始化插件"""
self.LOG = logger
self.LOG.debug(f"正在初始化 {self.name} 插件...")
# 保存上下文对象
self.event_system = context.get("event_system")
self.gbm = context.get("gbm")
self.db_manager = DBConnectionManager.get_instance()
# 初始化积分数据库操作类
self.points_db = PointsDBOperator(self.db_manager)
self.db_pool = self.db_manager.mysql_pool
if not self.db_pool:
self.LOG.error("数据库连接池未初始化,插件无法正常工作")
return False
# 从配置中获取参数
point_trade_config = self._config.get("PointTrade", {})
self._commands = point_trade_config.get("command",
["积分交易", "积分转账", "转账积分",
"我的积分", "积分排行", "打劫", "保释"])
self.command_format = point_trade_config.get("command-format", """
积分交易指令:
积分转账 积分数 @用户 - 转账给指定用户
我的积分 - 查询个人积分详情
积分排行 - 查看群内积分排行榜
打劫 @用户 - 尝试打劫用户积分(有风险)
保释 @用户 - 花费30积分保释他人
""")
self.enable = point_trade_config.get("enable", True)
# 打劫功能配置
self.rob_success_rate = point_trade_config.get("rob-success-rate", 0.3) # 基础打劫成功率
self.rob_rate_decay = point_trade_config.get("rob-rate-decay", 0.5) # 积分差距导致的成功率衰减系数
self.rob_min_percent = point_trade_config.get("rob-min-percent", 0.1) # 打劫最小百分比
self.rob_max_percent = point_trade_config.get("rob-max-percent", 0.3) # 打劫最大百分比
self.rob_penalty_percent = point_trade_config.get("rob-penalty-percent", 0.2) # 打劫失败惩罚百分比
self.rob_cooldown = point_trade_config.get("rob-cooldown", 1800) # 打劫冷却时间(秒)
self.rob_min_points = point_trade_config.get("rob-min-points", 10) # 打劫最低积分要求
# 打劫冷却记录 {wxid: last_rob_time}
self.rob_cooldown_records = {}
self.LOG.debug(f"[{self.name}] 插件初始化完成,指令:{self._commands}")
return True
def start(self) -> bool:
"""启动插件"""
self.LOG.debug(f"[{self.name}] 插件已启动")
self.status = PluginStatus.RUNNING
return True
def stop(self) -> bool:
"""停止插件"""
self.LOG.info(f"[{self.name}] 插件已停止")
self.status = PluginStatus.STOPPED
return True
def can_process(self, message: Dict[str, Any]) -> bool:
"""检查是否可以处理该消息"""
if not self.enable:
return False
content = str(message.get("content", "")).strip()
command = content.split(" ")[0]
return command in self._commands
@plugin_stats_decorator(plugin_name="积分交易")
async def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()
self.LOG.debug(f"插件执行: {self.name}{content}")
command = content.split(" ")
sender = message.get("sender")
roomid = message.get("roomid", "")
gbm: GroupBotManager = message.get("gbm")
self.bot: WechatAPIClient = message.get("bot")
self.revoke: MessageAutoRevoke = message.get("revoke")
# 检查权限
if roomid and gbm.get_group_permission(roomid, self.feature) == PermissionStatus.DISABLED:
return False, "没有权限"
# 处理不同的命令
if command[0] == "我的积分":
return await self._handle_my_points(message)
elif command[0] == "积分排行":
return await self._handle_points_ranking(message)
elif command[0] == "打劫" or content.startswith("打劫 "):
return await self._handle_rob_points(message)
elif command[0] == "保释":
return await self._handle_bailout(message)
elif command[0] in self._commands:
return await self._handle_transfer_points(message)
else:
await self.bot.send_text_message((roomid if roomid else sender), f"❌未知命令!{self.command_format}",
sender)
return True, "未知命令"
async def _handle_transfer_points(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理积分转账命令"""
content = str(message.get("content", "")).strip()
command = content.split(" ")
sender = message.get("sender")
roomid = message.get("roomid", "")
msg: WxMessage = message.get("full_wx_msg")
xml = msg.msg_source
# 检查命令格式
if len(command) < 3:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message((roomid if roomid else sender),
f"❌命令格式错误!积分转账 积分数 @用户",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "命令格式错误"
# 检查积分数是否为正整数
if not command[1].isdigit():
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message((roomid if roomid else sender),
f"🈚️转账积分无效(必须为正整数!) \n积分转账 积分数 @用户",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "积分无效"
# 检查@用户是否有效
at_users = self.at_list(xml)
if len(at_users) != 1:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message((roomid if roomid else sender),
f"转账失败❌\n🈚️转账人无效! \n积分转账 积分数 @用户",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "转账人无效"
reward_points = int(command[1])
target_wxid = next(iter(at_users))
trader_wxid = sender
group_id = roomid
try:
# 先解析双方昵称,再执行转账:
# 这样流水入库时可以直接使用昵称,避免写入 wxid。
from_user_info = self._get_user_record(trader_wxid, group_id)
to_user_info = self._get_user_record(target_wxid, group_id)
from_user_name = from_user_info.get('wx_nick_name', trader_wxid) if from_user_info else trader_wxid
to_user_name = to_user_info.get('wx_nick_name', target_wxid) if to_user_info else target_wxid
# 使用积分系统进行转账
success, result = self.points_db.transfer_points(
trader_wxid, target_wxid, group_id,
reward_points,
"积分转账命令执行",
from_user_name=from_user_name,
to_user_name=to_user_name,
)
if not success:
error_msg = result.get("error", "未知错误")
if "积分不足" in error_msg:
current_points = result.get("current_points", 0)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(
(roomid if roomid else sender),
f"❌转账失败!\n你的积分不足以进行转账!当前积分:{current_points},你需要 {reward_points} 积分。",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
else:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(
(roomid if roomid else sender),
f"❌转账失败!\n{error_msg}",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, f"转账失败: {error_msg}"
# 获取转账后的积分信息
from_user = result.get("from_user", {})
to_user = result.get("to_user", {})
output = (
f"✅积分转账成功!\n"
f"👤{from_user_name} 转给 👤{to_user_name} {reward_points} 积分\n"
f"👤{from_user_name} 当前积分: {from_user.get('total_points', 0)}\n"
f"👤{to_user_name} 当前积分: {to_user.get('total_points', 0)}"
)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message((roomid if roomid else sender),
output, [sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 20)
return True, "转账成功"
except Exception as e:
self.LOG.error(f"积分交易出错: {e}")
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message((roomid if roomid else sender),
f"❌积分交易失败!请稍后重试。错误: {str(e)}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 2)
return True, f"处理出错: {str(e)}"
async def _handle_my_points(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理查询个人积分命令"""
sender = message.get("sender")
roomid = message.get("roomid", "")
try:
# 获取用户积分信息
user_points = self.points_db.get_user_points(sender, roomid)
if not user_points:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(
(roomid if roomid else sender),
f"❌未找到你的积分记录!请先参与积分活动[签到,答题/t]。",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 4)
return False, "未找到积分记录"
# 获取用户昵称
user_info = self._get_user_record(sender, roomid)
user_name = user_info.get('wx_nick_name', sender) if user_info else sender
# 获取用户积分交易记录
transactions = self.points_db.get_user_transactions(sender, roomid, 5)
# 统计不同来源的积分
source_stats = {}
for tx in transactions:
source = tx.get('source', '其他')
points = tx.get('points', 0)
if source not in source_stats:
source_stats[source] = 0
source_stats[source] += points
# 构建积分详情消息 - 优化格式
source_icons = {
"sign": "📝", "game": "🎮", "trade": "💱",
"rob": "🔫", "bailout": "🔓", "其他": "🔄"
}
source_details = []
for source, points in source_stats.items():
icon = source_icons.get(source, "")
sign = "+" if points > 0 else ""
source_details.append(f"{icon} {source}: {sign}{points}")
source_text = " | ".join(source_details) if source_details else "暂无记录"
# 构建最近交易记录 - 优化格式
recent_txs = ""
if transactions:
recent_txs = "\n━━━ 最近交易 ━━━\n"
for i, tx in enumerate(transactions[:5], 1):
is_positive = tx.get('points', 0) > 0
tx_icon = "📈" if is_positive else "📉"
tx_type = "+" if is_positive else "-"
points = abs(tx.get('points', 0))
desc = tx.get('description', '无描述')
date = tx.get('created_at', '').strftime('%m/%d %H:%M') if tx.get('created_at') else '未知'
recent_txs += f"{tx_icon} {date} {tx_type}{points}{desc}\n"
# 构建更Compact美观的输出
output = (
f"💰 {user_name} 的积分\n"
f"━━━━━━━━━━━━━━\n"
f"💵 当前积分: {user_points.get('total_points', 0)}"
# f"📊 积分来源: {source_text}"
f"{recent_txs}"
)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message((roomid if roomid else sender),
output, [sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 20)
return True, "查询积分成功"
except Exception as e:
self.LOG.error(f"查询积分出错: {e}")
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message((roomid if roomid else sender),
f"❌查询积分失败!请稍后重试。错误: {str(e)}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, f"处理出错: {str(e)}"
async def _handle_points_ranking(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理积分排行榜命令"""
sender = message.get("sender")
roomid = message.get("roomid", "")
if not roomid:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(sender,
"❌积分排行榜仅在群聊中可用!", "")
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "非群聊环境"
try:
# 获取群内积分排行
ranking = self.points_db.get_points_ranking(roomid, 10)
if not ranking:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
"❌暂无积分排行数据!请先参与积分活动。",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "无排行数据"
# 构建排行榜消息
rank_list = []
con = ContactManager.get_instance()
for i, user in enumerate(ranking, 1):
user_id = user.get('user_id', '')
points = user.get('total_points', 0)
# 获取用户昵称
# user_info = await self.bot.get_chatroom_nickname(user_id, roomid)
user_info = con.get_group_name(roomid, user_id) or user_id
# 添加排名标记
rank_mark = "🥇" if i == 1 else "🥈" if i == 2 else "🥉" if i == 3 else f"{i}."
rank_list.append(f"{rank_mark} {user_info}: {points} 积分")
output = (
f"🏆 积分排行榜 🏆\n"
f"\n"
f"{chr(10).join(rank_list)}\n"
f"\n"
f"更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid, output, [sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 60)
return True, "查询排行榜成功"
except Exception as e:
self.LOG.error(f"查询积分排行榜出错: {e}")
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"❌查询积分排行榜失败!请稍后重试。错误: {str(e)}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, f"处理出错: {str(e)}"
def at_list(self, xml):
"""
解析消息中的 @用户列表
:param xml: 消息的 XML 数据
:return: @用户的集合
"""
try:
root = ET.fromstring(xml)
atuserlist_element = root.find('.//atuserlist')
atuserlist_content = (atuserlist_element.text if atuserlist_element is not None else '').strip()
atuserlist_content_no_commas = atuserlist_content.strip(',')
atuserlist_content_no_commas = re.sub(r'\s+', '', atuserlist_content_no_commas)
atuserlist_set = set(atuserlist_content_no_commas.split(','))
# 现在set中存在{''}这种,请过滤掉
atuserlist_set.discard('')
self.LOG.info(f"解析到的 @用户列表: {atuserlist_set}")
# 如果atuserlist_set 为空就打印XML
if not atuserlist_set:
self.LOG.info(f"解析到的 @用户列表为空,XML:{xml}")
return atuserlist_set
except ET.ParseError as e:
self.LOG.error(f"解析 XML 失败: {e}")
return set()
def _get_db_connection(self):
"""从连接池获取数据库连接"""
return self.db_pool.get_connection()
def _get_user_record(self, wx_id, group_id):
"""
查询用户的记录
:param wx_id: 用户的微信ID
:param group_id: 群组ID
:return: 用户记录(字典格式)
"""
try:
with self._get_db_connection() as conn:
with conn.cursor(dictionary=True) as cursor:
cursor.execute("""
SELECT id, wx_id, wx_nick_name, points FROM t_sign_record
WHERE wx_id = %s AND group_id = %s
""", (wx_id, group_id))
return cursor.fetchone()
except mysql.connector.Error as e:
self.LOG.error(f"查询用户记录失败: {e}")
return None
def _get_user_record_by_nick(self, wx_id, group_id):
"""
根据微信ID查询用户的记录
:param wx_id: 用户的微信ID
:param group_id: 群组ID
:return: 用户记录(字典格式)
"""
try:
with self._get_db_connection() as conn:
with conn.cursor(dictionary=True) as cursor:
cursor.execute("""
SELECT id, wx_id, wx_nick_name, points FROM t_sign_record
WHERE wx_id = %s AND group_id = %s
""", (wx_id, group_id))
return cursor.fetchone()
except mysql.connector.Error as e:
self.LOG.error(f"查询用户记录失败: {e}")
return None
def _update_user_points(self, user_id, points_change, group_id):
"""
更新用户积分,使用 SQL 增量调整
:param user_id: 用户ID (数据库中的 id 字段)
:param points_change: 积分变化量(正数增加,负数减少)
:param group_id: 群组ID
"""
try:
with self._get_db_connection() as conn:
with conn.cursor(dictionary=True) as cursor:
cursor.execute("""
UPDATE t_sign_record
SET points = points + %s, update_time = %s
WHERE id = %s AND group_id = %s
""", (points_change, datetime.now(), user_id, group_id))
conn.commit()
except mysql.connector.Error as e:
self.LOG.error(f"更新用户积分失败: {e}")
raise
async def _handle_rob_points(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理打劫积分命令"""
import random
import time
from datetime import datetime
content = str(message.get("content", "")).strip()
sender = message.get("sender")
roomid = message.get("roomid", "")
msg: WxMessage = message.get("full_wx_msg")
xml = msg.msg_source
# 检查是否在群聊中
if not roomid:
await self.bot.send_text_message(sender, "❌打劫功能仅在群聊中可用!", "")
return True, "非群聊环境"
# 检查时间限制 - 只允许在18:00-21:00之间打劫
current_hour = datetime.now().hour
if current_hour < 18 or current_hour >= 21:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
"❌打劫功能仅在晚上18:00-21:00之间开放请在开放时间再来。",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "时间限制"
# 检查是否在押
prison_status = self.points_db.check_prison_status(sender, roomid)
if prison_status:
remaining_time = prison_status['end_time'] - datetime.now()
hours = int(remaining_time.total_seconds() / 3600)
minutes = int((remaining_time.total_seconds() % 3600) / 60)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(
roomid,
f"❌你正在服刑!\n剩余时间: {hours}小时{minutes}分钟\n可请求他人花费30积分保释。",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "在押状态"
# 检查冷却时间
current_time = time.time()
if sender in self.rob_cooldown_records:
last_rob_time = self.rob_cooldown_records[sender]
time_passed = current_time - last_rob_time
if time_passed < self.rob_cooldown:
remaining_time = int(self.rob_cooldown - time_passed)
minutes, seconds = divmod(remaining_time, 60)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid,
f"❌你最近已经打劫过了,需要冷却 {minutes}{seconds}秒 后才能再次打劫!",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "冷却中"
# 检查@用户是否有效
at_users = self.at_list(xml)
if len(at_users) != 1:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid,
f"打劫失败❌\n请指定一个打劫目标!\n打劫 @用户",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "目标无效"
target_wxid = next(iter(at_users))
robber_wxid = sender
# 不能打劫自己
if target_wxid == robber_wxid:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid, "❌你不能打劫自己!",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "不能打劫自己"
try:
# 获取打劫者和目标的积分信息
robber_points = self.points_db.get_user_points(robber_wxid, roomid)
target_points = self.points_db.get_user_points(target_wxid, roomid)
if not robber_points:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid,
"❌你没有积分记录,无法进行打劫!请先参与积分活动。",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "打劫者无积分"
if not target_points:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid,
"❌目标没有积分记录,无法进行打劫!",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "目标无积分"
robber_total = robber_points.get('total_points', 0)
target_total = target_points.get('total_points', 0)
# 检查最低积分要求
if robber_total < self.rob_min_points:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid,
f"❌你的积分不足 {self.rob_min_points} 点,无法进行打劫!",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "打劫者积分不足"
if target_total < self.rob_min_points:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid,
f"❌目标积分不足 {self.rob_min_points} 点,不值得打劫!",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "目标积分不足"
# 获取用户昵称
robber_info = self._get_user_record(robber_wxid, roomid)
target_info = self._get_user_record(target_wxid, roomid)
robber_name = robber_info.get('wx_nick_name', robber_wxid) if robber_info else robber_wxid
target_name = target_info.get('wx_nick_name', target_wxid) if target_info else target_wxid
# 决定打劫是否成功
# 计算积分差距对成功率的影响
points_diff = target_total - robber_total
# if points_diff > 0:
# # 如果目标积分比打劫者高,降低成功率
# diff_ratio = min(points_diff / target_total, 1.0) # 差距比例最大为1
# final_success_rate = self.rob_success_rate * (1 - diff_ratio * self.rob_rate_decay)
# else:
# # 如果打劫者积分比目标高,使用基础成功率
final_success_rate = self.rob_success_rate
# 确保成功率在合理范围内
final_success_rate = max(0.05, min(final_success_rate, self.rob_success_rate))
is_success = random.random() < final_success_rate
# 更新冷却时间
self.rob_cooldown_records[sender] = current_time
if is_success:
# 打劫成功,随机获取目标一定比例的积分
rob_percent = random.uniform(self.rob_min_percent, self.rob_max_percent)
rob_amount = int(target_total * rob_percent)
# 确保至少抢到1点积分
rob_amount = max(1, rob_amount)
# 计算抽水金额20%
tax_amount = int(rob_amount * 0.2)
# 确保至少抽水1点积分
tax_amount = max(1, tax_amount)
# 实际获得的积分
actual_rob_amount = rob_amount - tax_amount
# 执行积分转移(从目标到打劫者)
success, result = self.points_db.transfer_points(
target_wxid, robber_wxid, roomid,
actual_rob_amount,
f"{robber_name}打劫",
from_user_name=target_name,
to_user_name=robber_name,
)
# 执行抽水从目标到SYSTEM
tax_success, tax_result = self.points_db.transfer_points(
target_wxid, "SYSTEM", roomid,
tax_amount,
"打劫抽水",
from_user_name=target_name,
to_user_name="系统",
)
if success and tax_success:
# 获取转账后的积分信息
from_user = result.get("from_user", {})
to_user = result.get("to_user", {})
# 构建打劫成功消息
output = (
f"🔫 打劫成功!\n"
f"👤{robber_name} 成功打劫了 👤{target_name} {rob_amount} 积分!\n"
f"💰 实际获得: {actual_rob_amount} 积分 | 系统抽水: {tax_amount} 积分(20%)\n"
f"👤{robber_name} 当前积分: {to_user.get('total_points', 0)}\n"
f"👤{target_name} 当前积分: {from_user.get('total_points', 0)}"
)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid, output, [sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 90)
return True, "打劫成功"
else:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"❌打劫过程中出现问题:{result.get('error', '未知错误')}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "打劫失败"
else:
# 打劫失败处理
penalty_amount = int(robber_total * self.rob_penalty_percent)
penalty_amount = max(1, penalty_amount)
# 记录积分变动
success, result = self.points_db.transfer_points(
robber_wxid, target_wxid, roomid,
penalty_amount,
f"打劫{target_name}失败的惩罚",
from_user_name=robber_name,
to_user_name=target_name,
)
if success:
# 关押处理
self.points_db.imprison_user(
robber_wxid, roomid, 24,
f"打劫{target_name}失败被捕"
)
# 获取转账后的积分信息
from_user = result.get("from_user", {})
to_user = result.get("to_user", {})
# 构建打劫失败消息
output = (
f"🚨 打劫失败!\n"
f"👤{robber_name} 试图打劫 👤{target_name} 但被当场抓获!\n"
f"👮‍♂️ 被罚款 {penalty_amount} 积分并关押24小时\n"
f"💰 可请求他人花费30积分进行保释\n"
f"👤{robber_name} 当前积分: {from_user.get('total_points', 0)}"
)
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid, output, [sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 90)
return True, "打劫失败"
else:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"❌处理打劫惩罚时出现问题:{result.get('error', '未知错误')}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "处理惩罚失败"
except Exception as e:
self.LOG.error(f"处理打劫请求出错: {e}")
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"❌打劫过程中出现意外:{str(e)}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, f"处理出错: {str(e)}"
async def _handle_bailout(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理保释命令"""
sender = message.get("sender")
roomid = message.get("roomid", "")
msg: WxMessage = message.get("full_wx_msg")
xml = msg.msg_source
# 检查是否在群聊中
if not roomid:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(sender,
"❌保释功能仅在群聊中可用!", "")
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "非群聊环境"
# 检查@用户是否有效
at_users = self.at_list(xml)
if len(at_users) != 1:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"保释失败❌\n请指定一个保释目标!\n保释 @用户",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "目标无效"
prisoner_wxid = next(iter(at_users))
bailout_wxid = sender
# 不能保释自己
if prisoner_wxid == bailout_wxid:
client_msg_id, create_time, new_msg_id = await self.bot.send_at_message(roomid, "❌你不能保释自己!",
[sender])
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 5)
return True, "不能保释自己"
try:
# 获取用户昵称
prisoner_info = self._get_user_record(prisoner_wxid, roomid)
bailout_info = self._get_user_record(bailout_wxid, roomid)
prisoner_name = prisoner_info.get('wx_nick_name', prisoner_wxid) if prisoner_info else prisoner_wxid
bailout_name = bailout_info.get('wx_nick_name', bailout_wxid) if bailout_info else bailout_wxid
# 执行保释
success, message = self.points_db.bailout_user(
prisoner_wxid,
bailout_wxid,
roomid,
prisoner_name=prisoner_name,
bailout_user_name=bailout_name,
)
if success:
output = (
f"✅ 保释成功!\n"
f"👤{bailout_name} 花费30积分保释了 👤{prisoner_name}"
)
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid, output, sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 10)
return True, "保释成功"
else:
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"❌保释失败: {message}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, "保释失败"
except Exception as e:
self.LOG.error(f"处理保释请求出错: {e}")
client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(roomid,
f"❌保释过程中出现意外:{str(e)}",
sender)
self.revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 3)
return True, f"处理出错: {str(e)}"