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

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]
enable = true
# 指令集合(无需前缀),按核心/经济/信息/社交/门派分类
command = ["修仙帮助", "积分购石", "积分换灵石", "注册修仙", "我的状态", "闭关", "出关", "聚灵", "排行榜", "修仙签到", "坊市", "购买", "乾坤袋", "使用", "服用", "突破", "强行突破", "劫掠", "赠与", "赠送", "创建门派", "加入门派", "退出门派"]
command = ["修仙帮助", "积分购石", "积分换灵石", "注册修仙", "我的状态", "闭关", "出关", "聚灵", "排行榜", "修仙签到", "坊市", "购买", "乾坤袋", "使用", "服用", "突破", "强行突破", "劫掠", "赠与", "赠送", "创建门派", "加入门派", "退出门派", "出门历练", "炼丹"]
# 用法提示:命令格式错误时的反馈文本
command-format = """
📜修仙指令:
@@ -19,6 +19,8 @@ command-format = """
乾坤袋
使用 物品名
服用 回气丹
出门历练
炼丹 物品 数量
突破 - 需要丹药
强行突破 - 不需要丹药
劫掠 - 抢劫其他门派弟子
@@ -49,6 +51,10 @@ buy_seconds = 5
gift_seconds = 10
points_to_stone_seconds = 10
# 副本与炼丹冷却
expedition_seconds = 1800
alchemy_seconds = 600
# 修为结算参数:基础速率(每小时),灵根乘数(名称:倍率)
[Xiuxian.cultivation]
base_rate_per_hour = 100
@@ -102,3 +108,26 @@ realm_key = "xiuxian:zset:leaderboard:realm"
[Xiuxian.points_exchange]
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("shop_seconds", 10),
"购买": rate_cfg.get("buy_seconds", 5),
"出售": rate_cfg.get("buy_seconds", 5),
"乾坤袋": rate_cfg.get("bag_seconds", 3),
"突破": rate_cfg.get("break_seconds", 60),
"强行突破": rate_cfg.get("force_break_seconds", 60),
@@ -300,6 +301,8 @@ class XiuxianPlugin(MessagePluginInterface):
"退出门派": 604800,
"积分购石": 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", {})
@@ -329,6 +332,38 @@ class XiuxianPlugin(MessagePluginInterface):
except Exception as 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", {})
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)
if cmd == "购买":
return await self._cmd_buy(bot, sender, roomid, content)
if cmd == "出售":
return await self._cmd_sell(bot, sender, roomid, content)
if cmd == "乾坤袋":
return await self._cmd_bag(bot, sender, roomid)
if cmd in ("使用", "服用"):
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 == "突破":
return await self._cmd_breakthrough(bot, sender, roomid)
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("赠与 目标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)
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]:
player = self._get_player(sender, roomid or "")
if not player:
@@ -1023,6 +1105,82 @@ class XiuxianPlugin(MessagePluginInterface):
self._rate_set(sender, roomid or "", "背包")
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]:
item_name = content.strip()
if not item_name:
@@ -1117,6 +1275,66 @@ class XiuxianPlugin(MessagePluginInterface):
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]:
player = self._get_player(sender, roomid or "")
if not player: