提交,加入了出门历练功能

This commit is contained in:
liuwei
2025-11-21 16:11:46 +08:00
parent d461198be5
commit 92295109a1
2 changed files with 248 additions and 1 deletions

View File

@@ -3,7 +3,7 @@
[Xiuxian] [Xiuxian]
enable = true enable = true
# 指令集合(无需前缀),按核心/经济/信息/社交/门派分类 # 指令集合(无需前缀),按核心/经济/信息/社交/门派分类
command = ["修仙帮助", "积分购石", "积分换灵石", "注册修仙", "我的状态", "闭关", "出关", "聚灵", "排行榜", "修仙签到", "坊市", "购买", "乾坤袋", "使用", "服用", "突破", "强行突破", "劫掠", "赠与", "赠送", "创建门派", "加入门派", "退出门派"] command = ["修仙帮助", "积分购石", "积分换灵石", "注册修仙", "我的状态", "闭关", "出关", "聚灵", "排行榜", "修仙签到", "坊市", "购买", "乾坤袋", "使用", "服用", "突破", "强行突破", "劫掠", "赠与", "赠送", "创建门派", "加入门派", "退出门派", "出门历练", "炼丹"]
# 用法提示:命令格式错误时的反馈文本 # 用法提示:命令格式错误时的反馈文本
command-format = """ command-format = """
📜修仙指令: 📜修仙指令:
@@ -19,6 +19,8 @@ command-format = """
乾坤袋 乾坤袋
使用 物品名 使用 物品名
服用 回气丹 服用 回气丹
出门历练
炼丹 物品 数量
突破 - 需要丹药 突破 - 需要丹药
强行突破 - 不需要丹药 强行突破 - 不需要丹药
劫掠 - 抢劫其他门派弟子 劫掠 - 抢劫其他门派弟子
@@ -49,6 +51,10 @@ buy_seconds = 5
gift_seconds = 10 gift_seconds = 10
points_to_stone_seconds = 10 points_to_stone_seconds = 10
# 副本与炼丹冷却
expedition_seconds = 1800
alchemy_seconds = 600
# 修为结算参数:基础速率(每小时),灵根乘数(名称:倍率) # 修为结算参数:基础速率(每小时),灵根乘数(名称:倍率)
[Xiuxian.cultivation] [Xiuxian.cultivation]
base_rate_per_hour = 100 base_rate_per_hour = 100
@@ -102,3 +108,26 @@ realm_key = "xiuxian:zset:leaderboard:realm"
[Xiuxian.points_exchange] [Xiuxian.points_exchange]
point_to_stone_rate = 10 point_to_stone_rate = 10
# 材料定义
[Xiuxian.materials]
items = [
"灵草:T1",
"玄土:T1",
"青木藤:T1",
"赤炎石:T2",
"寒晶:T2",
"紫电砂:T2",
"太一金精:T3",
"昆仑玉髓:T3"
]
# 炼丹配方:物品:材料*数量,材料*数量;灵石消耗;成功率
[Xiuxian.recipes]
items = [
"聚灵符:灵草*3,玄土*1;10;0.9",
"回气丹:灵草*5,玄土*2;20;0.85",
"洗髓丹:灵草*10,玄土*5;50;0.6",
"改灵丹:赤炎石*8,寒晶*8;100;0.3",
"天灵露:太一金精*4,昆仑玉髓*4;200;0.1"
]

View File

@@ -289,6 +289,7 @@ class XiuxianPlugin(MessagePluginInterface):
"签到": rate_cfg.get("signin_seconds", 86400), "签到": rate_cfg.get("signin_seconds", 86400),
"坊市": rate_cfg.get("shop_seconds", 10), "坊市": rate_cfg.get("shop_seconds", 10),
"购买": rate_cfg.get("buy_seconds", 5), "购买": rate_cfg.get("buy_seconds", 5),
"出售": rate_cfg.get("buy_seconds", 5),
"乾坤袋": rate_cfg.get("bag_seconds", 3), "乾坤袋": rate_cfg.get("bag_seconds", 3),
"突破": rate_cfg.get("break_seconds", 60), "突破": rate_cfg.get("break_seconds", 60),
"强行突破": rate_cfg.get("force_break_seconds", 60), "强行突破": rate_cfg.get("force_break_seconds", 60),
@@ -300,6 +301,8 @@ class XiuxianPlugin(MessagePluginInterface):
"退出门派": 604800, "退出门派": 604800,
"积分购石": rate_cfg.get("points_to_stone_seconds", 10), "积分购石": rate_cfg.get("points_to_stone_seconds", 10),
"积分换灵石": rate_cfg.get("points_to_stone_seconds", 10), "积分换灵石": rate_cfg.get("points_to_stone_seconds", 10),
"出门历练": rate_cfg.get("expedition_seconds", 1800),
"炼丹": rate_cfg.get("alchemy_seconds", 600),
} }
cult_cfg = cfg.get("cultivation", {}) cult_cfg = cfg.get("cultivation", {})
@@ -329,6 +332,38 @@ class XiuxianPlugin(MessagePluginInterface):
except Exception as e: except Exception as e:
self.LOG.warning(f"解析商品配置失败: {s}, 错误: {e}") self.LOG.warning(f"解析商品配置失败: {s}, 错误: {e}")
materials_cfg = cfg.get("materials", {})
self.material_tier = {}
self.materials_by_tier = {"T1": [], "T2": [], "T3": []}
for m in materials_cfg.get("items", []):
try:
n, tier = m.split(":")
self.material_tier[n] = tier
if tier in self.materials_by_tier:
self.materials_by_tier[tier].append(n)
except Exception as e:
self.LOG.warning(f"解析材料配置失败: {m}, 错误: {e}")
recipes_cfg = cfg.get("recipes", {})
self.recipes = {}
for r in recipes_cfg.get("items", []):
try:
name, rest = r.split(":")
mats_part, stone_part, rate_part = rest.split(";")
mats = {}
for kv in mats_part.split(","):
kv = kv.strip()
if "*" in kv:
mn, q = kv.split("*")
elif "x" in kv:
mn, q = kv.split("x")
else:
mn, q = kv, "1"
mats[mn.strip()] = int(q.strip())
self.recipes[name] = {"materials": mats, "stone": int(stone_part.strip()), "rate": float(rate_part.strip())}
except Exception as e:
self.LOG.warning(f"解析配方失败: {r}, 错误: {e}")
pts_cfg = cfg.get("points_exchange", {}) pts_cfg = cfg.get("points_exchange", {})
self.point_to_stone_rate = int(pts_cfg.get("point_to_stone_rate", 10)) self.point_to_stone_rate = int(pts_cfg.get("point_to_stone_rate", 10))
@@ -494,10 +529,16 @@ class XiuxianPlugin(MessagePluginInterface):
return await self._cmd_shop(bot, sender, roomid) return await self._cmd_shop(bot, sender, roomid)
if cmd == "购买": if cmd == "购买":
return await self._cmd_buy(bot, sender, roomid, content) return await self._cmd_buy(bot, sender, roomid, content)
if cmd == "出售":
return await self._cmd_sell(bot, sender, roomid, content)
if cmd == "乾坤袋": if cmd == "乾坤袋":
return await self._cmd_bag(bot, sender, roomid) return await self._cmd_bag(bot, sender, roomid)
if cmd in ("使用", "服用"): if cmd in ("使用", "服用"):
return await self._cmd_use(bot, sender, roomid, content) return await self._cmd_use(bot, sender, roomid, content)
if cmd == "出门历练":
return await self._cmd_expedition(bot, sender, roomid)
if cmd == "炼丹":
return await self._cmd_alchemy(bot, sender, roomid, content)
if cmd == "突破": if cmd == "突破":
return await self._cmd_breakthrough(bot, sender, roomid) return await self._cmd_breakthrough(bot, sender, roomid)
if cmd == "强行突破": if cmd == "强行突破":
@@ -593,6 +634,9 @@ class XiuxianPlugin(MessagePluginInterface):
lines.append("注册修仙 道号") lines.append("注册修仙 道号")
lines.append("聚灵 数量") lines.append("聚灵 数量")
lines.append("购买 物品 数量") lines.append("购买 物品 数量")
lines.append("出售 物品 数量")
lines.append("出门历练")
lines.append("炼丹 物品 数量")
lines.append("使用 物品名") lines.append("使用 物品名")
lines.append("服用 回气丹") lines.append("服用 回气丹")
lines.append("赠与 目标wxid 数量") lines.append("赠与 目标wxid 数量")
@@ -997,6 +1041,44 @@ class XiuxianPlugin(MessagePluginInterface):
self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10) self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10)
return True, "购买成功" return True, "购买成功"
async def _cmd_sell(self, bot: WechatAPIClient, sender: str, roomid: str, content: str) -> Tuple[bool, str]:
parts = content.split()
if len(parts) < 2:
return False, "命令格式错误"
item_name = parts[0]
try:
qty = int(parts[1])
except Exception:
return False, "命令格式错误"
player = self._get_player(sender, roomid or "")
if not player:
return False, "未注册"
player = self._check_status_update(player)
inv = player.get("inventory") or {}
have = int(inv.get(item_name, 0))
if qty <= 0 or have < qty:
return False, "物品不足"
item = next((i for i in self.shop_items if i["name"] == item_name), None)
if not item:
return False, "商品不存在"
sell_ratio = 0.5
revenue = int(item["price"] * qty * sell_ratio)
inv[item_name] = have - qty
player["inventory"] = inv
player["spirit_stone"] = int(player.get("spirit_stone", 0)) + revenue
if self.xdb:
try:
self.xdb.remove_item(sender, item_name, qty)
self.xdb.update_player_fields(sender, {"spirit_stone": player["spirit_stone"]})
except Exception:
pass
self._save_player(player)
self._rate_set(sender, roomid or "", "出售")
client_msg_id, create_time, new_msg_id = await bot.send_text_message(roomid or sender, f"✅ 出售成功,{item_name} × {qty},获得灵石{revenue}", sender)
if self.revoke:
self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10)
return True, "出售成功"
async def _cmd_bag(self, bot: WechatAPIClient, sender: str, roomid: str) -> Tuple[bool, str]: async def _cmd_bag(self, bot: WechatAPIClient, sender: str, roomid: str) -> Tuple[bool, str]:
player = self._get_player(sender, roomid or "") player = self._get_player(sender, roomid or "")
if not player: if not player:
@@ -1023,6 +1105,82 @@ class XiuxianPlugin(MessagePluginInterface):
self._rate_set(sender, roomid or "", "背包") self._rate_set(sender, roomid or "", "背包")
return True, "背包" return True, "背包"
async def _cmd_expedition(self, bot: WechatAPIClient, sender: str, roomid: str) -> Tuple[bool, str]:
player = self._get_player(sender, roomid or "")
if not player:
return False, "未注册"
player = self._check_status_update(player)
st = player.get("status", "Idle")
if st in ("Cultivating", "Injured"):
return False, "状态不可历练"
prefix, layer = self._parse_realm(player.get("realm", "炼气1层"))
rs = self.realm_score_map.get(prefix, 0)
realm_mult = 1.0 + (float(rs) / 100.0)
layer_bonus = 1.0 + (max(0, (layer or 1) - 1) * 0.02)
d = realm_mult * layer_bonus
jack_p = min(0.05 * d, 0.25)
succ_p = min(0.45 * d, 0.8)
back_p = max(0.10 / d, 0.02)
r = random.random()
stones_gain = 0
mats_gain: Dict[str, int] = {}
if r < jack_p:
stones_gain = int(random.uniform(2000, 5000) * d)
n = random.randint(2, 3)
tiers = ["T3", "T2"] if rs >= 40 else ["T2", "T1"]
for _ in range(n):
tier = tiers[0] if random.random() < 0.6 else tiers[1]
pool = self.materials_by_tier.get(tier, [])
if not pool:
continue
name = random.choice(pool)
mats_gain[name] = mats_gain.get(name, 0) + 1
elif r < jack_p + succ_p:
stones_gain = int(random.uniform(200, 800) * d)
n = random.randint(1, 2)
tiers = ["T2", "T1"]
for _ in range(n):
tier = tiers[0] if random.random() < min(0.3 * d, 0.7) else tiers[1]
pool = self.materials_by_tier.get(tier, [])
if not pool:
continue
name = random.choice(pool)
mats_gain[name] = mats_gain.get(name, 0) + 1
elif r < jack_p + succ_p + back_p:
player["status"] = "Injured"
player["status_until"] = (datetime.now(timezone.utc) + timedelta(minutes=30)).isoformat()
self._save_player(player)
self._rate_set(sender, roomid or "", "出门历练")
client_msg_id, create_time, new_msg_id = await bot.send_text_message(roomid or sender, "❌ 历练失败灵气反噬受伤30分钟", sender)
if self.revoke:
self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10)
return False, "历练失败"
else:
self._rate_set(sender, roomid or "", "出门历练")
client_msg_id, create_time, new_msg_id = await bot.send_text_message(roomid or sender, "⚠️ 历练无所得", sender)
if self.revoke:
self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10)
return True, "历练无所得"
player["spirit_stone"] = int(player.get("spirit_stone", 0)) + stones_gain
inv = player.get("inventory") or {}
for k, v in mats_gain.items():
inv[k] = int(inv.get(k, 0)) + v
player["inventory"] = inv
if self.xdb:
try:
self.xdb.update_player_fields(sender, {"spirit_stone": player["spirit_stone"]})
for k, v in mats_gain.items():
self.xdb.add_item(sender, k, "材料", v)
except Exception:
pass
self._save_player(player)
self._rate_set(sender, roomid or "", "出门历练")
mats_text = ", ".join([f"{k}×{v}" for k, v in mats_gain.items()]) if mats_gain else ""
client_msg_id, create_time, new_msg_id = await bot.send_text_message(roomid or sender, f"✅ 历练成功,获得灵石{stones_gain},材料:{mats_text}", sender)
if self.revoke:
self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10)
return True, "历练成功"
async def _cmd_use(self, bot: WechatAPIClient, sender: str, roomid: str, content: str) -> Tuple[bool, str]: async def _cmd_use(self, bot: WechatAPIClient, sender: str, roomid: str, content: str) -> Tuple[bool, str]:
item_name = content.strip() item_name = content.strip()
if not item_name: if not item_name:
@@ -1117,6 +1275,66 @@ class XiuxianPlugin(MessagePluginInterface):
return False, "灵根提升失败" return False, "灵根提升失败"
return False, "不可使用的物品" return False, "不可使用的物品"
async def _cmd_alchemy(self, bot: WechatAPIClient, sender: str, roomid: str, content: str) -> Tuple[bool, str]:
parts = content.split()
if len(parts) < 2:
return False, "命令格式错误"
item_name = parts[0]
try:
qty = int(parts[1])
except Exception:
return False, "命令格式错误"
player = self._get_player(sender, roomid or "")
if not player:
return False, "未注册"
player = self._check_status_update(player)
recipe = self.recipes.get(item_name)
if not recipe:
return False, "配方不存在"
total_stone = recipe["stone"] * qty
if int(player.get("spirit_stone", 0)) < total_stone:
return False, "灵石不足"
inv = player.get("inventory") or {}
need = {}
for mk, mv in recipe["materials"].items():
need[mk] = mv * qty
for mk, nv in need.items():
if int(inv.get(mk, 0)) < nv:
return False, "材料不足"
for mk, nv in need.items():
inv[mk] = int(inv.get(mk, 0)) - nv
success = 0
fail = 0
item_type = next((i["type"] for i in self.shop_items if i["name"] == item_name), "丹药")
for _ in range(qty):
if random.random() < float(recipe["rate"]):
success += 1
else:
fail += 1
player["spirit_stone"] = int(player.get("spirit_stone", 0)) - total_stone
inv[item_name] = int(inv.get(item_name, 0)) + success
player["inventory"] = inv
if fail > 0:
player["status"] = "Unstable_Qi"
player["status_until"] = (datetime.now(timezone.utc) + timedelta(minutes=int(self.unstable_qi_minutes))).isoformat()
if self.xdb:
try:
self.xdb.update_player_fields(sender, {"spirit_stone": player["spirit_stone"], "status": player.get("status"), "status_until": player.get("status_until")})
if success > 0:
self.xdb.add_item(sender, item_name, item_type, success)
for mk, nv in need.items():
if nv > 0:
self.xdb.remove_item(sender, mk, nv)
except Exception:
pass
self._save_player(player)
self._rate_set(sender, roomid or "", "炼丹")
msg = f"✅ 炼丹完成,成功{success},失败{fail}"
client_msg_id, create_time, new_msg_id = await bot.send_text_message(roomid or sender, msg, sender)
if self.revoke:
self.revoke.add_message_to_revoke((roomid if roomid else sender), client_msg_id, create_time, new_msg_id, 10)
return True, "炼丹完成"
async def _cmd_breakthrough(self, bot: WechatAPIClient, sender: str, roomid: str) -> Tuple[bool, str]: async def _cmd_breakthrough(self, bot: WechatAPIClient, sender: str, roomid: str) -> Tuple[bool, str]:
player = self._get_player(sender, roomid or "") player = self._get_player(sender, roomid or "")
if not player: if not player: