async def pgmanage(self, ctx: commands.Context, *args): if len(args) == 0: raise gb.BotException('Specifica un pg!') charid = args[0].lower() isChar, character = self.bot.dbm.validators.getValidateCharacter( charid).validate() if not isChar: raise gb.BotException(f"Il personaggio {charid} non esiste!") # TODO move to security. The reason why we do this here is because "ce" is computed in security checks, but is needed in the command (to be passed to pc_interact) # we need a way for security checks to pass on some stuff to the command (maybe with the ctx object?) # permission checks issuer = str(ctx.message.author.id) playerid = character['player'] st, _ = self.bot.dbm.isStorytellerForCharacter(issuer, charid) ba, _ = self.bot.dbm.validators.getValidateBotAdmin(issuer).validate() co = playerid == issuer ce = st or ba # can edit if co and (not ce): #1: unlinked cl, _ = self.bot.dbm.isCharacterLinked(charid) #2 active session sa, _ = self.bot.dbm.isSessionActiveForCharacter( charid, ctx.channel.id) ce = (not cl) or sa if not (st or ba or co): return # non vogliamo che .rossellini faccia cose #raise BotException("Per modificare un personaggio è necessario esserne proprietari e avere una sessione aperta, oppure essere Admin o Storyteller") response = await self.pc_interact(ctx, character, ce, *args[1:]) await self.bot.atSend(ctx, response)
async def newTrait(self, ctx: commands.Context, traitid: gc.GreedyShortIdConverter, traittype: gc.TraitTypeConverter, tracktype: gc.TrackerTypeConverter, std: gc.NoYesConverter, *args): if len(args) == 0: await self.bot.atSend(ctx, newTrait_description) return istrait, _ = self.bot.dbm.validators.getValidateTrait(traitid).validate() if istrait: raise gb.BotException(f"Il tratto {traitid} esiste già!") traittypeid = traittype['id'] traitname = " ".join(args) response = "" t = self.bot.dbm.db.transaction() try: self.bot.dbm.db.insert("Trait", id = traitid, name = traitname, traittype = traittypeid, trackertype = tracktype, standard = std, ordering = 1.0) # we insert it in all available languages and we assume that it will be translated later: # better have it in the wrong language than not having it at all self.bot.dbm.db.query(query_addTraitLangs, vars = dict(traitid=traitid, traitname=traitname)) response = f'Il tratto {traitname} è stato inserito' if std: self.bot.dbm.db.query(query_addTraitToPCs, vars = dict(traitid=traitid)) response += f'\nIl nuovo tratto standard {traitname} è stato assegnato ai personaggi!' except: t.rollback() raise else: t.commit() await self.bot.atSend(ctx, response)
async def name(self, ctx: commands.Context, user: gc.RegisteredUserConverter): target_st = user['userid'] name = user['name'] t_st, _ = self.bot.dbm.validators.getValidateBotStoryTeller(target_st).validate() if t_st: raise gb.BotException(f"L'utente selezionato è già uno storyteller") self.bot.dbm.db.insert("Storyteller", userid=target_st) await self.bot.atSend(ctx, f"{name} ora è Storyteller")
async def updt(self, ctx: gb.GreedyContext, old_traitid: gc.GreedyShortIdConverter, new_traitid: gc.GreedyShortIdConverter, traittype: gc.TraitTypeConverter, tracktype: gc.TrackerTypeConverter, std: gc.NoYesConverter, *args): if len(args) == 0: await self.bot.atSend(ctx, newTrait_description) return istrait, old_trait = self.bot.dbm.validators.getValidateTrait( old_traitid).validate() if not istrait: raise gb.BotException(f"Il tratto {old_traitid} non esiste!") istrait, new_trait = self.bot.dbm.validators.getValidateTrait(new_traitid).validate() if istrait and (old_traitid!=new_traitid): raise gb.BotException(f"Il tratto {new_traitid} esiste già!") traittypeid = traittype['id'] traitname = " ".join(list(args)) response = f'Il tratto {traitname} è stato aggiornato' t = self.bot.dbm.db.transaction() try: self.bot.dbm.db.update("Trait", where= 'id = $oldid' , vars=dict(oldid = old_traitid), id = new_traitid, name = traitname, traittype = traittypeid, trackertype = tracktype, standard = std, ordering = 1.0) # now we update the language description, but only of the current language self.bot.dbm.db.update("LangTrait", where= 'traitId = $traitid and langId = $lid' , vars=dict(traitid=new_traitid, lid = ctx.getLID()), traitName = traitname) if std and not old_trait['standard']: self.bot.dbm.db.query(query_addTraitToPCs_safe, vars = dict(traitid=new_traitid)) response += f'\nIl nuovo talento standard {traitname} è stato assegnato ai personaggi!' elif not std and old_trait['standard']: self.bot.dbm.db.query(""" delete from CharacterTrait where trait = $traitid and max_value = 0 and cur_value = 0 and text_value = ''; """, vars = dict(traitid=new_traitid)) response += f'\nIl talento {traitname} è stato rimosso dai personaggi che non avevano pallini' except: t.rollback() raise else: t.commit() await self.bot.atSend(ctx, response)
async def link(self, ctx: commands.Context, chronicle: gc.ChronicleConverter, storyteller: gc.StorytellerConverter = None): issuer = str(ctx.message.author.id) chronid = chronicle['id'] target_st = None if storyteller == None: storyteller = await gc.StorytellerConverter().convert(ctx, issuer) target_st = storyteller['userid'] t_stc, _ = self.bot.dbm.isChronicleStoryteller(target_st, chronid) if t_stc: raise gb.BotException(f"L'utente selezionato è già Storyteller per {chronid}") # link self.bot.dbm.db.insert("StoryTellerChronicleRel", storyteller=target_st, chronicle=chronid) await self.bot.atSend(ctx, f"Cronaca associata")
async def roll(self, ctx: commands.Context, *args): if len(args) == 0: raise gb.BotException( self.bot.getStringForUser(ctx, "string_error_x_what", "roll") + " diomadonna") # xd args_list = list(args) # capisco che tipo di tiro ho di fronte what = args_list[0].lower() action = None if what in INIZIATIVA_CMD: action = RollCat.INITIATIVE elif what in RIFLESSI_CMD: action = RollCat.REFLEXES elif what in SOAK_CMD: action = RollCat.SOAK else: action = RollCat.DICE # leggo e imposto le varie opzioni parsed = None start_arg = 0 if action == RollCat.DICE else 1 try: parsed = self.parseRollArgs(ctx, args_list[start_arg:]) except ValueError as e: await self.bot.atSend(ctx, str(e)) return # gestisco i tiri specifici response = '' if action == RollCat.INITIATIVE: response = await self.roll_initiative(ctx, parsed) elif action == RollCat.REFLEXES: response = await self.roll_reflexes(ctx, parsed) elif action == RollCat.SOAK: response = await self.roll_soak(ctx, parsed) else: response = await self.roll_dice(ctx, parsed) await self.bot.atSend(ctx, response)
async def addt(self, ctx: gb.GreedyContext, character: gc.CharacterConverter, trait: gc.TraitConverter, value, *args): issuer = str(ctx.message.author.id) try: lid = ctx.getLID() ptrait = self.bot.dbm.getTrait_LangSafe(character['id'], trait['id'], lid) raise gb.BotException(f"{character['fullname']} ha già il tratto {ptrait['name']} ") except ghostDB.DBException: pass ttype = self.bot.dbm.db.select('TraitType', where='id=$id', vars=dict(id=trait['traittype']))[0] val = None if ttype['textbased']: val = " ".join([value]+list(args)) self.bot.dbm.db.insert("CharacterTrait", trait=trait['id'], playerchar=character['id'], cur_value = 0, max_value = 0, text_value = val, pimp_max = 0) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.TEXT_VALUE, val, '', ctx.message.content) else: val = int(value) pimp = 6 if trait['traittype'] in ['fisico', 'sociale', 'mentale'] else 0 self.bot.dbm.db.insert("CharacterTrait", trait=trait['id'], playerchar=character['id'], cur_value = val, max_value = val, text_value = "", pimp_max = pimp) self.bot.dbm.log(issuer, character['id'], trait['id'], ghostDB.LogType.MAX_VALUE, val, '', ctx.message.content) await self.bot.atSend(ctx, f"{character['fullname']} ora ha {trait['name']} {val}")
async def pc_interact(self, ctx: gb.GreedyContext, pc: object, can_edit: bool, *args_tuple) -> str: lid = ctx.getLID() args = list(args_tuple) response = '' if len(args) == 0: parsed = list( urllib.parse.urlparse(self.bot.config['Website'] ['website_url'])) # load website url parsed[4] = urllib.parse.urlencode({'character': pc['id']}) # fill query unparsed = urllib.parse.urlunparse(tuple(parsed)) # recreate url return f"Personaggio: {pc['fullname']}\nScheda: {unparsed}" # detach stuff like ["exp+1"] to ["exp", "+1"]" or ["exp-", "1"] to ["exp", "-", "1"] in args for op in ["+", "-", "="]: idx = args[0].find(op) if idx > 0: args = [args[0][:idx]] + [args[0][idx:]] + args[1:] break trait_id = args[0].lower() if len(args) == 1: trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) return self.getFormattedTrait(ctx, trait) # qui siamo sicuri che c'è un'operazione (o spazzatura) if not can_edit: return f'A sessione spenta puoi solo consultare le tue statistiche' param = "".join(args[1:]) # squish operazione = None if param in reset_aliases: operazione = "r" else: operazione = param[0] if not operazione in ["+", "-", "="]: return f'Operazione "{operazione}" non supportata' trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) #trait = dbm.getTrait(pc['id'], trait_id) if trait['pimp_max'] == 0 and trait['trackertype'] == 0: raise gb.BotException( f"Non puoi modificare il valore corrente di {trait['traitName']}" ) if trait['trackertype'] != 2: n = None if operazione != "r": n = param[1:] if not (n.isdigit()): return f'"{n}" non è un intero >= 0' if operazione == "r": if trait['trackertype'] == 1 or trait['trackertype'] == 0: n = trait['max_value'] - trait['cur_value'] elif trait['trackertype'] == 3: n = -trait['cur_value'] else: raise gb.BotException( f"Tracker {trait['trackertype']} non supportato") elif operazione == "=": n = int(param[1:]) - trait['cur_value'] # tricks else: n = int(param) new_val = trait['cur_value'] + n max_val = max(trait['max_value'], trait['pimp_max']) if new_val < 0: raise gb.BotException( f'Non hai abbastanza {trait["traitName"].lower()}!') elif new_val > max_val and trait['trackertype'] != 3: raise gb.BotException( f"Non puoi avere {new_val} {trait['traitName'].lower()}. Valore massimo: {max_val}" ) # u = self.bot.dbm.db.update( 'CharacterTrait', where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=pc['id']), cur_value=new_val) self.bot.dbm.log(ctx.message.author.id, pc['id'], trait['trait'], ghostDB.LogType.CUR_VALUE, new_val, trait['cur_value'], ctx.message.content) if u == 1: trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) return self.getFormattedTrait(ctx, trait) elif u == 0: trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) return self.getFormattedTrait(ctx, trait) else: return f'Qualcosa è andato storto, righe aggiornate: {u}' # salute response = '' n = param[ 1:-1] # 1st char is the operation, last char is the damaage type if n == '': n = 1 elif n.isdigit(): n = int(n) elif operazione == "=" or operazione == "r": pass else: raise gb.BotException(f'"{n}" non è un parametro valido!') dmgtype = param[-1].lower() new_health = trait['text_value'] if (not dmgtype in damage_types) and operazione != "r": raise gb.BotException(f'"{dmgtype}" non è un tipo di danno valido') if operazione == "r": new_health = "" u = self.bot.dbm.db.update( 'CharacterTrait', where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=pc['id']), text_value=new_health, cur_value=trait['max_value']) self.bot.dbm.log(ctx.message.author.id, pc['id'], trait['trait'], ghostDB.LogType.CUR_VALUE, new_health, trait['text_value'], ctx.message.content) if u != 1: raise gb.BotException( f'Qualcosa è andato storto, righe aggiornate: {u}') trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) response = self.getFormattedTrait(ctx, trait) elif operazione == "+": rip = False for i in range( n): # applico i danni uno alla volta perchè sono un nabbo if dmgtype == "c" and new_health.endswith( "c"): # non rischio di cambiare la lunghezza new_health = new_health[:-1] + "l" else: if len(new_health) < trait[ 'max_value']: # non ho già raggiunto il massimo if dmgtype == "c": new_health += "c" elif dmgtype == "a": new_health = "a" + new_health else: la = new_health.rfind("a") + 1 new_health = new_health[:la] + "l" + new_health[la:] else: # oh no convert = False if dmgtype == "c": if trait['cur_value'] > 0: # trick per salvarsi mezzo aggravato trait['cur_value'] = 0 else: convert = True trait['cur_value'] = trait['max_value'] elif dmgtype == 'l': convert = True else: rip = True if convert: fl = new_health.find('l') if fl >= 0: new_health = new_health[:fl] + 'a' + new_health[ fl + 1:] else: rip = True if rip: break if new_health.count("a") == trait['max_value']: rip = True u = self.bot.dbm.db.update( 'CharacterTrait', where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=pc['id']), text_value=new_health, cur_value=trait['cur_value']) self.bot.dbm.log(ctx.message.author.id, pc['id'], trait['trait'], ghostDB.LogType.CUR_VALUE, new_health, trait['text_value'], ctx.message.content) if u != 1 and not rip: raise gb.BotException( f'Qualcosa è andato storto, righe aggiornate: {u}') trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) response = self.getFormattedTrait(ctx, trait) if rip: response += "\n\n RIP" elif operazione == "-": if dmgtype == "a": if new_health.count(dmgtype) < n: raise gb.BotException("Non hai tutti quei danni aggravati") else: new_health = new_health[n:] elif dmgtype == "l": if new_health.count(dmgtype) < n: raise gb.BotException("Non hai tutti quei danni letali") else: fl = new_health.find(dmgtype) new_health = new_health[:fl] + new_health[fl + n:] else: # dio can if ((int(trait['cur_value']) == 0) + new_health.count(dmgtype) + new_health.count("l") * 2) < n: raise gb.BotException( "Non hai tutti quei danni contundenti") for i in range(n): if trait['cur_value'] == 0: trait['cur_value'] = trait[ 'max_value'] # togli il mezzo aggravato else: if new_health[-1] == 'c': new_health = new_health[:-1] elif new_health[-1] == 'l': new_health = new_health[:-1] + 'c' else: raise gb.BotException( "Non hai tutti quei danni contundenti" ) # non dovrebbe mai succedere u = self.bot.dbm.db.update( 'CharacterTrait', where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=pc['id']), text_value=new_health, cur_value=trait['cur_value']) self.bot.dbm.log(ctx.message.author.id, pc['id'], trait['trait'], ghostDB.LogType.CUR_VALUE, new_health, trait['text_value'], ctx.message.content) if u != 1: raise gb.BotException( f'Qualcosa è andato storto, righe aggiornate: {u}') trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) response = self.getFormattedTrait(ctx, trait) else: # = full = param[1:] counts = list(map(lambda x: full.count(x), damage_types)) if sum(counts) != len(full): raise gb.BotException(f'"{full}" non è un parametro valido!') new_health = "".join( list(map(lambda x: x[0] * x[1], zip(damage_types, counts)))) # siamo generosi e riordiniamo l'input u = self.bot.dbm.db.update( 'CharacterTrait', where='trait = $trait and playerchar = $pc', vars=dict(trait=trait['id'], pc=pc['id']), text_value=new_health, cur_value=1) self.bot.dbm.log(ctx.message.author.id, pc['id'], trait['trait'], ghostDB.LogType.CUR_VALUE, new_health, trait['text_value'], ctx.message.content) if u != 1: raise gb.BotException( f'Qualcosa è andato storto, righe aggiornate: {u}') trait = self.bot.dbm.getTrait_LangSafe(pc['id'], trait_id, lid) response = self.getFormattedTrait(ctx, trait) return response