提交,加入了出门历练功能
This commit is contained in:
@@ -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"
|
||||
]
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user