def __init__(self, raw: Dict[str, str], server: Server): if not set(raw) <= set(Bonus.keys): raise ValueError('Unexpected keys: ' + str(set(raw) - set(Bonus.keys))) # Start time as gungho time string self.start_time_str = str(raw['s']) self.start_timestamp = pad_util.gh_to_timestamp_2( self.start_time_str, server) # End time as gungho time string self.end_time_str = str(raw['e']) self.end_timestamp = pad_util.gh_to_timestamp_2( self.end_time_str, server) # Optional DungeonId self.dungeon_id = None # type: Optional[DungeonId] if 'd' in raw: self.dungeon_id = DungeonId(int(raw['d'])) # Optional DungeonFloorId # Stuff like rewards text in monthly quests self.sub_dungeon_id = None # type: Optional[SubDungeonId] if 'f' in raw: self.sub_dungeon_id = SubDungeonId(int(raw['f'])) # If REM/PEM, the ID of the machine self.egg_machine_id = None # type: Optional[int] if 'i' in raw: self.egg_machine_id = int(raw['i']) # Optional human-readable message (with formatting) self.message = None # type: Optional[str] # Optional human-readable message (no formatting) self.clean_message = None # type: Optional[str] if 'm' in raw: self.message = str(raw['m']) self.clean_message = pad_util.strip_colors(self.message) bonus_id = int(raw['b']) self.bonus_info = TYPES_MAP.get(bonus_id, UNKNOWN_TYPE) # Bonus value, if provided, optionally processed self.bonus_value = None # type: Optional[Union[float, int]] if 'a' in raw: self.bonus_value = raw['a'] if self.bonus_info.mod_fn: self.bonus_value = self.bonus_info.mod_fn(self.bonus_value) # Human readable name for the bonus self.bonus_name = self.bonus_info.bonus_type.name if self.bonus_info.bonus_type == BonusType.unknown: self.bonus_name += '({})'.format(bonus_id) self.bonus_id = bonus_id
def __init__(self, raw: Dict[str, Any], server: Server): if not set(raw) <= set(Bonus.keys): raise ValueError('Unexpected keys: ' + str(set(raw) - set(Bonus.keys))) self.raw = raw # Start time as gungho time string self.start_time_str = str(raw['s']) self.start_timestamp = pad_util.gh_to_timestamp_2( self.start_time_str, server) # End time as gungho time string self.end_time_str = str(raw['e']) self.end_timestamp = pad_util.gh_to_timestamp_2( self.end_time_str, server) # Optional DungeonId self.dungeon_id = None # type: Optional[DungeonId] if 'd' in raw: self.dungeon_id = DungeonId(int(raw['d'])) # Optional DungeonFloorId # Stuff like rewards text in monthly quests self.sub_dungeon_id = None # type: Optional[SubDungeonId] if 'f' in raw: self.sub_dungeon_id = SubDungeonId(int(raw['f'])) # If REM/PEM, the ID of the machine self.egg_machine_id = None # type: Optional[int] if 'i' in raw: self.egg_machine_id = int(raw['i']) # Optional human-readable message (with formatting) self.message = None # type: Optional[str] # Optional human-readable message (no formatting) self.clean_message = None # type: Optional[str] # Optional URL in message self.url = None # type: Optional[str] if 'm' in raw: self.message = str(raw['m']) self.clean_message = pad_util.strip_colors(self.message) if (match := re.search(r'https?:.+?(?=\|)', self.message)): self.url = match.group()
def __init__(self, dungeon_id: DungeonId, raw: List[Any]): self.sub_dungeon_id = SubDungeonId(dungeon_id * 1000 + int(raw[0])) self.simple_sub_dungeon_id = int(raw[0]) self.raw_name = raw[1] self.clean_name = pad_util.strip_colors(self.raw_name) self.floors = int(raw[2]) self.rflags1 = int(raw[3]) self.stamina = raw[4] self.bgm1 = raw[5] self.bgm2 = raw[6] self.rflags2 = int(raw[7]) # If monsters can use skills in this dungeon. self.technical = self.rflags1 & 0x80 > 0 # This next loop runs through the elements from raw[8] until it hits a 0. The 0 indicates the end of the list # of drops for the floor, the following segments are the dungeon modifiers pos = 8 while int(raw[pos]) != 0: pos += 1 pos += 1 self.flags = int(raw[pos]) self.remaining_fields = raw[pos + 1:] # Modifiers parsing doesn't seem to always work # Hacked up version for dungeon modifiers, needed for # enemy parsing. self.hp_mult = 1.0 self.atk_mult = 1.0 self.def_mult = 1.0 for field in self.remaining_fields: if 'hp:' in field or 'at:' in field or 'df:' in field: for mod in field.split('|'): if mod.startswith('hp:'): self.hp_mult = float(mod[3:]) / 10000 elif mod.startswith('at:'): self.atk_mult = float(mod[3:]) / 10000 elif mod.startswith('df:'): self.def_mult = float(mod[3:]) / 10000 break # Modifiers parsing also seems to skip fixed teams sometimes. # Hacked up version for just that here. self.fixed_team = {} for field in self.remaining_fields: if not 'fc1' in field: continue else: # TODO: this broke, look into re-enabling it continue for sub_field in field.split('|'): if not sub_field.startswith('fc'): continue idx = int(sub_field[2]) contents = sub_field[4:] details = contents.split(';') full_record = len(details) > 1 self.fixed_team[idx] = { 'monster_id': details[0], 'hp_plus': details[1] if full_record else 0, 'atk_plus': details[2] if full_record else 0, 'rcv_plus': details[3] if full_record else 0, 'awakening_count': details[4] if full_record else 0, 'skill_level': details[5] if full_record else 0, } # This code imported from Rikuu, need to clean it up and merge # with the other modifiers parsing code. For now just importing # the score parsing, needed for dungeon loading. self.score = None i = 0 if (self.flags & 0x1) != 0: i += 2 # self.requirement = { # dungeonId: Number(self.remaining_fields[i++]), # floorId: Number(self.remaining_fields[i++]) # }; if (self.flags & 0x4) != 0: i += 1 # self.beginTime = fromPADTime(self.remaining_fields[i++]); if (self.flags & 0x8) != 0: self.score = int(self.remaining_fields[i]) i += 1 if (self.flags & 0x10) != 0: i += 1 # self.minRank = Number(self.remaining_fields[i++]); if (self.flags & 0x40) != 0: i += 1
def __init__(self, dungeon_id: DungeonId, raw: List[Any]): # https://github.com/TsubakiBotPad/pad-data-pipeline/wiki/Subdungeon-Arguments self.sub_dungeon_id = SubDungeonId(dungeon_id * 1000 + int(raw[0])) self.simple_sub_dungeon_id = int(raw[0]) self.raw_name = self.name = raw[1] self.clean_name = pad_util.strip_colors(self.raw_name) self.floors = int(raw[2]) self.rflags1 = int(raw[3]) self.stamina = raw[4] self.bgm1 = raw[5] self.bgm2 = raw[6] self.disables = int(raw[7]) # If monsters can use skills in this dungeon. self.technical = self.rflags1 & 0x80 > 0 # This next loop runs through the elements from raw[8] until it hits a 0. The 0 indicates the end of the list # of drops for the floor, the following segments are the dungeon modifiers pos = 8 while int(raw[pos]) != 0: pos += 1 pos += 1 flags = int(raw[pos]) pos += 1 self.prev_dungeon_id = None self.prev_floor_id = None self.start_timestamp = None self.score = None self.unknown_f4 = None pipe_hell = "" self.end_timestamp = None if flags & 1 << 0: # Prev Floor self.prev_dungeon_id = int(raw[pos]) self.prev_floor_id = int(raw[pos + 1]) pos += 2 if flags & 1 << 2: # Start Timestamp self.start_timestamp = ghtime(raw[pos], 'utc') pos += 1 if flags & 1 << 3: # S-Rank Score self.score = int(raw[pos]) pos += 1 if flags & 1 << 4: # Unknown Value self.unknown_f4 = int(raw[pos]) pos += 1 if flags & 1 << 6: # Pipe Hell pipe_hell = raw[pos] pos += 1 if flags & 1 << 7: # Start Timestamp self.end_timestamp = ghtime(raw[pos], 'utc') pos += 1 self.restriction_type = int(raw[pos]) self.restriction_args = raw[pos + 1:] modifiers = parse_modifiers(pipe_hell) self.hp_mult = default_int(modifiers, 'hp', 10000) / 10000 self.atk_mult = default_int(modifiers, 'at', 10000) / 10000 self.def_mult = default_int(modifiers, 'df', 10000) / 10000 self.fixed_monsters: Dict[int, FixedTeamMonster] = {} for idx in range(6): if None is (fc := modifiers.get(f'fc{idx + 1}')): # Not all dungeons have fixed cards in all slots continue self.fixed_monsters[idx] = FixedTeamMonster(fc)