def recover(self, update: Update, context: CallbackContext) -> bool: """将重伤患者的状态恢复。使用回复或者`@username`作为参数来选择对象恢复。 回复的优先级高于参数。""" kp = self.forcegetplayer(update) gp = self.forcegetgroup(update) if gp.game is None: return self.errorInfo("没有进行中的游戏", True) if kp != gp.kp: return self.errorInfo("没有权限", True) rppl = self.getreplyplayer(update) if rppl is None: if len(context.args) == 0: return self.errorInfo("使用回复或@username指定恢复者") if not isint(context.args[0]) or int(context.args[0]) < 0: return self.errorInfo("参数无效", True) rppl = self.getplayer(int(context.args[0])) if rppl is None: return self.errorInfo("玩家无效") card = self.findcardfromgame(gp.game, rppl) if card is None: return self.errorInfo("找不到该玩家的卡。") if card.status != STATUS_SERIOUSLYWOUNDED: return self.errorInfo("该角色没有重伤") card.status = STATUS_ALIVE self.reply("角色已恢复") card.write() return True
def textpassjob(self, update: Update) -> bool: t = update.message.text.split() if getmsgfromid(update) != ADMIN_ID or (t[0] != "jobcomfirm" and t[0] != "jobreject"): self.botchat(update) return if len(t) < 2 or not isint(t[1]): return self.errorInfo("参数无效") plid = int(t[1]) if plid not in self.addjobrequest: return self.errorInfo("没有该id的职业新增申请") self.popOP(ADMIN_ID) if t[0] == "jobcomfirm": self.joblist[self.addjobrequest[plid] [0]] = self.addjobrequest[plid][1] with open(PATH_JOBDICT, 'w', encoding='utf-8') as f: json.dump(self.joblist, f, indent=4, ensure_ascii=False) self.reply(plid, "您的新增职业申请已通过。") else: self.reply(plid, "您的新增职业申请没有通过。") return True
def kill(self, update: Update, context: CallbackContext) -> bool: """使角色死亡。使用回复或者`@username`作为参数来选择对象撕卡。 回复的优先级高于参数。""" kp = self.forcegetplayer(update) gp = self.forcegetgroup(update) if gp.game is None: return self.errorInfo("没有进行中的游戏", True) if kp != gp.kp: return self.errorInfo("没有权限", True) rppl = self.getreplyplayer(update) if rppl is None: if len(context.args) == 0: return self.errorInfo("使用回复或@username指定对象") if not isint(context.args[0]) or int(context.args[0]) < 0: return self.errorInfo("参数无效", True) rppl = self.getplayer(int(context.args[0])) if rppl is None: return self.errorInfo("玩家无效") card = self.findcardfromgame(gp.game, rppl) if card is None: return self.errorInfo("找不到该玩家的卡。") if card.status == STATUS_DEAD: return self.errorInfo("角色已死亡") card.status = STATUS_DEAD self.reply("已撕卡") card.write() return True
def modify(self, update: Update, context: CallbackContext) -> bool: """强制修改某张卡某个属性的值。 需要注意可能出现的问题,使用该指令前,请三思。 `/modify --cardid --arg --value (game)`: 修改id为cardid的卡的value,要修改的参数是arg。 带game时修改的是游戏内卡片数据,不指明时默认游戏外 (对于游戏中与游戏外卡片区别,参见 `/help startgame`)。 修改对应卡片的信息必须要有对应的KP权限,或者是BOT的管理者。 如果要修改主要技能点和兴趣技能点,请使用`mainpoints`, `intpoints`作为`arg`,而不要使用points。 id, playerid, groupid这三个属性不可以修改。 想要修改id,请使用指令 `/changeid --cardid --newid` (参考`/help changeid`)。 想要修改所属群,使用指令 `/changegroup --cardid --newgroupid` (参考`/help changegroup`)。""" pl = self.forcegetplayer(update) if not self.searchifkp(pl) and pl.id != ADMIN_ID: return self.errorInfo("没有权限", True) # need 3 args, first: card id, second: attrname, third: value if len(context.args) < 3: return self.errorInfo("需要至少3个参数", True) card_id = context.args[0] if not isint(card_id) or int(card_id) < 0: return self.errorInfo("无效ID", True) card_id = int(card_id) if len(context.args) > 3 and context.args[3] == "game": card = self.getgamecard(card_id) rttext = "修改了游戏内的卡片:\n" else: card = self.getcard(card_id) rttext = "修改了游戏外的卡片:\n" if card is None: return self.errorInfo("找不到这张卡") if not self.checkaccess(pl, card) & CANMODIFY: return self.errorInfo("没有权限", True) try: if context.args[1] == "mainpoints": ans, ok = card.skill.modify("points", context.args[2]) elif context.args[1] == "intpoints": ans, ok = card.interest.modify("points", context.args[2]) else: ans, ok = card.modify(context.args[1], context.args[2]) except TypeError as e: return self.errorInfo(str(e)) if not ok: return self.errorInfo("修改失败。" + ans) rttext += context.args[1] + "从" + ans + "变为" + context.args[2] self.reply(rttext) return True
def switch(self, update: Update, context: CallbackContext): """切换目前操作的卡。 注意,这不是指kp在游戏中的多张卡之间切换,如果kp要切换游戏中骰骰子的卡,请参见指令`/switchgamecard`。 玩家只能修改目前操作的卡的基本信息,例如:年龄、性别、背景、技能点数等。 `/switch`:生成按钮来切换卡。 `/switch --cdid`切换至id为`cdid`的卡。""" if isgroup(update): return self.errorInfo("对bot私聊来切换卡。") pl = self.forcegetplayer(update) if len(pl.cards) == 0: return self.errorInfo("你没有任何卡。") if len(pl.cards) == 1: if pl.controlling is not None: return self.errorInfo("你只有一张卡,无需切换。") for card in pl.cards.values(): pl.controlling = card break pl.write() self.reply(f"你只有一张卡,自动控制这张卡。现在操作的卡:{pl.controlling.getname()}") return True if len(context.args) > 0: if not isint(context.args[0]): return self.errorInfo("输入无效。") cdid = int(context.args[0]) if cdid < 0: return self.errorInfo("卡片id为正数。") if cdid not in pl.cards: return self.errorInfo("找不到这个id的卡。") pl.controlling = pl.cards[cdid] pl.write() self.reply(f"现在操作的卡:{pl.controlling.getname()}") return True # 多个选项。创建按钮 rtbuttons = [[]] for card in pl.cards.values(): if len(rtbuttons[len(rtbuttons) - 1]) == 4: rtbuttons.append([]) rtbuttons[len(rtbuttons) - 1].append( InlineKeyboardButton(card.getname(), callback_data="switch " + str(card.id))) rp_markup = InlineKeyboardMarkup(rtbuttons) self.reply("请选择要切换控制的卡:", reply_markup=rp_markup) self.workingMethod[self.lastchat] = BUTTON_SWITCH # 交给按钮来完成 return True
def textsetage(self, update: Update) -> bool: text = update.message.text plid = getchatid(update) if not isint(text): return self.errorInfo("输入无效,请重新输入") cardi = self.findcard(plid) if not cardi: self.popOP(plid) return self.errorInfo("找不到卡") return (bool(self.popOP(plid)) or True) if self.cardsetage( update, cardi, int(text)) else False
def cardtransfer(self, update: Update, context: CallbackContext) -> bool: """转移卡片所有者。格式为 `/cardtransfer --cardid --playerid`:将卡转移给playerid。 回复某人`/cardtransfer --cardid`:将卡转移给被回复的人。要求参数有且仅有一个。 只有卡片拥有者或者KP有权使用该指令。 如果对方不是KP且对方已经在本群有卡,则无法转移。""" if len(context.args) == 0: return self.errorInfo("需要参数", True) if len(context.args) == 1 and self.getreplyplayer(update) is None: return self.errorInfo("参数不足", True) if not isint(context.args[0]) or (len(context.args) > 1 and not isint(context.args[1])): return self.errorInfo("参数无效", True) if int(context.args[0]) < 0 or (len(context.args) > 1 and int(context.args[1]) < 0): return self.errorInfo("负数参数无效", True) cdid = int(context.args[0]) card = self.getcard(cdid) if card is None: return self.errorInfo("找不到这张卡") operationer = self.forcegetplayer(update) if len(context.args) == 1: tpl: Player = self.getreplyplayer(update) else: tpl = self.forcegetplayer(int(context.args[1])) if not self.checkaccess(operationer, card) & (OWNCARD | CANMODIFY): return self.errorInfo("没有权限", True) if tpl != card.group.kp: for c in tpl.cards.values(): if c.group == card.group: return self.errorInfo("目标玩家已经在对应群有一张卡了") # 开始处理 self.atcardtransfer(update.message, cdid, tpl) return True
def textnewcard(self, update: Update, cdid: int = -1) -> bool: text = update.message.text pl = self.forcegetplayer(update) if not isint(text) or int(text) >= 0: return self.errorInfo("无效群id。如果你不知道群id,在群里发送 /getid 获取群id。") gpid = int(text) self.popOP(pl.id) if self.hascard(pl.id, gpid) and self.forcegetgroup(gpid).kp != pl: return self.errorInfo("你在这个群已经有一张卡了!") return self.getnewcard(update.message.message_id, gpid, pl.id, cdid)
def deletemsg(self, update: Update, context: CallbackContext) -> bool: """用于删除消息,清空当前对话框中没有用的消息。 bot可以删除任意私聊消息,无论是来自用户还是bot。 如果是群内使用该指令,需要管理员或KP权限, 以及bot是管理员,此时可以删除群内的任意消息。 当因为各种操作产生了过多冗杂消息的时候,使用 `/delmsg --msgnumber`将会删除:delmsg指令的消息 以及该指令上面的msgnumber条消息。例如: `/delmsg 2`将删除包含delmsg指令在内的3条消息。 没有参数的时候,`/delmsg`默认删除指令和指令的上一条消息。 因为要进行连续的删除请求,删除的时间会稍微有些滞后, 请不要重复发送该指令,否则可能造成有用的消息丢失。 如果感觉删除没有完成,请先随意发送一条消息来拉取删除情况, 而不是继续用`/delmsg`删除。""" delnum = 1 chatid = getchatid(update) if isgroup(update) and not self.isadmin(self.lastchat, BOT_ID): return self.errorInfo("Bot没有管理权限") if isgroup(update) and self.checkaccess(self.forcegetplayer(update), self.forcegetgroup(update)) & (GROUPKP | GROUPADMIN) == 0: return self.errorInfo("没有权限", True) if len(context.args) >= 1: if not isint(context.args[0]) or int(context.args[0]) <= 0: return self.errorInfo("参数错误", True) delnum = int(context.args[0]) if delnum > 10: return self.errorInfo("一次最多删除10条消息") lastmsgid = self.lastmsgid while delnum >= 0: # 这是因为要连同delmsg指令的消息也要删掉 if lastmsgid < -100: break try: context.bot.delete_message( chat_id=chatid, message_id=lastmsgid) except Exception as e: if str(e).find("can't be deleted for everyone") != -1: self.errorInfo("消息删除失败,发送时间较久的消息无法删除") break lastmsgid -= 1 else: delnum -= 1 lastmsgid -= 1 update.effective_chat.send_message("删除完成").delete() return True
def changeid(self, update: Update, context: CallbackContext) -> bool: """修改卡片id。卡片的所有者或者KP均有使用该指令的权限。 指令格式: `/changeid --cardid --newid` 如果`newid`已经被占用,则指令无效。 这一行为将同时改变游戏内以及游戏外的卡id。""" if len(context.args) < 2: return self.errorInfo("至少需要两个参数。") if not isint(context.args[0]) or not isint(context.args[1]): return self.errorInfo("参数无效", True) oldid = int(context.args[0]) newid = int(context.args[1]) if newid < 0: return self.errorInfo("卡id不能为负数", True) if newid == oldid: return self.errorInfo("前后id相同", True) if newid in self.allids: return self.errorInfo("该ID已经被占用") card = self.getcard(oldid) if card is None: return self.errorInfo("找不到该ID对应的卡") pl = self.forcegetplayer(update) if not self.checkaccess(pl, card) & (OWNCARD | CANMODIFY): return self.errorInfo("没有权限") # 开始处理 self.atidchanging(update.message, oldid, newid) return True
def transferkp(self, update: Update, context: CallbackContext) -> bool: """转移KP权限,只有群管理员可以使用这个指令。 当前群没有KP时或当前群KP为管理员时,无法使用。 `/transferkp --kpid`:将当前群KP权限转移到某个群成员。 如果指定的`kpid`不在群内则无法设定。 `/transferkp`:将当前群KP权限转移到自身。 `/trasferkp`(reply to someone):将kp权限转移给被回复者。""" if isprivate(update): return self.errorInfo("发送群消息强制转移KP权限") gp = self.getgp(update) pl = self.getplayer(update) f = self.checkaccess(pl, gp) if not f & GROUPADMIN: return self.errorInfo("没有权限", True) if gp.kp is None: return self.errorInfo("没有KP", True) if self.checkaccess(gp.kp, gp) & GROUPADMIN: return self.errorInfo("KP是管理员,无法转移") # 获取newkp newkpid: int if len(context.args) != 0: if not isint(context.args[0]): return self.errorInfo("参数需要是整数", True) newkp = self.forcegetplayer(int(context.args[0])) else: t = self.getreplyplayer(update) newkp = t if t is not None else self.forcegetplayer(update) if newkp == gp.kp: return self.errorInfo("原KP和新KP相同", True) if not self.changeKP(gp, newkp): return self.errorInfo("程序错误:不符合添加KP要求,请检查代码") # 不应触发 return True
def setage(self, update: Update, context: CallbackContext): if isgroup(update): return self.errorInfo("发送私聊消息设置年龄。", True) pl = self.forcegetplayer(update) card = pl.controlling if card is None: return self.errorInfo("找不到卡。") if card.info.age >= 17 and card.info.age <= 99: return self.errorInfo("已经设置过年龄了。") if len(context.args) == 0: self.reply("请输入年龄:") self.addOP(getchatid(update), "setage") return True age = context.args[0] if not isint(age): return self.errorInfo("输入无效") age = int(age) return self.cardsetage(update, card, age)
def delcard(self, update: Update, context: CallbackContext) -> bool: """KP才能使用该指令,删除一张卡片。一次只能删除一张卡。 `/delcard --cardid`:删除id为cardid的卡。""" if len(context.args) == 0: return self.errorInfo("需要卡id作为参数", True) if not isint(context.args[0]) or int(context.args[0]) < 0: return self.errorInfo("参数无效", True) cdid = int(context.args[0]) card = self.getcard(cdid) if card is None: return self.errorInfo("找不到对应id的卡") kp = self.forcegetplayer(update) if not self.checkaccess(kp, card) & CANMODIFY: return self.errorInfo("没有权限", True) # 开始处理 self.reply( f"请确认是否删除卡片\n姓名:{card.getname()}\n如果确认删除,请回复:确认。否则,请回复其他任何文字。") self.addOP(getchatid(update), "delcard "+context.args[0]) return True
def show(self, update: Update, context: CallbackContext) -> bool: """显示目前操作中的卡片的信息。私聊时默认显示游戏外的卡,群聊时优先显示游戏内的卡。 (如果有多张卡,用`/switch`切换目前操作的卡。) `/show`:显示最基础的卡片信息; `/show card`:显示当前操作的整张卡片的信息; `/show --attrname`:显示卡片的某项具体属性。 (回复某人消息)`/show card或--attrname`:同上,但显示的是被回复者的卡片的信息。 例如,`/show skill`显示主要技能, `/show interest`显示兴趣技能。 如果要显示主要技能点和兴趣技能点,请使用`mainpoints`, `intpoints`作为`arg`,而不要使用points。 如果当前卡中没有这个属性,则无法显示。 可以显示的属性例子: `STR`,`description`,`SAN`,`MAGIC`,`name`,`item`,`job`""" pl = self.forcegetplayer(update) rppl = self.getreplyplayer(update) rpcard: Optional[GameCard] = None if rppl is None and len(context.args) > 0: if isint(context.args[0]): rppl = self.getplayer(int(context.args[0])) if rppl is not None: context.args = context.args[1:] if rppl is not None: gp = self.forcegetgroup(update) rpcard = self.findcardfromgroup(rppl, gp) if rpcard is None: return self.errorInfo("该玩家在本群没有卡") card = rpcard if rpcard is not None else None if card is None: if isgroup(update): gp = self.forcegetgroup(update) card = self.findcardfromgroup(pl, gp) if card is None: return self.errorInfo("请先在本群创建卡") else: card = pl.controlling if card is None: return self.errorInfo("请先创建卡,或者使用 /switch 选中一张卡") game = card.group.game if card.group.game is not None else card.group.pausedgame rttext = "" if game is not None and isgroup(update): if card.id in game.cards: rttext = "显示游戏中的卡:\n" card = game.cards[card.id] if rttext == "": rttext = "显示游戏外的卡:\n" if not self.checkaccess(pl, card) & CANREAD: return self.errorInfo("没有权限") if card.type != PLTYPE and isgroup(update): return self.errorInfo("非玩家卡片不可以在群内显示") if len(context.args) == 0: self.reply(card.basicinfo()) return True if context.args[0] == "card": self.reply(str(card)) return True if context.args[0] == "mainpoints": ans = card.skill.show("points") elif context.args[0] == "intpoints": ans = card.interest.show("points") elif context.args[0] == "points": return self.errorInfo("请用mainpoints或intpoints来显示") else: ans = card.show(context.args[0]) if ans == "找不到该属性": return self.errorInfo("找不到该属性") if ans == "": self.reply(rttext + "无") else: self.reply(rttext + ans) return True
def setrule(self, update: Update, context: CallbackContext) -> bool: """设置游戏的规则。 一个群里游戏有自动生成的默认规则,使用本指令可以修改这些规则。 `/setrule --args`修改规则。`--args`格式如下: `rulename1:str --rules1:List[int] rulename2:str --rule2:List[int] ...` 一次可以修改多项规则。 有可能会出现部分规则设置成功,但部分规则设置失败的情况, 查看返回的信息可以知道哪些部分已经成功修改。 规则的详细说明: skillmax:接收长度为3的数组,记为r。`r[0]`是一般技能上限, `r[1]`是个别技能的上限,`r[2]`表示个别技能的个数。 skillmaxAged:年龄得到的技能上限增加设定。 接收长度为4的数组,记为r。`r[0]`至`r[2]`同上, 但仅仅在年龄大于`r[3]`时开启该设定。`r[3]`等于100代表不开启该设定。 skillcost:技能点数分配时的消耗。接收长度为偶数的数组,记为r。 若i为偶数(或0),`r[i]`表示技能点小于`r[i+1]`时, 需要分配`r[i]`点点数来获得1点技能点。r的最后一项必须是100。 例如:`r=[1, 80, 2, 100]`,则从10点升至90点需要花费`1*70+2*10=90`点数。 greatsuccess:大成功范围。接收长度为4的数组,记为r。 `r[0]-r[1]`为检定大于等于50时大成功范围,否则是`r[2]-r[3]`。 greatfail:大失败范围。同上。""" if isprivate(update): return self.errorInfo("请在群内用该指令设置规则") gp = self.forcegetgroup(update) if not self.isfromkp(update): return self.errorInfo("没有权限", True) if len(context.args) == 0: return self.errorInfo("需要参数", True) gprule = gp.rule ruledict: Dict[str, List[int]] = {} i = 0 while i < len(context.args): j = i+1 tplist: List[int] = [] while j < len(context.args): if isint(context.args[j]): tplist.append(int(context.args[j])) j += 1 else: break ruledict[context.args[i]] = tplist i = j del i, j msg, ok = gprule.changeRules(ruledict) if not ok: return self.errorInfo(msg) self.reply(msg) return True
def changegroup(self, update: Update, context: CallbackContext) -> bool: """修改卡片的所属群。 一般只用于卡片创建时输入了错误的群id。 比较特殊的情形: 如果需要将某个群的所有卡片全部转移到另一个群, 第一个参数写为负数的`groupid`即可。这一操作需要原群的kp权限。 在原群进行游戏时,这个指令无效。 指令格式: `/changegroup --groupid/--cardid --newgroupid` """ if len(context.args) < 2: return self.errorInfo("至少需要2个参数", True) if not isint(context.args[0]) or not isint(context.args[1]): return self.errorInfo("参数无效", True) newgpid = int(context.args[1]) if newgpid >= 0: return self.errorInfo("转移的目标群id应该是负数", True) if int(context.args[0]) < 0: # 转移全部群卡片 ogpid = int(context.args[0]) oldgp = self.getgp(ogpid) if oldgp is None or len(oldgp.cards) == 0: return self.errorInfo("该群没有卡") newgp = self.forcegetgroup(newgpid) kp = self.forcegetgroup(update) if ((kp != oldgp.kp and oldgp.id != -1) or kp != newgp.kp) and kp.id != ADMIN_ID: return self.errorInfo("没有权限", True) if oldgp.getexistgame() is not None: return self.errorInfo("游戏进行中,无法转移") # 检查权限通过 numofcards = len(oldgp.cards) self.changecardgpid(ogpid, newgpid) self.reply("操作成功,已经将" + str(numofcards) + "张卡片从群:" + str(ogpid) + "移动到群:" + str(newgpid)) return True # 转移一张卡片 cdid = int(context.args[0]) card = self.getcard(cdid) if card is None: return self.errorInfo("找不到这个id的卡片", True) oldgp = card.group if oldgp.getexistgame(): return self.errorInfo("游戏正在进行,无法转移") pl = self.forcegetplayer(update) if not self.checkaccess(pl, card) & (OWNCARD | CANMODIFY): return self.errorInfo("没有权限") # 开始执行 card = self.popcard(cdid) self.addcardoverride(card, newgpid) cardname = card.getname() self.reply("操作成功,已经将卡片" + cardname + "从群:" + str(oldgp.id) + "移动到群:" + str(newgpid)) return True
def checknonnegativeint(update, context: 'CallbackContext', *args, **kwargs) -> bool: index = kwargs['index'] return len(context.args) > index and isint( context.args[index]) and int(context.args[index] >= 0)
def roll(self, update: Update, context: CallbackContext): """基本的骰子功能。 只接受第一个空格前的参数`dicename`。 `dicename`可能是技能名、属性名(仅限游戏中),可能是`3d6`,可能是`1d4+2d10`。 骰子环境可能是游戏中,游戏外。 `/roll`:默认1d100。 `/roll --mdn`骰一个mdn的骰子。 `/roll --test`仅限游戏中可以使用。对`test`进行一次检定。 例如,`/roll 力量`会进行一次STR检定。 `/roll 射击`进行一次射击检定。 检定心理学时结果只会发送给kp。 如果要进行一个暗骰,可以输入 `/roll 暗骰`进行一次检定为50的暗骰,或者 `/roll 暗骰60`进行一次检定为60的暗骰。""" if len(context.args) == 0: self.reply(commondice("1d100")) # 骰1d100 return True dicename = context.args[0] if isprivate(update): self.reply(commondice(dicename)) return True gp = self.forcegetgroup(update) # 检查输入参数是不是一个基础骰子,如果是则直接计算骰子 if gp.game is None or dicename.find('d') >= 0 or isint(dicename): if isint(dicename) and int(dicename) > 0: dicename = "1d" + dicename rttext = commondice(dicename) if rttext == "Invalid input.": return self.errorInfo("输入无效") self.reply(rttext) return True if gp.game is None: return self.errorInfo("输入无效") # 确认不是基础骰子的计算,转到卡检定 # 获取临时检定 tpcheck, gp.game.tpcheck = gp.game.tpcheck, 0 if tpcheck != 0: gp.write() pl = self.forcegetplayer(update) # 获取卡 if pl != gp.kp: gamecard = self.findcardfromgame(gp.game, pl) else: gamecard = gp.game.kpctrl if gamecard is None: return self.errorInfo("请用 /switchgamecard 切换kp要用的卡") if not gamecard: return self.errorInfo("找不到游戏中的卡。") if gamecard.status == STATUS_DEAD: return self.errorInfo("角色已死亡") if gamecard.status == STATUS_PERMANENTINSANE: return self.errorInfo("角色已永久疯狂") if dicename.encode('utf-8').isalpha(): dicename = dicename.upper() # 找卡完成,开始检定 test = 0 if dicename == "侦察": dicename = "侦查" if dicename in gamecard.skill.allskills(): test = gamecard.skill.get(dicename) elif dicename in gamecard.interest.allskills(): test = gamecard.interest.get(dicename) elif dicename == "母语": test = gamecard.data.EDU elif dicename == "闪避": test = gamecard.data.DEX // 2 elif dicename in gamecard.data.alldatanames: test = gamecard.data.__dict__[dicename] elif dicename == "力量": dicename = "STR" test = gamecard.data.STR elif dicename == "体质": dicename = "CON" test = gamecard.data.CON elif dicename == "体型": dicename = "SIZ" test = gamecard.data.SIZ elif dicename == "敏捷": dicename = "DEX" test = gamecard.data.DEX elif dicename == "外貌": dicename = "APP" test = gamecard.data.APP elif dicename == "智力" or dicename == "灵感": dicename = "INT" test = gamecard.data.INT elif dicename == "意志": dicename = "POW" test = gamecard.data.POW elif dicename == "教育": dicename = "EDU" test = gamecard.data.EDU elif dicename == "幸运": dicename = "LUCK" test = gamecard.data.LUCK elif dicename in self.skilllist: test = self.skilllist[dicename] elif dicename[:2] == "暗骰" and (isint(dicename[2:]) or len(dicename) == 2): if len(dicename) != 2: test = int(dicename[2:]) else: test = 50 else: # HIT BAD TRAP return self.errorInfo("输入无效") # 将所有检定修正相加 test += gamecard.tempstatus.GLOBAL if gamecard.hasstatus(dicename): test += gamecard.getstatus(dicename) test += tpcheck if test < 1: test = 1 testval = dicemdn(1, 100)[0] rttext = dicename + " 检定/出目:" + str(test) + "/" + str(testval) + " " greatsuccessrule = gp.rule.greatsuccess greatfailrule = gp.rule.greatfail if (test < 50 and testval >= greatfailrule[2] and testval <= greatfailrule[3]) or ( test >= 50 and testval >= greatfailrule[0] and testval <= greatfailrule[1]): rttext += "大失败" elif (test < 50 and testval >= greatsuccessrule[2] and testval <= greatsuccessrule[3]) or ( test >= 50 and testval >= greatsuccessrule[0] and testval <= greatsuccessrule[1]): rttext += "大成功" elif testval > test: rttext += "失败" elif testval > test // 2: rttext += "普通成功" elif testval > test // 5: rttext += "困难成功" else: rttext += "极难成功" if dicename == "心理学" or dicename[:2] == "暗骰": if gp.kp is None: return self.errorInfo("本群没有KP,请先添加一个KP再试!") self.reply(dicename + " 检定/出目:" + str(test) + "/???") self.sendto(gp.kp, rttext) else: self.reply(rttext) return True
def sancheck(self, update: Update, context: CallbackContext) -> bool: """进行一次sancheck,格式如下: `/sancheck checkpass/checkfail`""" if isprivate(update): return self.errorInfo("在游戏中才能进行sancheck。") if len(context.args) == 0: return self.errorInfo("需要参数", True) checkname = context.args[0] if checkname.find("/") == -1: return self.errorInfo("将成功和失败的扣除点数用/分开。") checkpass, checkfail = checkname.split(sep='/', maxsplit=1) if not isadicename(checkpass) or not isadicename(checkfail): return self.errorInfo("无效输入") gp = self.forcegetgroup(update) if gp.game is None: return self.errorInfo("找不到游戏", True) pl = self.forcegetplayer(update) # KP 进行 if pl == gp.kp: card1 = gp.game.kpctrl if card1 is None: return self.errorInfo("请先用 /switchgamecard 切换到你的卡") else: # 玩家进行 card1 = self.findcardfromgame(gp.game, pl) if card1 is None: return self.errorInfo("找不到卡。") rttext = "理智:检定/出目 " sanity = card1.attr.SAN check = dicemdn(1, 100)[0] rttext += str(sanity) + "/" + str(check) + " " greatfailrule = gp.rule.greatfail if (sanity < 50 and check >= greatfailrule[2] and check <= greatfailrule[3]) or ( sanity >= 50 and check >= greatfailrule[0] and check <= greatfailrule[1]): # 大失败 rttext += "大失败" anstype = "大失败" elif check > sanity: # check fail rttext += "失败" anstype = "失败" else: rttext += "成功" anstype = "" rttext += "\n损失理智:" sanloss, m, n = 0, 0, 0 if anstype == "大失败": if isint(checkfail): sanloss = int(checkfail) else: t = checkfail.split("+") for tt in t: if isint(tt): sanloss += int(tt) else: ttt = tt.split('d') sanloss += int(ttt[0]) * int(ttt[1]) elif anstype == "失败": if isint(checkfail): sanloss = int(checkfail) else: m, n = checkfail.split("d", maxsplit=1) m, n = int(m), int(n) sanloss = int(sum(dicemdn(m, n))) else: if isint(checkpass): sanloss = int(checkpass) else: m, n = checkpass.split("d", maxsplit=1) m, n = int(m), int(n) sanloss = int(sum(dicemdn(m, n))) card1.attr.SAN -= sanloss rttext += str(sanloss) + "\n" if card1.attr.SAN <= 0: card1.attr.SAN = 0 card1.status = STATUS_PERMANENTINSANE rttext += "陷入永久疯狂,快乐撕卡~\n" elif sanloss > (card1.attr.SAN + sanloss) // 5: rttext += "一次损失五分之一以上理智,进入不定性疯狂状态。\n" # TODO 处理角色的疯狂状态 elif sanloss >= 5: rttext += "一次损失5点或以上理智,可能需要进行智力(灵感)检定。\n" self.reply(rttext) card1.write() return True
def discard(self, update: Update, context: CallbackContext) -> bool: """该指令用于删除角色卡。 通过识别卡中`discard`是否为`True`来判断是否可以删除这张卡。 如果`discard`为`False`,需要玩家向KP申请,让KP修改`discard`属性为`True`。 指令格式如下: `/discard (--groupid_1/--cardid_1 --groupid_2/--cardid_2 ...)`。 可以一次输入多个群或卡id来批量删除。 无参数时,如果只有一张卡可以删除,自动删除那张卡。 否则,会创建一组按钮来让玩家选择要删除哪张卡。 有参数时, 若其中一个参数为群id(负数),则删除该群内所有可删除的卡。 若其中一个参数为卡id,删除对应的那张卡。 找不到参数对应的卡时,该参数会被忽略。""" if isgroup(update): return self.errorInfo("发送私聊消息删除卡。") pl = self.getplayer(update) # 发送者 if pl is None: return self.errorInfo("找不到可删除的卡。") if len(context.args) > 0: # 先处理context.args if any(not isint(x) for x in context.args): return self.errorInfo("参数需要是整数") nargs = list(map(int, context.args)) discards = self.findDiscardCardsWithGpidCdid(pl, nargs) # 求args提供的卡id与可删除的卡id的交集 if len(discards) == 0: # 交集为空集 return self.errorInfo("输入的(群/卡片)ID均无效。") if len(discards) == 1: card = discards[0] rttext = "删除卡:"+str(card.getname()) rttext += "删除操作不可逆。" self.reply(rttext) else: self.reply( "删除了"+str(len(discards))+"张卡片。\n删除操作不可逆。") for card in discards: self.cardpop(card) return True # 计算可以discard的卡有多少 discardgpcdTupleList = self.findAllDiscardCards(pl) if len(discardgpcdTupleList) > 1: # 创建按钮,接下来交给按钮完成 rtbuttons: List[List[InlineKeyboardButton]] = [[]] for card in discardgpcdTupleList: if len(rtbuttons[len(rtbuttons)-1]) == 4: rtbuttons.append([]) cardname = card.getname() rtbuttons[len(rtbuttons)-1].append(InlineKeyboardButton(cardname, callback_data="discard "+str(card.id))) rp_markup = InlineKeyboardMarkup(rtbuttons) self.reply("请点击要删除的卡片:", reply_markup=rp_markup) self.workingMethod[self.lastchat] = BUTTON_DISCARD return True if len(discardgpcdTupleList) == 1: card = discardgpcdTupleList[0] rttext = "删除卡:"+card.getname() rttext += "\n删除操作不可逆。" self.reply(rttext) self.cardpop(card) return True # 没有可删除的卡 return self.errorInfo("找不到可删除的卡。")
def showcard(self, update: Update, context: CallbackContext) -> bool: """显示某张卡的信息。 `/showcard --cardid (card/--attrname)`: 显示卡id为`cardid`的卡片的信息。 如果第二个参数是`card`,显示整张卡;否则,显示这一项数据。 如果第二个参数不存在,显示卡片基本信息。 群聊时使用该指令,优先查看游戏内的卡片。 显示前会检查发送者是否有权限显示这张卡。在这些情况下,无法显示卡: 群聊环境:显示非本群的卡片,或者显示本群的type不为PL的卡片; 私聊环境:显示没有查看权限的卡片。""" if len(context.args) == 0: return self.errorInfo("需要参数") if not isint(context.args[0]) or int(context.args[0]) < 0: return self.errorInfo("卡id参数无效", True) cdid = int(context.args[0]) rttext: str = "" cardi: Optional[GameCard] = None if isgroup(update): cardi = self.getgamecard(cdid) if cardi is not None: rttext = "显示游戏内的卡片\n" if cardi is None: cardi = self.getcard(cdid) if cardi is None: return self.errorInfo("找不到这张卡") if rttext == "": rttext = "显示游戏外的卡片\n" # 检查是否有权限 if isprivate(update): pl = self.forcegetplayer(update) if self.checkaccess(pl, cardi) & CANREAD == 0: return self.errorInfo("没有权限") else: if (cardi.groupid != -1 and cardi.group != self.forcegetgroup(update)) or cardi.type != PLTYPE: return self.errorInfo("没有权限", True) # 开始处理 if len(context.args) >= 2: if context.args[1] == "card": self.reply(rttext + str(cardi)) else: ans = cardi.show(context.args[1]) if ans == "找不到该属性": return self.errorInfo(ans) self.reply(rttext + ans) return True # 显示基本属性 self.reply(rttext + cardi.basicinfo()) return True
def showkp(self, update: Update, context: CallbackContext) -> bool: """这一指令是为KP设计的。不能在群聊中使用。 `/showkp game --groupid`: 显示发送者在某个群主持的游戏中所有的卡 `/showkp card`: 显示发送者作为KP控制的所有卡 `/showkp group --groupid`: 显示发送者是KP的某个群内的所有卡""" if isgroup(update): return self.errorInfo("使用该指令请发送私聊消息", True) if len(context.args) == 0: return self.errorInfo("需要参数") arg = context.args[0] if arg == "group": kp = self.forcegetplayer(update) # args[1] should be group id if len(context.args) < 2: return self.errorInfo("需要群ID") gpid = context.args[1] if not isint(gpid) or int(gpid) >= 0: return self.errorInfo("无效ID") gpid = int(gpid) if gpid < 0 or self.getgp(gpid) is None or self.getgp( gpid).kp != kp: return self.errorInfo("这个群没有卡或没有权限") gp: Group = self.getgp(gpid) ans: List[GameCard] = [] for card in kp.cards.values(): if card.group != gp: continue ans.append(card) if len(ans) == 0: return self.errorInfo("该群没有你的卡") for i in ans: self.reply(str(i)) time.sleep(0.2) return True if arg == "game": kp = self.forcegetplayer(update) if len(context.args) < 2: return self.errorInfo("需要群ID") gpid = context.args[1] if not isint(gpid) or int(gpid) >= 0: return self.errorInfo("无效群ID") gp = self.getgp(gpid) if gp is None or (gp.game is None and gp.pausedgame is None): return self.errorInfo("没有找到游戏") if gp.kp != kp: return self.errorInfo("你不是这个群的kp") game = gp.game if gp.game is not None else gp.pausedgame hascard = False for i in game.cards.values(): if i.player != kp: continue hascard = True self.reply(str(i)) time.sleep(0.2) return True if hascard else self.errorInfo("你没有控制的游戏中的卡") if arg == "card": kp = self.forcegetplayer(update) hascard = False for card in kp.cards.values(): if card.group.kp != kp: continue hascard = True self.reply(str(card)) time.sleep(0.2) return True if hascard else self.errorInfo("你没有控制NPC卡片") return self.errorInfo("无法识别的参数")
def addcard(self, update: Update, context: CallbackContext) -> bool: """使用已有信息添加一张卡片,模板使用的是NPC/怪物模板。指令格式如下: `/addcard --attr_1 --val_1 --attr_2 --val_2 …… --attr_n -- val_n`, 其中`attr`是卡的直接属性或子属性。 卡的属性只有三种类型的值:`int`, `str`, `bool`,其他类型暂不支持用本指令。 函数会自动判断对应的属性是什么类型,其中`bool`类型`attr`对应的`val`只能是`true`, `True`, `false`, `False`之一。 不可以直接添加tempstatus这个属性。 如果需要添加主要技能点数,用mainpoints作为`attr`,兴趣技能点则用intpoints,清不要使用points。 如果要添加特殊技能,比如怪物的技能,请令`attr`为`specialskill`,`val`为`特殊技能名:技能值`。 技能值是正整数,技能名和技能值用英文冒号分开。 `name`和背景信息不支持空格,如果要设置这一项信息,需要之后用`/setbkg`来修改,所以尽量不要用该指令设置背景信息。 如果遇到无法识别的属性,将无法创建卡片。 参数中,必须的`attr`之一为`groupid`,如果找不到`groupid`将无法添加卡片。 `playerid`会自动识别为发送者,无需填写`playerid`。 指令使用者是KP的情况下,才可以指定`playerid`这个属性,否则卡片无效。 给定`id`属性的话,在指定的卡id已经被占用的时候,会重新自动选取。""" if isgroup(update): return self.errorInfo("向我发送私聊消息来添加卡", True) if len(context.args) == 0: return self.errorInfo("需要参数") if (len(context.args)//2)*2 != len(context.args): self.reply("参数长度应该是偶数") t = templateNewCard() # 遍历args获取attr和val mem: List[str] = [] for i in range(0, len(context.args), 2): argname: str = context.args[i] if argname in mem: return self.errorInfo(argname+"属性重复赋值") mem.append(argname) argval = context.args[i+1] if argname == "specialskill": skillname, skillval = argval.split(":") if not isint(skillval) or int(skillval) <= 0: return self.errorInfo("技能值应该是正整数") t["skill"]["skills"][skillname] = int(skillval) continue if argname == "points": return self.errorInfo("points应指明是mainpoints还是intpoints") if argname == "mainpoints": argname = "points" dt = t["skill"] elif argname == "intpoints": argname = "points" dt = t["interest"] dt = findattrindict(t, argname) if not dt: # 可能是技能,否则返回 if argname in self.skilllist or argname == "母语" or argname == "闪避": if not isint(argval) or int(argval) <= 0: return self.errorInfo("技能值应该是正整数") dt: dict = t["skill"]["skills"] dt[argname] = 0 # 这一行是为了防止之后判断类型报错 else: return self.errorInfo("属性 "+argname+" 在角色卡模板中没有找到") if isinstance(dt[argname], dict): return self.errorInfo(argname+"是dict类型,不可直接赋值") if type(dt[argname]) is bool: if argval == "false" or argval == "False": argval = False elif argval == "true" or argval == "True": argval = True if not type(argval) is bool: return self.errorInfo(argname+"应该为bool类型") dt[argname] = argval elif type(dt[argname]) is int: if not isint(argval): return self.errorInfo(argname+"应该为int类型") dt[argname] = int(argval) else: dt[argname] = argval # 参数写入完成 # 检查groupid是否输入了 if t["groupid"] == 0: return self.errorInfo("需要groupid!") # 检查是否输入了以及是否有权限输入playerid pl = self.forcegetplayer(update) if not self.searchifkp(pl): if t["playerid"] != 0 and t["playerid"] != pl.id: return self.errorInfo("没有权限设置非自己的playerid") t["playerid"] = getchatid(update) else: if t["groupid"] not in pl.kpgroups and t["playerid"] != 0 and t["playerid"] != pl.id: return self.errorInfo("没有权限设置非自己的playerid") if t["playerid"] == 0: t["playerid"] = pl.id # 生成成功 card1 = GameCard(t) # 添加id if "id" not in context.args or card1.id < 0 or card1.id in self.allids: self.reply("输入了已被占用的id,或id未设置,或id无效。自动获取id") card1.id = self.getoneid() # 生成衍生数值 card1.generateOtherAttributes() # 卡检查 rttext = card1.check() if rttext != "": self.reply( "卡片添加成功,但没有通过开始游戏的检查。") self.reply(rttext) else: self.reply("卡片添加成功") return True if self.addonecard(card1) else self.errorInfo("卡id重复")
def newcard(self, update: Update, context: CallbackContext) -> bool: """随机生成一张新的角色卡。需要一个群id作为参数。 只接受私聊消息。 如果发送者不是KP,那么只能在一个群内拥有最多一张角色卡。 如果不知道群id,请先发送`/getid`到群里获取id。 `/newcard`提交创建卡请求,bot会等待你输入`groupid`。 `/newcard --groupid`新建一张卡片,绑定到`groupid`对应的群。 `/newcard --cardid`新建一张卡片,将卡片id设置为`cardid`,`cardid`必须是非负整数。 `/newcard --groupid --cardid`新建一张卡片,绑定到`groupid`对应的群的同时,将卡片id设置为`cardid`。 当指定的卡id已经被别的卡占用的时候,将自动获取未被占用的id。 当生成时有至少三项基础属性低于50时,可以使用`/discard`来放弃并删除这张角色卡。 创建新卡之后,当前控制卡片会自动切换到新卡,详情参见 `/help switch`。 角色卡说明 一张角色卡具有: `groupid`,`id`,`playerid`基本信息。 STR,CON,SIZ,DEX,APP,INT,EDU,LUCK基本属性; 职业、姓名、性别、年龄; 技能信息; 背景故事(描述,重要之人,重要之地,珍视之物,特质,受过的伤,恐惧之物,神秘学物品,第三类接触); 检定修正值; 物品,财产; 角色类型(PL,NPC); 是否可以被删除; 状态(存活,死亡,疯狂等)。""" gpid: int = None gp: Optional[Group] = None newcdid: Optional[int] = None if isgroup(update): # 先检查是否有该玩家信息 rtbutton = [[InlineKeyboardButton( text="跳转到私聊", callback_data="None", url="t.me/"+self.bot.username)]] rp_markup = InlineKeyboardMarkup(rtbutton) if self.getplayer(update) is None: self.reply("请先开启与bot的私聊", reply_markup=rp_markup) return True if len(context.args) > 0: if not isint(context.args[0]) or int(context.args[0]) < 0: return self.errorInfo("参数无效") gpid = getchatid(update) gp = self.forcegetgroup(gpid) if len(context.args) > 0: newcdid = int(context.args[0]) elif len(context.args) > 0: msg = context.args[0] if not isint(msg): return self.errorInfo("输入无效") if int(msg) >= 0: newcdid = int(msg) else: gpid = int(msg) gp = self.forcegetgroup(gpid) if len(context.args) > 1: if not isint(context.args[1]) or int(context.args[1]) < 0: return self.errorInfo("输入无效") newcdid = int(context.args[1]) if gp is None: self.reply( "准备创建新卡。\n如果你不知道群id,在群里发送 /getid 即可创建角色卡。\n你也可以选择手动输入群id,请发送群id:") if newcdid is None: self.addOP(getchatid(update), "newcard " + str(update.message.message_id)) else: self.addOP(getchatid(update), "newcard " + str(update.message.message_id)+" "+str(newcdid)) return True # 检查(pl)是否已经有卡 pl = self.forcegetplayer(update) plid = pl.id if self.hascard(plid, gpid) and pl != gp.kp: return self.errorInfo("你在这个群已经有一张卡了!") # 符合建卡条件,生成新卡 # gp is not None assert(gpid is not None) remsgid = None if isprivate(update): remsgid = update.message.message_id else: assert rp_markup self.reply("建卡信息已经私聊发送", reply_markup=rp_markup) return self.getnewcard(remsgid, gpid, plid, newcdid)
def switchgamecard(self, update: Update, context: CallbackContext): """用于KP切换游戏中进行对抗时使用的NPC卡片。 (仅限私聊时)`/switchgamecard --groupid`:创建按钮,让KP选择要用的卡。 (私聊群聊皆可)`/switchgamecard --cardid`:切换到id为cardid的卡并控制。""" if len(context.args) == 0: return self.errorInfo("需要参数") if not isint(context.args[0]): return self.errorInfo("参数无效") pl = self.forcegetplayer(update) iid = int(context.args[0]) if iid >= 0: cdid = iid if cdid not in pl.gamecards: return self.errorInfo("你没有这个id的游戏中的卡") card = pl.gamecards[cdid] game: GroupGame = card.group.game if card.group.game is not None else card.group.pausedgame assert (game is not None) if game.kp != pl: return self.errorInfo("你不是该卡对应群的kp") game.kpctrl = card self.reply("切换成功") game.write() return True gpid = iid if isgroup(update): return self.errorInfo("请直接指定要切换的卡id,或者向bot发送私聊消息切换卡!") gp = self.getgp(gpid) if gp is None: return self.errorInfo("找不到该群") game = gp.game if gp.game is not None else gp.pausedgame if game is None: return self.errorInfo("该群没有在进行游戏") if game.kp != pl: return self.errorInfo("你不是kp") rtbuttons = [[]] for card in game.cards.values(): if card.player != pl: continue if len(rtbuttons[len(rtbuttons) - 1]) == 4: rtbuttons.append([]) rtbuttons[len(rtbuttons) - 1].append( InlineKeyboardButton(card.getname(), callback_data="switchgamecard " + str(card.id))) rp_markup = InlineKeyboardMarkup(rtbuttons) self.reply("请选择要切换控制的卡:", reply_markup=rp_markup) self.workingMethod[self.lastchat] = BUTTON_SWITCHGAMECARD # 交给按钮来完成 return True
def hp(self, update: Update, context: CallbackContext) -> bool: """修改HP。KP通过回复某位PL消息并在回复消息中使用本指令即可修改对方卡片的HP。 回复自己的消息,则修改kp当前选中的游戏卡。 或者,也可以使用@用户名以及用玩家id的方法选中某名PL,但请不要同时使用回复和用户名。 使用范例: `/hp +1d3`:恢复1d3点HP。 `/hp -2`:扣除2点HP。 `/hp 10`:将HP设置为10。 `/hp @username 12`:将用户名为username的玩家HP设为12。 下面的例子是无效输入: `/hp 1d3`:无法将HP设置为一个骰子的结果,恢复1d3生命请在参数前加上符号`+`,扣除同理。 在生命变动的情况下,角色状态也会同步地变动。""" if isprivate(update): return self.errorInfo("游戏中才可以修改HP。") gp = self.forcegetgroup(update) kp = self.forcegetplayer(update) if gp.kp != kp: return self.errorInfo("没有权限", True) if len(context.args) == 0: return self.errorInfo("需要指定扣除的HP", True) chp: str = context.args[0] game = gp.game if game is None: return self.errorInfo("找不到进行中的游戏", True) rppl = self.getreplyplayer(update) if update.message.reply_to_message is not None: rpmsgid = update.message.reply_to_message.message_id else: rpmsgid = update.message.message_id if rppl is None: if len(context.args) < 2: return self.errorInfo("请用回复或@用户名的方式来选择玩家改变HP") if not isint(context.args[0]) or int(context.args[0]) < 0: return self.errorInfo("参数无效") rppl = self.getplayer(int(context.args[0])) if rppl is None: return self.errorInfo("指定的用户无效") chp = context.args[1] if rppl != kp: cardi = self.findcardfromgame(game, rppl) else: cardi = game.kpctrl if cardi is None: return self.errorInfo("找不到这名玩家的卡。") if chp[0] == "+" or chp[0] == "-": if len(chp) == 1: return self.errorInfo("参数无效", True) # 由dicecalculator()处理。减法时,检查可能的括号导致的输入错误 if chp[0] == '-' and chp[1] != '(' and (chp[1:].find('+') != -1 or chp[1:].find('-') != -1): return self.errorInfo("当第一个减号的后面是可计算的骰子,且存在加减法时,请在第一个符号之后使用括号") try: diceans = dicecalculator(chp[1:]) except Exception: return self.errorInfo("参数无效", True) if diceans < 0: return self.errorInfo("骰子的结果为0,生命值不修改") chp = chp[0]+str(diceans) else: # 直接修改生命为目标值的情形。不支持dicecalculator(),仅支持整数 if not isint(chp) or int(chp) > 100 or int(chp) < 0: return self.errorInfo("参数无效", True) if cardi.status == STATUS_DEAD: return self.errorInfo("该角色已死亡") originhp = cardi.attr.HP if chp[0] == "+": cardi.attr.HP += int(chp[1:]) elif chp[0] == "-": cardi.attr.HP -= int(chp[1:]) else: cardi.attr.HP = int(chp) hpdiff = cardi.attr.HP - originhp if hpdiff == 0: return self.errorInfo("HP不变,目前HP:"+str(cardi.attr.HP)) if hpdiff < 0: # 承受伤害描述。分类为三种状态 takedmg = -hpdiff if takedmg < cardi.attr.MAXHP//2: # 轻伤,若生命不降到0,不做任何事 if takedmg >= originhp: self.reply( text="HP归0,角色昏迷", reply_to_message_id=rpmsgid) elif takedmg > cardi.attr.MAXHP: self.reply( text="致死性伤害,角色死亡", reply_to_message_id=rpmsgid) cardi.status = STATUS_DEAD else: self.reply(text="角色受到重伤,请进行体质检定以维持清醒", reply_to_message_id=rpmsgid) cardi.status = STATUS_SERIOUSLYWOUNDED if originhp <= takedmg: self.reply( text="HP归0,进入濒死状态", reply_to_message_id=rpmsgid) cardi.status = STATUS_NEARDEATH if cardi.attr.HP < 0: cardi.attr.HP = 0 else: # 恢复生命,可能脱离某种状态 if cardi.attr.HP >= cardi.attr.MAXHP: cardi.attr.HP = cardi.attr.MAXHP self.reply(text="HP达到最大值", reply_to_message_id=rpmsgid) if hpdiff > 1 and originhp <= 1 and cardi.status == STATUS_NEARDEATH: self.reply(text="脱离濒死状态", reply_to_message_id=rpmsgid) cardi.status = STATUS_SERIOUSLYWOUNDED cardi.write() self.reply(text="生命值从"+str(originhp)+"修改为" + str(cardi.attr.HP), reply_to_message_id=rpmsgid) return True