def parseDiceExpression_Dice(self, what: str) -> DiceExprParsed: split = what.split("d") if len(split) > 2: raise gb.GreedyCommandError('string_error_toomany_d') if len(split) == 1: raise gb.GreedyCommandError('string_error_not_XdY', (split[0], )) if split[0] == "": split[0] = "1" if not split[0].isdigit(): raise gb.GreedyCommandError('string_error_not_positive_integer', (split[0], )) if split[1] == "": split[1] = "10" if not split[1].isdigit(): raise gb.GreedyCommandError('string_error_not_positive_integer', (split[1], )) n = int(split[0]) faces = int(split[1]) if n == 0: raise gb.GreedyCommandError('string_error_not_gt0', (n, )) if faces == 0: raise gb.GreedyCommandError('string_error_not_gt0', (faces, )) if n > int(self.bot.config['BotOptions']['max_dice']): raise gb.GreedyCommandError('string_error_toomany_dice', (n, )) if faces > int(self.bot.config['BotOptions']['max_faces']): raise gb.GreedyCommandError('string_error_toomany_faces', (faces, )) return DiceExprParsed(n, n, 0, faces, None)
async def convert(self, ctx: Context, argument: str) -> bool: stdarg = argument.lower() std = stdarg in ['y', 's', '1', 'true'] if not std and not stdarg in ['n', '0', 'false']: raise gb.GreedyCommandError("'{}' non è un'opzione valida", (stdarg, )) return std
async def roll_soak(self, ctx: gb.GreedyContext, parsed: dict) -> str: if RollArg.MULTI in parsed or RollArg.SPLIT in parsed or RollArg.ADD in parsed or parsed[ RollArg.ROLLTYPE] != RollType.NORMALE: raise gb.GreedyCommandError( "string_error_roll_invalid_param_combination") lid = ctx.getLID() diff = parsed[RollArg.DIFF] if RollArg.DIFF in parsed else 6 character = self.bot.dbm.getActiveChar(ctx) pool = self.bot.dbm.getTrait_LangSafe(character['id'], 'costituzione', lid)['cur_value'] try: pool += self.bot.dbm.getTrait_LangSafe(character['id'], 'robustezza', lid)['cur_value'] except ghostDB.DBException: pass return self.rollAndFormatVTM(ctx, pool, 10, diff, RollStatusSoak(self.bot.languageProvider, lid), 0, False, statistics=RollArg.STATS in parsed)
async def roll_reflexes(self, ctx: gb.GreedyContext, parsed: dict) -> str: if RollArg.MULTI in parsed or RollArg.SPLIT in parsed or parsed[ RollArg. ROLLTYPE] != RollType.NORMALE or RollArg.DIFF in parsed: raise gb.GreedyCommandError( "string_error_roll_invalid_param_combination") lid = ctx.getLID() add = parsed[RollArg.ADD] if RollArg.ADD in parsed else 0 character = self.bot.dbm.getActiveChar(ctx) volonta = self.bot.dbm.getTrait_LangSafe(character['id'], 'volonta', lid) #['cur_value'] prontezza = self.bot.dbm.getTrait_LangSafe(character['id'], 'prontezza', lid) #['cur_value'] diff = 10 - prontezza['cur_value'] response = f'{volonta["traitName"]}: {volonta["cur_value"]}, {prontezza["traitName"]}: {prontezza["cur_value"]} -> {volonta["cur_value"]}d{10} {self.bot.getStringForUser(ctx, "string_diff")} ({diff} = {10}-{prontezza["cur_value"]})\n' response += self.rollAndFormatVTM(ctx, volonta['cur_value'], 10, diff, RollStatusReflexes( self.bot.languageProvider, lid), add, statistics=RollArg.STATS in parsed) return response
async def roll_initiative(self, ctx: gb.GreedyContext, parsed: dict) -> str: if RollArg.MULTI in parsed or RollArg.SPLIT in parsed or parsed[ RollArg. ROLLTYPE] != RollType.NORMALE or RollArg.DIFF in parsed: raise gb.GreedyCommandError( "string_error_roll_invalid_param_combination") lid = ctx.getLID() add = parsed[RollArg.ADD] if RollArg.ADD in parsed else 0 raw_roll = random.randint(1, 10) bonuses_log = [] bonus = add if add: bonuses_log.append( self.bot.getStringForUser(ctx, "string_bonus_X", add)) try: character = self.bot.dbm.getActiveChar(ctx) for traitid in ['prontezza', 'destrezza', 'velocità']: # TODO dehardcode? try: val = self.bot.dbm.getTrait_LangSafe( character['id'], traitid, lid) bonus += val["cur_value"] bonuses_log.append( f'{val["traitName"]}: {val["cur_value"]}') except ghostDB.DBException: pass except ghostDB.DBException: bonuses_log.append( self.bot.getStringForUser(ctx, "string_comment_no_pc")) details = "" if len(bonuses_log): details = ", ".join(bonuses_log) final_val = raw_roll + bonus return f'{self.bot.getStringForUser(ctx, "string_initiative")}: **{final_val}**\n{self.bot.getStringForUser(ctx, "string_roll")}: [{raw_roll}] + {bonus if bonus else 0} ({details})'
def parseDiceExpressionIntoSummary(self, ctx: commands.Context, summary: dict, expression: str, firstNegative: bool = False) -> dict: parsed_expr = self.parseDiceExpression_Mixed( ctx, expression, firstNegative=firstNegative, character=summary[RollArg.CHARACTER]) if RollArg.DADI in summary: summary[RollArg.DADI] += parsed_expr.n_dice summary[RollArg.DADI_PERMANENTI] += parsed_expr.n_dice_permanent else: summary[RollArg.DADI] = parsed_expr.n_dice summary[RollArg.DADI_PERMANENTI] = parsed_expr.n_dice_permanent if parsed_expr.n_extrasucc != 0: if RollArg.ADD in summary: summary[RollArg.ADD] += parsed_expr.n_extrasucc else: summary[RollArg.ADD] = parsed_expr.n_extrasucc if parsed_expr.character != None: summary[RollArg.CHARACTER] = parsed_expr.character # figure out if we are mixing faces if parsed_expr.n_faces != 0: # if it's 0, it's just a flat number, compatible with all faces if RollArg.NFACES in summary and summary[ RollArg.NFACES] != parsed_expr.n_faces: raise gb.GreedyCommandError("string_error_face_mixing") summary[RollArg.NFACES] = parsed_expr.n_faces return summary
async def convert(self, ctx: gb.GreedyContext, argument: str) -> Any: try: user = await super().convert(ctx, argument) except UserNotFound: raise gb.GreedyCommandError('string_error_usernotfound_discord', (argument, )) bot: gb.GreedyGhost = ctx.bot return bot.dbm.validators.getValidateBotUser(user.id).get()
async def convert(self, ctx: Context, argument: str) -> int: error = gb.GreedyCommandError("'{}' non è tracker valido!", (argument, )) tracktype = 0 try: tracktype = int(argument) if not tracktype in [0, 1, 2, 3]: # TODO dehardcode raise error except ValueError: raise error return tracktype
async def guild_authorization(self, ctx: commands.Context, authorize: NoYesConverter = None): guild_ctx = ctx.guild if guild_ctx is None: raise gb.GreedyCommandError( "string_error_not_available_outside_guild") await self.bot.checkAndJoinGuild(guild_ctx) guild_db = self.bot.dbm.validators.getValidateGuild(guild_ctx.id).get() if authorize is None: status_str = None if guild_db["authorized"]: status_str = "string_msg_guild_authstatus_enabled" else: status_str = "string_msg_guild_authstatus_disabled" status = self.bot.getStringForUser(ctx, status_str) await self.bot.atSendLang(ctx, "string_msg_guild_authstatus", status) elif authorize: self.bot.dbm.updateGuildAuthorization(guild_ctx.id, True) for member in guild_ctx.members: iu, _ = self.bot.dbm.validators.getValidateBotUser( member.id).validate() if not iu: self.bot.dbm.registerUser( member.id, member.name, self.bot.config['BotOptions']['default_language']) await self.bot.atSendLang( ctx, "string_msg_guild_authstatus", self.bot.getStringForUser( ctx, "string_msg_guild_authstatus_enabled")) else: self.bot.dbm.updateGuildAuthorization(guild_ctx.id, False) guild_map = self.bot.getGuildActivationMap() for member in guild_ctx.members: self.bot.checkAndRemoveUser(member, guild_map) await self.bot.atSendLang( ctx, "string_msg_guild_authstatus", self.bot.getStringForUser( ctx, "string_msg_guild_authstatus_disabled"))
async def convert(self, ctx: Context, argument: str) -> Any: if validate_id(argument): return argument.lower() else: raise gb.GreedyCommandError('string_error_invalid_shortid', (argument, ))
async def roll_dice(self, ctx: gb.GreedyContext, parsed: dict) -> str: lid = ctx.getLID() ndice = 0 if RollArg.PERMANENTE in parsed: ndice = parsed[RollArg.DADI_PERMANENTI] else: ndice = parsed[RollArg.DADI] if not RollArg.NFACES in parsed: raise gb.GreedyCommandError("string_error_no_faces") nfaces = parsed[RollArg.NFACES] character = parsed[RollArg.CHARACTER] # might be None # modifico il numero di dadi if RollArg.PENALITA in parsed: if not character: character = self.bot.dbm.getActiveChar(ctx) health = self.bot.dbm.getTrait_LangSafe(character['id'], 'salute', lid) penalty, _ = utils.parseHealth(health) ndice += penalty[0] max_dice = int(self.bot.config['BotOptions']['max_dice']) if ndice > max_dice: raise gb.GreedyCommandError("string_error_toomany_dice", (max_dice, )) if ndice <= 0: raise gb.GreedyCommandError("string_error_toofew_dice", (ndice, )) # check n° di mosse per le multiple if RollArg.MULTI in parsed: multi = parsed[RollArg.MULTI] max_moves = int( ((ndice + 1) / 2) - 0.1 ) # (ndice+1)/2 è il numero di mosse in cui si rompe, non il massimo. togliendo 0.1 e arrotondando per difetto copro sia il caso intero che il caso con .5 if max_moves == 1: raise gb.GreedyCommandError( "string_error_not_enough_dice_multi") elif multi > max_moves: raise gb.GreedyCommandError( "string_error_not_enough_dice_multi_MAX_REQUESTED", (max_moves, ndice)) # decido cosa fare add = parsed[RollArg.ADD] if RollArg.ADD in parsed else 0 # simple roll if not (RollArg.MULTI in parsed) and not ( RollArg.DIFF in parsed) and not (RollArg.SPLIT in parsed) and ( parsed[RollArg.ROLLTYPE] == RollType.NORMALE or parsed[RollArg.ROLLTYPE] == RollType.SOMMA): raw_roll = list( map(lambda x: random.randint(1, nfaces), range(ndice))) if add != 0 or parsed[RollArg.ROLLTYPE] == RollType.SOMMA: roll_sum = sum(raw_roll) + add return f'{repr(raw_roll)} {"+" if add >= 0 else "" }{add} = **{roll_sum}**' else: return repr(raw_roll) if nfaces != 10: raise gb.GreedyCommandError('string_error_not_d10') # past this point, we are in d10 territory stats = RollArg.STATS in parsed response = '' if RollArg.MULTI in parsed: multi = parsed[RollArg.MULTI] split = [] if RollArg.SPLIT in parsed: split = parsed[RollArg.SPLIT] if parsed[RollArg.ROLLTYPE] == RollType.NORMALE: response = "" if not RollArg.DIFF in parsed: raise gb.GreedyCommandError("string_error_missing_diff") for i in range(multi): parziale = '' ndadi = ndice - i - multi split_diffs = findSplit(i, split) if len(split_diffs): pools = [(ndadi - ndadi // 2), ndadi // 2] for j in range(len(pools)): parziale += f'\n{self.bot.getStringForUser(ctx, "string_roll")} {j+1}: ' + self.rollAndFormatVTM( ctx, pools[j], nfaces, split_diffs[j], RollStatusNormal(self.bot.languageProvider, lid, parsed[RollArg.MINSUCC]), statistics=stats) else: parziale = self.rollAndFormatVTM( ctx, ndadi, nfaces, parsed[RollArg.DIFF], RollStatusNormal(self.bot.languageProvider, lid, parsed[RollArg.MINSUCC]), statistics=stats, minsucc=parsed[RollArg.MINSUCC]) response += f'\n{self.bot.getStringForUser(ctx, "string_action")} {i+1}: ' + parziale # line break all'inizio tanto c'è il @mention else: raise gb.GreedyCommandError( "string_error_roll_invalid_param_combination") else: # 1 tiro solo if RollArg.SPLIT in parsed: split = parsed[RollArg.SPLIT] if parsed[RollArg.ROLLTYPE] == RollType.NORMALE: pools = [(ndice - ndice // 2), ndice // 2] response = '' for i in range(len(pools)): parziale = self.rollAndFormatVTM( ctx, pools[i], nfaces, split[0][i + 1], RollStatusNormal(self.bot.languageProvider, lid, parsed[RollArg.MINSUCC]), statistics=stats) response += f'\n{self.bot.getStringForUser(ctx, "string_roll")} {i+1}: ' + parziale else: raise gb.GreedyCommandError( "string_error_roll_invalid_param_combination") else: if parsed[ RollArg.ROLLTYPE] == RollType.NORMALE: # tiro normale if not RollArg.DIFF in parsed: raise gb.GreedyCommandError( "string_error_missing_diff") response = self.rollAndFormatVTM( ctx, ndice, nfaces, parsed[RollArg.DIFF], RollStatusNormal(self.bot.languageProvider, lid, parsed[RollArg.MINSUCC]), add, statistics=stats, minsucc=parsed[RollArg.MINSUCC]) elif parsed[RollArg.ROLLTYPE] == RollType.DANNI: diff = parsed[ RollArg.DIFF] if RollArg.DIFF in parsed else 6 response = self.rollAndFormatVTM( ctx, ndice, nfaces, diff, RollStatusDMG(self.bot.languageProvider, lid), add, False, statistics=stats) elif parsed[RollArg.ROLLTYPE] == RollType.PROGRESSI: diff = parsed[ RollArg.DIFF] if RollArg.DIFF in parsed else 6 response = self.rollAndFormatVTM( ctx, ndice, nfaces, diff, RollStatusProgress(self.bot.languageProvider, lid), add, False, True, statistics=stats) else: raise gb.GreedyCommandError( "string_error_unknown_rolltype", (RollArg.ROLLTYPE, )) return response
def parseRollArgs(self, ctx: commands.Context, args_raw: tuple) -> dict: parsed = { # TODO this should probably become a class RollArg.ROLLTYPE: RollType.NORMALE, # default RollArg.MINSUCC: 1, RollArg.CHARACTER: None, RollArg.DADI: 0, RollArg.DADI_PERMANENTI: 0 } args = list(args_raw) max_dice = int(self.bot.config['BotOptions']['max_dice']) # detaching + or - from the end of an expression needs to be done immediately i = 0 while i < len(args): if args[i].endswith(ADD_CMD) and args[i] != ADD_CMD: args = args[:i] + [args[i][:-1], ADD_CMD] + args[i + 1:] if args[i].endswith(SUB_CMD) and args[i] != SUB_CMD: args = args[:i] + [args[i][:-1], SUB_CMD] + args[i + 1:] i += 1 # do the actual parsing i = 0 last_i = -1 repeats = 0 while i < len(args): # bit of safety code due to the fact that we decrement i sometimes if i == last_i: repeats += 1 else: repeats = 0 if repeats >= 2: raise gb.GreedyCommandError( "string_arg_X_in_Y_notclear", (args[i], utils.prettyHighlightError(args, i))) last_i = i if args[i] in SOMMA_CMD: parsed[RollArg.ROLLTYPE] = RollType.SOMMA elif args[i] in DIFF_CMD: if RollArg.DIFF in parsed: raise gb.GreedyCommandError("string_error_multiple_diff") if len(args) == i + 1: raise gb.GreedyCommandError("string_error_x_what", (args[i], )) i, diff = self.validateDifficulty(ctx, args, i + 1) parsed[RollArg.DIFF] = diff elif args[i] in MULTI_CMD: if RollArg.SPLIT in parsed: raise gb.GreedyCommandError( "string_error_split_before_multi") if RollArg.MULTI in parsed: raise gb.GreedyCommandError("string_error_multiple_multi") if len(args) == i + 1: raise gb.GreedyCommandError("string_error_x_what", (args[i], )) i, multi = self.validateBoundedNumber( ctx, args, i + 1, 2, utils.INFINITY, self.bot.getStringForUser( ctx, "string_errorpiece_validarg_multi", args[i]) ) # controlliamo il numero di mosse sotto, dopo aver applicato bonus o penalità al numero di dadi parsed[RollArg.MULTI] = multi elif args[i] in DANNI_CMD: parsed[RollArg.ROLLTYPE] = RollType.DANNI elif args[i] in PROGRESSI_CMD: parsed[RollArg.ROLLTYPE] = RollType.PROGRESSI elif args[i] in SPLIT_CMD: roll_index = 0 split = [] if RollArg.SPLIT in parsed: # fetch previous splits split = parsed[RollArg.SPLIT] if RollArg.MULTI in parsed: if len(args) < i + 4: raise ValueError( self.bot.getStringForUser( ctx, "string_error_X_takes_Y_params", args[i], 3) + " " + self.bot.getStringForUser( ctx, "string_errorpiece_with_multi")) i, temp = self.validateIntegerGreatZero(ctx, args, i + 1) roll_index = temp - 1 if roll_index >= parsed[RollArg.MULTI]: raise gb.GreedyCommandError( "string_error_split_X_higherthan_multi_Y", (args[i + 1], multi)) if sum(filter( lambda x: x[0] == roll_index, split)): # cerco se ho giò splittato questo tiro raise gb.GreedyCommandError( "string_error_already_splitting_X", (roll_index + 1, )) else: # not an elif because reasons if len(args) < i + 3: raise gb.GreedyCommandError( "string_error_X_takes_Y_params", (args[i], 2)) i, d1 = self.validateIntegerGreatZero(ctx, args, i + 1) i, d2 = self.validateIntegerGreatZero(ctx, args, i + 1) split.append([roll_index] + list(map(int, [d1, d2]))) parsed[RollArg.SPLIT] = split # save the new split elif args[i] in [ADD_CMD, SUB_CMD]: if len(args) == i + 1: raise gb.GreedyCommandError("string_error_x_what", (args[i], )) # 3 options here: XdY (and variants), trait(s), integers. try: sign = (1 - 2 * (args[i] == SUB_CMD) ) # 1 or -1 depending on args[i] i, add = self.validateIntegerGreatZero( ctx, args, i + 1) # simple positive integer -> add as successes if RollArg.ADD in parsed: parsed[RollArg.ADD] += add * sign else: parsed[RollArg.ADD] = add * sign except ValueError as e_add: # not an integer -> try to parse it as a dice expression parsed = self.parseDiceExpressionIntoSummary( ctx, parsed, args[i + 1], firstNegative=args[i] == SUB_CMD) i += 1 elif args[i] in PENALITA_CMD: parsed[RollArg.PENALITA] = True elif args[i] in DADI_CMD: if len(args) == i + 1: raise gb.GreedyCommandError("string_error_x_what", (args[i], )) i, val = self.validateBoundedInteger( ctx, args, i + 1, -max_dice, max_dice) # this is also checked later on the final number if RollArg.DADI in parsed: parsed[RollArg.DADI] += val parsed[RollArg.DADI_PERMANENTI] += val else: parsed[RollArg.DADI] = val parsed[RollArg.DADI_PERMANENTI] = val elif args[i] in PERMANENTE_CMD: parsed[RollArg.PERMANENTE] = True elif args[i] in STATISTICS_CMD: parsed[RollArg.STATS] = True elif args[i] in MINSUCC_CMD: i, minsucc = self.validateIntegerGreatZero( ctx, args, i + 1) # simple positive integer -> add as successes parsed[RollArg.MINSUCC] = minsucc else: #try parsing a dice expr try: parsed = self.parseDiceExpressionIntoSummary( ctx, parsed, args[i]) except (gb.GreedyCommandError, gb.BotException, lng.LangSupportErrorGroup) as e: # provo a staccare parametri attaccati did_split = False idx = 0 tests = DIFF_CMD + MULTI_CMD + DADI_CMD + [ ADD_CMD, SUB_CMD ] while not did_split and idx < len(tests): cmd = tests[idx] if args[i].startswith(cmd): args = args[:i] + [cmd, args[i][len(cmd):] ] + args[i + 1:] did_split = True idx += 1 if not did_split: # F raise lng.LangSupportErrorGroup( "MultiError", [ gb.GreedyCommandError( "string_arg_X_in_Y_notclear", (args[i], utils.prettyHighlightError(args, i))), e ]) else: i -= 1 # forzo rilettura i += 1 return parsed
def parseDiceExpression_Mixed(self, ctx: gb.GreedyContext, what: str, firstNegative: bool = False, character=None) -> DiceExprParsed: lid = ctx.getLID() saw_trait = False saw_notd10 = False faces = 0 n = 0 n_perm = 0 n_extrasucc = 0 split_add_list = what.split( ADD_CMD ) # split on "+", so each of the results STARTS with something to add for i in range(0, len(split_add_list)): split_add = split_add_list[i] split_sub_list = split_add.split( SUB_CMD ) # split on "-", so the first element will be an addition (unless firstNegative is true and i == 0), and everything else is a subtraction for j in range(0, len(split_sub_list)): term = split_sub_list[j] n_term = 0 n_term_perm = 0 n_term_extra = 0 new_faces = 0 try: # either a xdy expr parsed_expr = self.parseDiceExpression_Dice(term) n_term = parsed_expr.n_dice n_term_perm = parsed_expr.n_dice_permanent new_faces = parsed_expr.n_faces saw_notd10 = saw_notd10 or (new_faces != 10) except gb.GreedyCommandError as e: # or a trait try: if not character: character = self.bot.dbm.getActiveChar( ctx) # can raise temp = self.bot.dbm.getTrait_LangSafe( character['id'], term, lid) n_term = temp['cur_value'] n_term_perm = temp['max_value'] saw_trait = True new_faces = 10 except ghostDB.DBException as edb: try: _, n_term_extra = self.validateNumber( ctx, [term], 0) except ValueError as ve: raise lng.LangSupportErrorGroup( "MultiError", [ gb.GreedyCommandError( "string_error_notsure_whatroll"), e, edb, gb.GreedyCommandError(f'{ve}') ]) if new_faces: if faces and ( faces != new_faces ): # we do not support mixing different face numbers for now raise gb.GreedyCommandError("string_error_face_mixing") faces = new_faces if saw_trait and saw_notd10: # forced10 = false only lets through non d10 expressions that DO NOT use traits raise gb.GreedyCommandError("string_error_not_d10") if j > 0 or (i == 0 and firstNegative): n -= n_term n_perm -= n_term_perm n_extrasucc -= n_term_extra else: n += n_term n_perm += n_term_perm n_extrasucc += n_term_extra # is it good that if the espression is just flat numbers we can parse it? # for example ".roll 3d10 7" will parse the same as ".roll 3d10 +7" return DiceExprParsed(n, n_perm, n_extrasucc, faces, character)