def mutate(self): MAX_ENEMIES = 6 if self.bosses or self.enemies_hidden or not self.enemies_present: return candidates = list(self.leaders) while len(candidates) < 3: base = random.choice(candidates) new = base.get_similar() if new not in candidates: candidates.append(new) assert len(set(candidates)) <= 3 num_enemies = random.randint(1, random.randint(3, MAX_ENEMIES)) num_enemies = max(num_enemies, len(self.leaders)) chosen_enemies = list(self.leaders) while len(chosen_enemies) < num_enemies: vram_total = sum([e.vram_value for e in chosen_enemies]) sub_candidates = candidates + chosen_enemies sub_candidates = [e for e in sub_candidates if vram_total + e.vram_value <= 64] if not sub_candidates: num_enemies = len(chosen_enemies) break chosen_enemies.append(random.choice(sub_candidates)) random.shuffle(chosen_enemies) def mutate_coordinate((x, y)): x = mutate_normal(x, minimum=self.lower_x, maximum=self.upper_x) y = mutate_normal(y, minimum=self.lower_y, maximum=self.upper_y) return (x, y) def get_distance((x1, y1), (x2, y2)): return ((x1-x2)**2 + (y1-y2)**2)**0.5
def mutate(self): global chest_items if self.is_key: return if self.index in [0x6A, 0x6B, 0x6C, 0x6E]: self.contents = 0x2A return any_left = self.desirable_left + self.undesirable_left value = None if self.is_consumable and (not any_left or random.randint(1, 7) != 7): self.contents = random.choice(self.consumable_options) return elif self.is_consumable: if self.undesirable_left and (not self.desirable_left or random.randint(1, 10) != 10): value = self.undesirable_left.pop() else: value = self.desirable_left.pop() if value is None: if self.desirable_left: value = self.desirable_left.pop() elif self.undesirable_left: value = self.undesirable_left.pop() else: value = 0x12 # seed if (value not in [0x12, 0x14] and value in DESIRABLE_ITEMS and self.is_consumable): self.well_hidden.add(value) self.contents = value
def mutate_magic_bits(self): self.reseed(salt="magicbit") for attr in self.magic_bits_attributes: value = getattr(self, attr) sort_func = lambda x: (bin(value ^ x).count('1'), random.random(), value) all_values = set([o.old_data[attr] for o in self.every] + [value]) all_values = sorted(all_values, key=sort_func) assert all_values[0] == value max_index = len(all_values) - 1 a = random.randint(0, random.randint(0, random.randint(0, max_index))) b = random.randint(0, max_index) if a > b: a, b = b, a index = int( round((b * self.random_degree) + (a * (1 - self.random_degree)))) new_value = all_values[index] assert (value | new_value) == 0xFFFF & (value | new_value) new_value = new_value ^ value for i in xrange(16): mask = (1 << i) if random.random() > max(self.random_degree, 0.5): if (new_value & mask): new_value = new_value ^ mask value = value ^ new_value setattr(self, attr, value)
def mutate(self): global chest_items if self.is_key: return if self.index in [0x6A, 0x6B, 0x6C, 0x6E]: self.contents = 0x2A return any_left = self.desirable_left + self.undesirable_left value = None if self.is_consumable and (not any_left or random.randint(1, 7) != 7): self.contents = random.choice(self.consumable_options) return elif self.is_consumable: if self.undesirable_left and ( not self.desirable_left or random.randint(1, 10) != 10): value = self.undesirable_left.pop() else: value = self.desirable_left.pop() if value is None: if self.desirable_left: value = self.desirable_left.pop() elif self.undesirable_left: value = self.undesirable_left.pop() else: value = 0x12 # seed if (value not in [0x12, 0x14] and value in DESIRABLE_ITEMS and self.is_consumable): self.well_hidden.add(value) self.contents = value
def rank(self): if hasattr(self, "_rank"): return self._rank price = PriceObject.get(self.index).price if self.banned: self._rank = -1 elif price == 0 and not self.is_key: self._rank = random.randint(1, random.randint(1, 999)) elif price == 0: self._rank = -1 elif self.is_frog_coin_item: self._rank = price * 50 elif price > 1000: self._rank = price / 2 elif self.rare and self.is_consumable: rank = 2 * price if price <= 50: rank = rank * 50 if self.reuseable: rank = rank * 4 self._rank = rank elif self.rare and self.is_armor: self._rank = price * 3 elif self.index == 0x5e: # quartz charm self._rank = 999 elif self.rare and self.is_accessory: self._rank = price * 2 else: self._rank = price self._rank += (1 - (self.index / 1000.0)) return self.rank
def mutate_all(cls): for group in cls.groups.values(): for o in group: while o.level >= 100 or o.level == 0: other = random.choice(group) o.level = random.randint(2, random.randint(2, 99)) o.increase = max(1, other.increase) o.mutate()
def mutate_all(cls): for group in cls.groups.values(): for o in group: while o.level >= 100 or o.level == 0: other = random.choice(group) o.level = random.randint(2, random.randint(2, 99)) o.increase = max(1, other.increase) o.mutate()
def unbecome_frog_coin_item(self): if not self.is_frog_coin_item: return False factor = float(random.randint(50, random.randint(50, 100))) price = int(round(self.price * factor)) PriceObject.get(self.index).price = min(price, 1998) self._is_frog_coin_item = False return True
def mutate(self): if random.choice([True, False]): level = max([r for r in self.reqs if 1 <= r <= 8]) else: level = random.randint(1, 4) + random.randint(0, 4) newreqs = [level, random.randint(1, level)] if self.is_triple: newreqs.append(random.randint(1, level)) random.shuffle(newreqs) self.reqs[:len(newreqs)] = newreqs
def mutate(self): if random.choice([True, False]): level = max([r for r in self.reqs if 1 <= r <= 8]) else: level = random.randint(1, 4) + random.randint(0, 4) newreqs = [level, random.randint(1, level)] if self.is_triple: newreqs.append(random.randint(1, level)) random.shuffle(newreqs) self.reqs[:len(newreqs)] = newreqs
def become_frog_coin_item(self): if self.is_frog_coin_item: return False factor = float(random.randint(random.randint(10, 50), 50)) if self.rare: price = int(round(self.rank / factor)) else: price = int(round(self.price / factor)) PriceObject.get(self.index).price = min(max(price, 1), 50) self._is_frog_coin_item = True return True
def become_boss(self): flamerus_rank = MonsterObject.get(0x4a).rank battlefields = [ bf for bf in BattleFormationObject.ranked if bf.index < 20 ] my_index = battlefields.index(self) candidates = [ m for m in MonsterObject.ranked if m.rank >= flamerus_rank ] new_index = int(round(my_index * (len(candidates) / 20.0))) new_index = mutate_normal(new_index, minimum=0, maximum=len(candidates) - 1) leader = candidates[new_index] candidates = [m for m in MonsterObject.ranked if m.rank < leader.rank] max_index = len(candidates) - 1 follow_index = random.randint(random.randint(0, max_index), max_index) follower = candidates[follow_index].index if random.randint(0, max_index) >= follow_index: follow2_index = random.randint( random.randint(max_index - follow_index, max_index), max_index) follower2 = candidates[follow2_index].index new_ids = [follower, leader.index, follower2] else: new_ids = [leader.index, follower, 0xFF] f = FormationObject.get_unused() f.special_boss = True f.enemy_ids = new_ids self.formation_ids = [f.index] * 3 f.mutated = True br = BattleRoundsObject.get(self.index) br.num_rounds = 1 br.mutated = True if "t" not in get_flags(): return br2 = BattleRewardObject.get(self.index) br2.reward = 0x4000 done_items = [ t.reward & 0xFF for t in BattleRewardObject.every if hasattr(t, "mutated") and t.mutated and t.reward & 0x4000 ] if TreasureIndexObject.well_hidden: value = random.choice(sorted(TreasureIndexObject.well_hidden)) TreasureIndexObject.well_hidden.remove(value) else: value = random.choice([ i for i in DESIRABLE_ITEMS if i != 0x14 and i not in done_items ]) br2.reward |= value br2.mutated = True
def mutate(self): super(ArmorObject, self).mutate() if random.randint(1, 4) == 4: self.element = shuffle_bits(self.element) else: value = shuffle_bits(self.element >> 3, size=5) value = value << 3 self.element = self.element & 0x7 self.element |= value if self.index + self.first_name_index not in UNDESIRABLE_ITEMS: if self.status & 0x80 and random.randint(1, 10) == 10: return self.status &= 0x7F
def mutate(self): super(ArmorObject, self).mutate() if random.randint(1, 4) == 4: self.element = shuffle_bits(self.element) else: value = shuffle_bits(self.element >> 3, size=5) value = value << 3 self.element = self.element & 0x7 self.element |= value if self.index + self.first_name_index not in UNDESIRABLE_ITEMS: if self.status & 0x80 and random.randint(1, 10) == 10: return self.status &= 0x7F
def nudge_hue(hue): #designed for 'pure' hue: one 31, one 0, one anything new_color = hue[:] if len([h for h in hue if h not in [0, 31]]) > 0: new_color = [(h if h in [0, 31] else h + random.randint(-2, 2)) for h in hue] elif len([h for h in hue if h == 31]) >= 2: nudge_idx = random.choice( [i for i, h in enumerate(hue) if h == 31]) new_color[nudge_idx] -= random.randint(0, 3) elif 0 in hue: nudge_idx = random.choice([i for i, h in enumerate(hue) if h == 0]) new_color[nudge_idx] += random.randint(0, 3) new_color = [(c if c <= 31 else 31) for c in new_color] new_color = [(c if c >= 0 else 0) for c in new_color] # just in case return new_color
def mutate(self): item = None if self.contents & 0x8000: value = (self.contents & 0x7FFF) << 1 elif self.contents & 0xFF00: return else: item = ItemObject.get(self.contents & 0xff) if item is None: return if item.rare: new_item = item.get_similar() self.contents = new_item.full_index return elif not item.buyable: return value = item.rank_price if random.randint(1, 20) == 20: value = min(65000, max(0, value)) value = mutate_normal(value, minimum=0, maximum=65000, random_degree=self.random_degree) self.contents = 0x8000 | (value >> 1) return if item is None: item = [ i for i in ItemObject.every_buyable if i.rank_price <= value ][-1] new_item = item.get_similar() self.contents = new_item.full_index
def randomize_all(cls): meats = {m.meat.old_data['meat'] for m in MonsterObject.every} for meat in sorted(meats): monsters = [m for m in MonsterObject.every if m.meat.old_data['meat'] == meat and m.index <= MonsterObject.MAX_EVOLVE_INDEX] if not monsters: assert meat >= 0xc0 continue assert len(monsters) == 5 assert monsters[-1].level == 0xb assert monsters == sorted(monsters, key=lambda m: m.level) new_levels = set([]) for m in monsters[:4]: new_level = mutate_normal( m.level, minimum=1, maximum=0xa, wide=True, random_degree=MonsterLevelObject.random_degree) new_levels.add(new_level) while len(new_levels) < 4: new_levels.add(random.randint(1, 0xa)) new_levels = sorted(new_levels) for level, monster in zip(new_levels, monsters): assert 1 <= level <= 0xa MonsterLevelObject.get(monster.index).set_level(level) super(MonsterLevelObject, cls).randomize_all()
def mutate(self): item = None if self.contents & 0x8000: value = (self.contents & 0x7FFF) << 1 elif self.contents & 0xFF00: return else: item = ItemObject.get(self.contents & 0xff) if item is None: return if item.rare: new_item = item.get_similar() self.contents = new_item.full_index return elif not item.buyable: return value = item.rank_price if random.randint(1, 20) == 20: value = min(65000, max(0, value)) value = mutate_normal(value, minimum=0, maximum=65000, random_degree=self.random_degree) self.contents = 0x8000 | (value >> 1) return if item is None: item = [i for i in ItemObject.every_buyable if i.rank_price <= value][-1] new_item = item.get_similar() self.contents = new_item.full_index
def randomize_battle_animations(): raise NotImplementedError pointers = [1, 2, 7, 0xa, 0xb, 0xc, 0xd] pointers = [p + 0xd4000 for p in pointers] short = [0, 3, 8, 0xa, 0xc] longg = [2, 4, 6] special = [0xd, 33] restricted = [6] f = open(get_outfile(), "r+b") for p in pointers: if random.choice([True, False]): continue f.seek(p) value = ord(f.read(1)) container = [l for l in [short, longg] if value in l][0] notcontainer = [l for l in [short, longg] if l is not container][0] if random.randint(1, 100) == 100: # use special value = random.choice(special) elif random.choice([True, False]): # use same type value = random.choice(container) else: # use different type candidates = [v for v in notcontainer if v not in restricted] value = random.choice(candidates) f.seek(p) f.write(chr(value)) f.close()
def full_randomize(cls): if hasattr(cls, "after_order"): for cls2 in cls.after_order: if not (hasattr(cls2, "randomized") and cls2.randomized): raise Exception("Randomize order violated.") for c in CharacterObject.every: c.known_spells = 0 spells = range(0x1b) spells.remove(7) # group hug random.shuffle(spells) supplemental = [0xFF] * 3 spells = spells + supplemental charspells = defaultdict(list) while spells: valid = [i for i in range(5) if len(charspells[i]) < 5 or (len(charspells[i]) < 6 and i != 1)] chosen = random.choice(valid) spell = spells.pop(0) if spell == 0xFF: valid = [s for s in range(0x1b) if s not in charspells[i] and s != 7] # group hug spell = random.choice(valid) charspells[chosen].append(spell) charspells[1].insert(random.randint(0, 5), 7) for l in LearnObject.every: l.spell = 0xFF for i in range(5): charlevels = sorted(random.sample(range(2, 20), 5)) spells = charspells[i] c = CharacterObject.get(i) c.known_spells |= (1 << spells[0]) for l, s in zip(charlevels, spells[1:]): l = LearnObject.get_by_character(i, l-2) l.spell = s cls.randomized = True
def randomize_battle_animations(): raise NotImplementedError pointers = [1, 2, 7, 0xa, 0xb, 0xc, 0xd] pointers = [p + 0xd4000 for p in pointers] short = [0, 3, 8, 0xa, 0xc] longg = [2, 4, 6] special = [0xd, 33] restricted = [6] f = open(get_outfile(), "r+b") for p in pointers: if random.choice([True, False]): continue f.seek(p) value = ord(f.read(1)) container = [l for l in [short, longg] if value in l][0] notcontainer = [l for l in [short, longg] if l is not container][0] if random.randint(1, 100) == 100: # use special value = random.choice(special) elif random.choice([True, False]): # use same type value = random.choice(container) else: # use different type candidates = [v for v in notcontainer if v not in restricted] value = random.choice(candidates) f.seek(p) f.write(chr(value)) f.close()
def mutate(self): if "f" not in get_flags(): return if (self.index < 20 and random.randint(1, 4) == 4) or ( self.index == 19 and BattleFormationObject.num_special < 5): self.become_boss() BattleFormationObject.num_special += 1 return if self.is_boss: return if self.index >= 20: leaders = [f.leader for f in self.formations] maxrank = max([f.maxrank for f in self.formations]) assert len(set(leaders)) == 1 leader = leaders[0] candidates = [ f for f in FormationObject.every if f.leader == leader and f.maxrank <= maxrank ] else: candidates = list(FormationObject.every) new_ids = [f.get_similar(candidates).index for f in self.formations] if len(set(new_ids)) < len(set(self.formation_ids)): return self.formation_ids = new_ids
def mutate(self): if "f" not in get_flags(): return if (self.index < 20 and random.randint(1, 4) == 4) or ( self.index == 19 and BattleFormationObject.num_special < 5): self.become_boss() BattleFormationObject.num_special += 1 return if self.is_boss: return if self.index >= 20: leaders = [f.leader for f in self.formations] maxrank = max([f.maxrank for f in self.formations]) assert len(set(leaders)) == 1 leader = leaders[0] candidates = [f for f in FormationObject.every if f.leader == leader and f.maxrank <= maxrank] else: candidates = list(FormationObject.every) new_ids = [f.get_similar(candidates).index for f in self.formations] if len(set(new_ids)) < len(set(self.formation_ids)): return self.formation_ids = new_ids
def become_boss(self): flamerus_rank = MonsterObject.get(0x4a).rank battlefields = [bf for bf in BattleFormationObject.ranked if bf.index < 20] my_index = battlefields.index(self) candidates = [m for m in MonsterObject.ranked if m.rank >= flamerus_rank] new_index = int(round(my_index * (len(candidates) / 20.0))) new_index = mutate_normal(new_index, minimum=0, maximum=len(candidates)-1) leader = candidates[new_index] candidates = [m for m in MonsterObject.ranked if m.rank < leader.rank] max_index = len(candidates)-1 follow_index = random.randint(random.randint(0, max_index), max_index) follower = candidates[follow_index].index if random.randint(0, max_index) >= follow_index: follow2_index = random.randint( random.randint(max_index-follow_index, max_index), max_index) follower2 = candidates[follow2_index].index new_ids = [follower, leader.index, follower2] else: new_ids = [leader.index, follower, 0xFF] f = FormationObject.get_unused() f.special_boss = True f.enemy_ids = new_ids self.formation_ids = [f.index] * 3 f.mutated = True br = BattleRoundsObject.get(self.index) br.num_rounds = 1 br.mutated = True if "t" not in get_flags(): return br2 = BattleRewardObject.get(self.index) br2.reward = 0x4000 done_items = [t.reward & 0xFF for t in BattleRewardObject.every if hasattr(t, "mutated") and t.mutated and t.reward & 0x4000] if TreasureIndexObject.well_hidden: value = random.choice(sorted(TreasureIndexObject.well_hidden)) TreasureIndexObject.well_hidden.remove(value) else: value = random.choice([i for i in DESIRABLE_ITEMS if i != 0x14 and i not in done_items]) br2.reward |= value br2.mutated = True
def bit_random_add(self, attr, rate=0.5): size = self.get_bit_width(attr) while random.random() <= rate: mask = 1 << random.randint(0, size-1) value = getattr(self, attr) if value & mask: break setattr(self, attr, value | mask)
def intershuffle(cls): candidates = sorted( [jco for jco in JobCrystalObject.every if jco.intershuffle_valid], key=lambda jco: (jco.ability_ap_rank, jco.signature)) shuffled = [] while candidates: max_index = len(candidates) - 1 index = random.randint(0, max_index) degree = JobCrystalObject.random_degree**0.25 if degree <= 0.5: degree = degree * 2 a, b = 0, index else: degree = (degree - 0.5) * 2 a, b = index, max_index index = int(round((a * (1 - degree)) + (b * degree))) index = random.randint(0, index) chosen = candidates[index] shuffled.append(chosen) candidates.remove(chosen) candidates = sorted(shuffled, key=lambda jco: (jco.rank, jco.signature)) if 'GBA' not in get_global_label(): assert len(candidates) == len(shuffled) == 21 else: assert len(candidates) == len(shuffled) == 25 for c, s in zip(candidates, shuffled): c.crystal_index = s.old_data["crystal_index"] freelancer = [jco for jco in candidates if jco.is_freelancer][0] fight_crystals = [jco for jco in shuffled if jco.has_fight_command] if freelancer not in fight_crystals: assert not freelancer.has_fight_command chosen = fight_crystals[0] freelancer.crystal_index, chosen.crystal_index = ( chosen.crystal_index, freelancer.crystal_index) assert freelancer.has_fight_command if 'r' in get_flags(): chance = int(RemoveJobs.random_degree * 100) print('Removing jobs ({}% chance)...'.format(chance)) for c in candidates: if random.random() < RemoveJobs.random_degree: c.crystal_index = freelancer.crystal_index
def shuffle(self): spells = [s for s in self.spell_queue if s != 0xFF] if spells: length = random.randint(len(set(spells)), 8) temp = sorted(set(spells)) while len(temp) < length: temp.append(random.choice(spells)) random.shuffle(temp) self.spell_queue = temp skills = [s for s in self.skill_queue if s != 0xFF] if skills: length = random.randint(len(set(skills)), 4) temp = sorted(set(skills)) while len(temp) < length: temp.append(random.choice(skills)) random.shuffle(temp) self.skill_queue = temp
def bit_random_remove(self, attr, rate=0.5): size = self.get_bit_width(attr) while random.random() <= rate: mask = 1 << random.randint(0, size-1) mask = mask ^ ((2**size)-1) value = getattr(self, attr) if value == value & mask: break setattr(self, attr, value & mask)
def mutate(self): value = mutate_normal(self.price, minimum=0, maximum=65000, random_degree=self.random_degree) value = value * 2 power = 0 while value > 100: value /= 10 power += 1 value = (value * (10**power)) / 2 self.price = value if self.equippable and not self.is_weapon: self.equippable = random.randint(1, 127) << 1
def mutate(self): oldstats = {} for key in self.mutate_attributes: oldstats[key] = getattr(self, key) super(MonsterObject, self).mutate() if self.is_boss: for (attr, oldval) in oldstats.items(): if getattr(self, attr) < oldval: setattr(self, attr, oldval) if self.is_boss: while True: chance = random.randint(0, 3) if chance == 0: break if chance == 1: self.resistances |= (1 << random.randint(4, 7)) elif chance == 2: self.immunities |= (1 << random.randint(0, 3)) elif chance == 3: weak = (1 << random.randint(4, 7)) if self.weaknesses_approach & weak: self.weaknesses_approach ^= weak else: resistances = shuffle_bits(self.resistances >> 4, size=4) self.resistances = resistances << 4 self.immunities = shuffle_bits(self.immunities, size=4) weak = shuffle_bits(self.weaknesses_approach >> 4, size=4) self.weaknesses_approach &= 0x0F self.weaknesses_approach |= (weak << 4) if random.randint(1, 3) == 3: self.hit_special_defense ^= 0x2 self.hit_special_defense ^= (random.randint(0, 3) << 2)
def mutate(self): if self.rank <= 0 and self.contents: return self.reseed(salt="mut") partner = random.choice([ c for c in self.every if c.rank > 0 and c.item_type > 0 and c.contents > 0 ]) value = self.rank if value <= 0: high = random.randint(0, partner.rank) low = random.randint(0, high) value = int( round((high * self.random_degree) + (low * (1 - self.random_degree)))) if not partner.get_bit("contains_item"): value = random.randint(int(round(value**0.9)), value) value = min(value, 65537) value = mutate_normal(value, 1, 65537, random_degree=self.random_degree) value = min(value, 65535) self.set_money_amount(value) else: partner = partner.item candidates = [c for c in partner.ranked if 0 < c.rank <= value] if not candidates: candidates = [c for c in partner.ranked if c.rank > 0] chosen = candidates[0] else: chosen = candidates[-1] chosen = chosen.get_similar( random_degree=ChestObject.random_degree) assert chosen.index > 0 self.set_item(chosen)
def mutate(self): if self.index in self.restricted_indexes: return if self.multiplier <= 7 and not self.buffs: new_multiplier = random.randint(0, random.randint( 0, random.randint(0, random.randint(0, 8)))) if new_multiplier > self.multiplier: self.misc_multiplier = new_multiplier if not self.buffs and random.randint(1, 5) == 5: i = random.randint(0, 6) if i != 4 or random.randint(1, 10) == 10: self.ailments = (0 | 1 << i) if self.buffs and random.choice([True, False]): self.buffs |= 1 << random.randint(3, 6) super(MonsterAttackObject, self).mutate()
def mutate(self): if self.index == 0x42: # Behemoth return oldstats = {} for key in self.mutate_attributes: oldstats[key] = getattr(self, key) super(MonsterObject, self).mutate() if self.is_boss: for (attr, oldval) in oldstats.items(): if getattr(self, attr) < oldval: setattr(self, attr, oldval) for attr in ["resistances", "weaknesses", "immunities"]: if self.is_boss and attr == "immunities": continue value = getattr(self, attr) >> 4 value = shuffle_bits(value, size=4) << 4 while random.choice([True, False]): attr = random.choice(["resistances", "weaknesses", "immunities"]) value = getattr(self, attr) if attr != "immunities" and bin(value).count("1") > 6: continue flag = (1 << random.randint(0, 7)) if ((attr == "weaknesses" or not self.is_boss) and random.randint(1, 10) == 10): value ^= flag else: if attr != "immunities" and bin(value).count("1") > 4: continue value |= flag setattr(self, attr, value) self.resistances = self.resistances & 0xF0 if self.hp < 200 or self.index in [0x43, 0x4a]: return if random.randint(1, 4) == 4: self.counter &= 0x0F newcounter = random.choice([0, 0, 0x10, 0x20, 0x40, 0x80, 0x80]) self.counter |= newcounter
def mutate(self): if self.index == 0x42: # Behemoth return oldstats = {} for key in self.mutate_attributes: oldstats[key] = getattr(self, key) super(MonsterObject, self).mutate() if self.is_boss: for (attr, oldval) in oldstats.items(): if getattr(self, attr) < oldval: setattr(self, attr, oldval) for attr in ["resistances", "weaknesses", "immunities"]: if self.is_boss and attr == "immunities": continue value = getattr(self, attr) >> 4 value = shuffle_bits(value, size=4) << 4 while random.choice([True, False]): attr = random.choice(["resistances", "weaknesses", "immunities"]) value = getattr(self, attr) if attr != "immunities" and bin(value).count("1") > 6: continue flag = (1 << random.randint(0, 7)) if ((attr == "weaknesses" or not self.is_boss) and random.randint(1, 10) == 10): value ^= flag else: if attr != "immunities" and bin(value).count("1") > 4: continue value |= flag setattr(self, attr, value) self.resistances = self.resistances & 0xF0 if self.hp < 200 or self.index in [0x43, 0x4a]: return if random.randint(1, 4) == 4: self.counter &= 0x0F newcounter = random.choice([0, 0, 0x10, 0x20, 0x40, 0x80, 0x80]) self.counter |= newcounter
def mutate(self): value = mutate_normal(self.price, minimum=0, maximum=65000, random_degree=self.random_degree) value = value * 2 power = 0 while value > 100: value /= 10 power += 1 value = (value * (10**power)) / 2 self.price = value if self.equippable and not self.is_weapon: self.equippable = random.randint(1, 127) << 1
def mutate_stat_curve(cls, class_index, attr): lus = [ lu for lu in LevelUpObject.every if lu.class_index == class_index ] assert len(lus) == 99 lus = lus[:98] assert len(lus) == 98 lus[0].reseed(salt="fullmut" + attr) bits = [lu.get_bit(attr) for lu in lus] value = len([b for b in bits if b]) base_ratio = value / float(len(lus)) max_ratio = max([ cls.get_class_stat_score(i, attr) / float(len(lus)) for i in xrange(6) ]) assert max_ratio >= base_ratio base_ratio = mutate_normal(base_ratio, 0, max_ratio, wide=False, random_degree=LevelUpObject.random_degree, return_float=True) remaining = list(lus) while remaining: ratio = mutate_normal(base_ratio, 0, max_ratio, wide=False, random_degree=LevelUpObject.random_degree, return_float=True) max_index = len(remaining) - 1 divider = random.randint(0, max_index) aa = remaining[:divider] bb = remaining[divider:] if len(aa) > len(bb): aa, bb = bb, aa elif len(aa) == len(bb) and random.choice([True, False]): aa, bb = bb, aa if random.choice([True, True, False]): to_set, remaining = aa, bb else: to_set, remaining = bb, aa assert len(to_set + remaining) == max_index + 1 for lu in to_set: value = (random.random() < ratio) lu.set_bit(attr, value)
def rank(self): if not self.intershuffle_valid: return -1 if self.is_magic: price = SpellPriceObject.get(self.value).rank elif self.is_item: price = PriceObject.get(self.value).rank elif self.is_monster: return random.randint( 0, max(i.rank for i in PriceObject.every if not i.is_magic)) else: price = self.value * (10**(self.treasure_type & 0x7)) if not self.mutate_valid and not self.is_magic: price += 60000 return price
def randomize(self): if self.index == 6: candidates = [jao.ability for jao in JobAbilityObject.groups[self.index] if jao.ability > 0x4D] if candidates: self.commands[1] = random.choice(candidates) return if self.index > 20: return old_commands = list(self.commands) candidates = [jao.ability for jao in JobAbilityObject.groups[self.index] if jao.ability <= 0x4D] if self.index == 20: candidates += [5, 2] redundant_groups = [ range(0x2C, 0x32), range(0x32, 0x38), range(0x38, 0x3E), range(0x3E, 0x44), ] for i, ability in enumerate(self.commands): if not candidates: break if ability > 0 and random.randint(1, 3) == 3: new_command = random.choice(candidates) if new_command in self.commands: continue self.commands[i] = new_command for rg in redundant_groups: if len(set(self.commands) & set(rg)) >= 2: self.commands[i] = ability break else: candidates.remove(new_command) if ability in candidates: candidates.remove(ability) if not set(self.commands) & set([5, 0x2b, 2]): self.commands = old_commands for rg in redundant_groups: if len(set(self.commands) & set(rg)) >= 2: assert False
def price_cleanup(self): if 'phantomthief' in get_activated_codes(): self.price = 0 if self.price == self.old_data['price']: return price = self.price * 2 counter = 0 while price >= 100: price = int(round(price / 10.0)) counter += 1 if random.randint(1, 10) == 10: break price = price * (10**counter) self.price = price // 2 if self.price % 10: self.price += 10 - (self.price % 10)
def mutate(self): if self.is_item and self.value == 0x14: # Exit battlefield is fixed return self.reward = 0 done_items = [ t.reward & 0xFF for t in BattleRewardObject.every if hasattr(t, "mutated") and t.mutated and t.reward & 0x4000 ] assert len(done_items) == len(set(done_items)) if TreasureIndexObject.desirable_left: value = TreasureIndexObject.desirable_left.pop() if value == 0x14 and TreasureIndexObject.desirable_left: value = TreasureIndexObject.desirable_left.pop() if value != 0x14: self.reward |= 0x4000 self.reward |= value if TreasureIndexObject.undesirable_left: remaining = [ i for i in TreasureIndexObject.undesirable_left if i not in BROKEN_ITEMS ] if remaining: value = remaining.pop() self.reward |= 0x4000 self.reward |= value TreasureIndexObject.undesirable_left.remove(value) if self.reward == 0: rewardtype = random.choice(["xp", "xp", "item", "gp"]) if rewardtype == "item": self.reward |= 0x4000 self.reward |= random.choice( sorted(set(DESIRABLE_ITEMS + UNDESIRABLE_ITEMS))) else: if rewardtype == "xp": self.reward |= 0x8000 self.reward |= random.randint(1, 0x3FF) if self.reward & 0x4000 and (self.reward & 0xFF) in done_items: self.reward = 0 return self.mutate()
def mutate(self): if self.is_item and self.value == 0x14: # Exit battlefield is fixed return self.reward = 0 done_items = [t.reward & 0xFF for t in BattleRewardObject.every if hasattr(t, "mutated") and t.mutated and t.reward & 0x4000] assert len(done_items) == len(set(done_items)) if TreasureIndexObject.desirable_left: value = TreasureIndexObject.desirable_left.pop() if value == 0x14 and TreasureIndexObject.desirable_left: value = TreasureIndexObject.desirable_left.pop() if value != 0x14: self.reward |= 0x4000 self.reward |= value if TreasureIndexObject.undesirable_left: remaining = [i for i in TreasureIndexObject.undesirable_left if i not in BROKEN_ITEMS] if remaining: value = remaining.pop() self.reward |= 0x4000 self.reward |= value TreasureIndexObject.undesirable_left.remove(value) if self.reward == 0: rewardtype = random.choice(["xp", "xp", "item", "gp"]) if rewardtype == "item": self.reward |= 0x4000 self.reward |= random.choice( sorted(set(DESIRABLE_ITEMS + UNDESIRABLE_ITEMS))) else: if rewardtype == "xp": self.reward |= 0x8000 self.reward |= random.randint(1, 0x3FF) if self.reward & 0x4000 and (self.reward & 0xFF) in done_items: self.reward = 0 return self.mutate()
def mutate(self): if bin(self.equippable).count('1') > 3: self.equippable = random.randint(1, 127) << 1
def mutate(self): if not self.unused: self.find_unused() old_ids = list(self.enemy_ids) if self.is_boss: boss = self.leader boss_index = boss.index if boss_index == 0x50: return new = [] upper = self.leader.rank for e in self.enemy_ids: if e == boss_index: continue if e == 0xFF and random.choice([True, False]): continue if e == 0xFF: lower = 0 else: lower = MonsterObject.get(e).rank candidates = [m for m in MonsterObject.ranked if lower <= m.rank < upper and m.index not in self.banned_bosses] if not candidates: return upper_index = max(len(candidates)-2, 0) index = random.randint(0, upper_index) index = random.randint(index/2, index) chosen = candidates[index] upper = min(upper, chosen.rank) new.append(chosen.index) if len(new) == 2: new = [new[0], boss_index, new[1]] else: new = new + [boss_index] while len(new) < 3: new += [0xFF] self.enemy_ids = new return if len(self.enemies) <= 1: return for i, e in enumerate(self.enemies): if len(self.enemies) >= 2 and i == 1: continue elif len(self.enemies) == 1: continue new = e.get_similar() if new.index in self.banned_bosses: continue if new in self.done_bosses and random.randint(1, 10) != 10: continue self.enemy_ids[i] = new.index if new.is_boss: self.done_bosses.add(new) new_tuple = sorted(tuple(self.enemy_ids)) if new_tuple == sorted(tuple(old_ids)): return for f in FormationObject.every: if f.index == self.index: continue if sorted(tuple(f.enemy_ids)) == new_tuple: self.enemy_ids = old_ids break
def mutate(self): super(WeaponObject, self).mutate() if random.randint(1, 3) == 3: element = (1 << random.randint(3, 7)) self.element |= element