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 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 randomize(self): num_items = len(self.items) num_items = mutate_normal(num_items, minimum=1, maximum=8, random_degree=self.random_degree, wide=True) old_items = list(self.items) new_items = [] for _ in range(500): if len(new_items) == num_items: break buyable_check = not (random.random() < self.random_degree) chosen_class = random.choice(old_items).shop_item_class chosen_price = random.choice(old_items) candidates = [a for a in AttributeObject.every if a.index <= 0x7f and a.rank >= 0 and a.shop_item_class == chosen_class and a.is_buyable >= buyable_check] candidates = [c for c in candidates if c not in new_items] if not candidates: continue chosen = chosen_price.get_similar( candidates=candidates, random_degree=self.random_degree, override_outsider=True) new_items.append(chosen) else: raise Exception('Unable to populate shop.') for i in new_items: if not i.is_buyable: ItemPriceObject.get(i.index).price = 60000 self.item_indexes = [i.index for i in new_items]
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 intershuffle(cls): for e in cls.every: if e.rank < 0: continue for i in xrange(4): e2 = e.get_similar(random_degree=cls.random_degree**2) chosen = random.choice((e2.old_data["common"] * 2) + e2.old_data["uncommon"]) e.common[i] = chosen for i in xrange(2): e2 = e.get_similar(random_degree=cls.random_degree) chosen = random.choice(e2.old_data["common"] + (e2.old_data["uncommon"] * 4) + (e2.old_data["rare"] * 4)) e.uncommon[i] = chosen e2 = e.get_similar(random_degree=cls.random_degree**0.5) chosen = random.choice(e2.old_data["uncommon"] + (e2.old_data["rare"] * 4) + (e2.old_data["super_rare"] * 2)) e.rare[0] = chosen e2 = e.get_similar(random_degree=cls.random_degree**0.25) chosen = random.choice(e2.old_data["rare"] + (e2.old_data["super_rare"] * 2)) e.super_rare[0] = chosen
def choose_requirements(self): if not hasattr(self, "old_goal_requirements"): self.old_goal_requirements = None candidates = sorted([ r for r in self.requirements_locations if self.requirements_locations[r] & self.unreachable_locations ]) if not candidates: self.goal_requirements = None return None if self.goal_requirements in candidates: return self.goal_requirements candidates += [c for c in candidates if set(c) & self.assigned_items] candidates = sorted(candidates) chosen = random.choice(candidates) while True: candidates = [ c for c in candidates if len(c) > len(chosen) and self.requirements_locations[c] < self.requirements_locations[chosen] ] if candidates: newchoice = random.choice(candidates + [chosen]) if newchoice != chosen: chosen = newchoice continue break if self.goal_requirements != chosen: self.old_goal_requirements = self.goal_requirements self.goal_requirements = chosen return chosen
def mutate(self): oldstats = {} for key in self.mutate_attributes: oldstats[key] = getattr(self, key) super(MonsterObject, self).mutate() if self.get_bit("bosslike"): for (attr, oldval) in oldstats.items(): if getattr(self, attr) < oldval: setattr(self, attr, oldval) def is_resistance(val): return val >= 128 or val in [0, 1, 2] elements = ["fire", "water", "lightning", "shadow"] while random.choice([True, False]): el = random.choice(elements) if getattr(self, el) != 4 and random.choice([True, False]): continue value = random.choice( [0, 1, 2, 3, 4, 6, 8, 64, 128, 129, 132, 143]) if is_resistance(value) and not is_resistance(getattr(self, el)): for e in elements: if e == el: continue if not is_resistance(getattr(self, e)): break else: continue setattr(self, el, value)
def mutate(self): oldstats = {} for key in self.mutate_attributes: oldstats[key] = getattr(self, key) super(MonsterObject, self).mutate() if self.get_bit("bosslike"): for (attr, oldval) in oldstats.items(): if getattr(self, attr) < oldval: setattr(self, attr, oldval) def is_resistance(val): return val >= 128 or val in [0, 1, 2] elements = ["fire", "water", "lightning", "shadow"] while random.choice([True, False]): el = random.choice(elements) if getattr(self, el) != 4 and random.choice([True, False]): continue value = random.choice([0, 1, 2, 3, 4, 6, 8, 64, 128, 129, 132, 143]) if is_resistance(value) and not is_resistance(getattr(self, el)): for e in elements: if e == el: continue if not is_resistance(getattr(self, e)): break else: continue setattr(self, el, value)
def randomize(self): if self.index == 6: # berserker passive 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 "fight" in get_activated_codes() and ability == 5: pass elif ability > 0 and random.random() <= (self.random_degree**0.75): 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) while not set(self.commands) & set([5, 0x2b, 2]): i, c = random.choice(sorted(enumerate(old_commands))) if c in [5, 0x2b, 2]: self.commands[i] = c for rg in redundant_groups: if len(set(self.commands) & set(rg)) >= 2: assert False
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_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 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): for attr in ["steal_common", "steal_rare", "drop_common", "drop_rare"]: value = getattr(self, attr) if value > 0 and item_is_buyable(value): price = PriceObject.get(value).price setattr(self, attr, get_item_similar_price(price)) if random.choice([True, False]): if random.choice([True, False]): self.steal_common, self.drop_common = (self.drop_common, self.steal_common) if random.choice([True, False]): self.steal_rare, self.drop_rare = (self.drop_rare, self.steal_rare)
def mutate(self): if self.misc in [2, 4] and self.contents < 0x10: return partner = random.choice(FF2ChestObject.every) assert self.misc in [1, 2, 4] assert partner.misc in [1, 2, 4] if partner.misc == 1: if self.misc == 1: value = self.contents else: value = ff2_get_price(self.contents) self.misc = 1 value = min(65000, max(0, value)) self.contents = mutate_normal(value, 0, 65000, wide=True, random_degree=self.random_degree) else: if self.misc == 1: item = ff2_get_item_valued(self.contents) self.misc = 2 else: item = self.contents item = ff2_get_similar_item(item, random_degree=self.random_degree) self.contents = item assert self.misc in [1, 2, 4]
def randomize(self): if self.monster.morph_chance and not self.monster.banned: self.yoshi_cookie = random.choice( [i for i in ItemObject.every if i.is_consumable and not i.banned]).index else: self.yoshi_cookie = 0xFF
def randomize_all(cls): attributes = [AttributeObject.get(m.skill_index) for m in MutantSkillsObject.every] new_attributes = [] for old_attribute in attributes: candidates = [a for a in AttributeObject.every if a.get_bit('fixed') and a.rank >= 0 and a not in new_attributes] if old_attribute not in candidates: if old_attribute.get_bit('fixed'): # vanilla doesn't have non-fixed attributes # this is for romhack compatibility assert old_attribute in new_attributes template = random.choice(attributes) temp = [c for c in candidates if c.get_bit('use_battle') == template.get_bit('use_battle')] if temp: candidates = temp new_attribute = old_attribute.get_similar( candidates, random_degree=MutantSkillsObject.random_degree, override_outsider=True) new_attributes.append(new_attribute) assert len(new_attributes) == len(MutantSkillsObject.every) for new, mu in zip(new_attributes, MutantSkillsObject.every): mu.skill_index = new.index super(MutantSkillsObject, cls).randomize_all()
def mutate_all(cls): numgroups = len(cls.groups) reassignments = range(numgroups) random.shuffle(reassignments) reassignments = dict(zip(range(numgroups), reassignments)) for o in cls.every: o.groupindex = reassignments[o.groupindex] for n, group in sorted(cls.groups.items()): for i, o in enumerate(group): done = [o2.item for o2 in group[:i]] item = ItemObject.get(o.item) for _ in xrange(100): new_item = item.get_similar() if new_item.full_index not in done: break else: candidates = [ i for i in ItemObject.every_buyable if i.full_index not in done ] new_item = random.choice(candidates) o.item = new_item.full_index indices_sorted = sorted(group[:-1], key=lambda i: i.item) indices_sorted = [i.item for i in indices_sorted] for (a, b) in zip(group, indices_sorted): a.item = b
def full_cleanup(cls): if 'e' in get_flags(): rope_candidates = [ i for i in ItemObject.every if 0x12d7a <= i.pointer <= 0x12da6 ] if not any([i.item_type == 0xd for i in rope_candidates]): chosen = random.choice(rope_candidates) chosen.item_type = 0xd else: chosen = random.choice( [i for i in rope_candidates if i.item_type == 0xd]) rope_candidates.remove(chosen) if not any([i.item_type == 0xc for i in rope_candidates]): chosen = random.choice(rope_candidates) chosen.item_type = 0xc super(ItemObject, cls).full_cleanup()
def randomize_file_select(): if get_global_label() == "SMRPG_NA": addresses = [0x34757, 0x3489a, 0x34ee7, 0x340aa, 0x3501e] elif get_global_label() == "SMRPG_JP": addresses = [0x347d7, 0x3490d, 0x34f59, 0x340fa, 0x35099] else: return choices = {"peach": range(7, 13), "bowser": range(13, 19), "mallow": range(19, 25), "geno": range(25, 31), } values = random.choice(choices.values()) values = [values[i] for i in [0, 1, 0, 0, 1]] f = open(get_outfile(), "r+b") for addr, value in zip(addresses, values): f.seek(addr) f.write(chr(value)) if get_global_label() != "SMRPG_NA": return f.seek(0x3EF140) seed = str(get_seed()).center(10) f.write(seed) f.close()
def mutate_all(cls): numgroups = len(cls.groups) reassignments = range(numgroups) random.shuffle(reassignments) reassignments = dict(zip(range(numgroups), reassignments)) for o in cls.every: o.groupindex = reassignments[o.groupindex] for n, group in sorted(cls.groups.items()): for i, o in enumerate(group): done = [o2.item for o2 in group[:i]] item = ItemObject.get(o.item) for _ in xrange(100): new_item = item.get_similar() if new_item.full_index not in done: break else: candidates = [i for i in ItemObject.every_buyable if i.full_index not in done] new_item = random.choice(candidates) o.item = new_item.full_index indices_sorted = sorted(group[:-1], key=lambda i: i.item) indices_sorted = [i.item for i in indices_sorted] for (a, b) in zip(group, indices_sorted): a.item = b
def randomize_crystal_shards(): if "y" not in get_flags(): return FREELANCER, MIME = 0x84fc3, 0x91baf def map_crystal_job(value): return (7-(value%8)) + ((value/8)*8) def map_job_crystal(value): crystals = [c for c in range(24) if map_crystal_job(c) == value] assert len(crystals) == 1 return crystals[0] values = [] # galuf has no mime sprite addrs = [a for a in CRYSTAL_ADDRS if a not in [FREELANCER, MIME]] assert len(addrs) == 20 f = open(get_outfile(), "r+b") start_candidates = [j.index for j in JobCommandObject.every if j.commands[0] == 5 and j.index < 20] start_choice = random.choice(start_candidates) f.seek(FREELANCER) f.write(chr(map_job_crystal(start_choice))) remaining = [j.index for j in JobCommandObject.every if j.index != 20 and j.index != start_choice] random.shuffle(remaining) assert len(addrs) == len(remaining) == 20 for addr, j in zip(addrs, remaining): f.seek(addr) f.write(chr(map_job_crystal(j))) f.close() return values
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(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 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 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 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 ensure_item_access(index, day): item = ItemObject.get_by_index(index) ensure_shops = sorted(day_shops[day]) existing_this = [sio for sio in ShopItemObject.every if sio.item is item and not hasattr(sio, '_is_protected')] if existing_this: chosen = random.choice(existing_this) else: shuffled_shop_items = sorted( ShopItemObject.every, key=lambda sio: (not hasattr(sio, '_is_protected'), sio.signature)) seen_items = set([]) chosen = None for sio in shuffled_shop_items: if (sio.item in seen_items and not hasattr(sio, '_is_protected')): chosen = sio break seen_items.add(sio.item) chosen.shop_index = None chosen.day_available = min(day, chosen.day_available) chosen.item_index = index assert not hasattr(chosen, '_is_protected') chosen._is_protected = True if chosen.shop_index in ensure_shops: return True ensure_shops = sorted(ensure_shops) temp = [s for s in ensure_shops if len(ShopItemObject.get_items_by_shop_index(s)) < MAX_SHOP_INVENTORY] if temp: ensure_shops = temp if hasattr(item, 'brand') and item.brand <= 12: temp = [s for s in ensure_shops if ShopItemObject.get_primary_brand(s) == item.brand] if temp: ensure_shops = temp chosen.shop_index = random.choice(ensure_shops)
def insert_item(cls, item_type, item_index): candidates = [ s for s in ShopIndexObject.every if hasattr(s, "shop_rank") and s.shop_rank == 3 and not s.inserted_item ] chosen = random.choice(candidates) chosen.inserted_item = True chosen.item_type = item_type chosen.item_index = item_index
def cleanup(self): growth = CharGrowthObject.get(self.index) for attr in ["power", "stamina", "magic", "hit", "evade", "mdef"]: baseattr = "%s_base" % attr increase = getattr(growth, attr) * (self.level-1) / 100 initial = getattr(self, baseattr) + increase setattr(self, attr, initial) hpgroup = HPGrowthObject.getgroup(self.index) mpgroup = MPGrowthObject.getgroup(self.index) max_hp = mutate_normal(85, minimum=1, maximum=999, random_degree=self.random_degree) max_mp = mutate_normal(9, minimum=1, maximum=99, random_degree=self.random_degree) temp_level = 1 while temp_level < self.level: temp_level += 1 hpo = [o for o in hpgroup if temp_level <= o.level][-1] mpo = [o for o in mpgroup if temp_level <= o.level][-1] max_hp += hpo.increase max_mp += mpo.increase max_hp = min(999, max(max_hp, 1)) max_mp = min(99, max(max_mp, 1)) self.max_hp, self.hp = max_hp, max_hp self.max_mp, self.mp = max_mp, max_mp if self.level > 1: self.xp = sum([e.experience for e in ExperienceObject if e.index < (self.level-1)]) else: self.xp = 0 self.xpnext = ExperienceObject.get(self.level-1).experience for attr in ["helmet", "armor"]: current = getattr(self, attr) if self.can_equip(current): continue candidates = [c for c in ItemObject.every_equippable if getattr(c, "is_%s" % attr) and self.can_equip(c) and c.buyable] if not candidates: candidates = [c for c in ItemObject.every_equippable if getattr(c, "is_%s" % attr) and c.buyable] chosen = min(candidates, key=lambda c: c.rank_price) chosen.make_equippable(self.index) setattr(self, attr, chosen.full_index) current = ItemObject.get(self.accessory) if not self.can_equip(current): candidates = [c for c in Accessory2Object.every if self.can_equip(c)] if candidates: chosen = random.choice(candidates) chosen.make_equippable(self.index) self.accessory = chosen.full_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 randomize_counts(self): if self.index <= 0xf: # boss formation enumerated_fcounts = list(enumerate(self.fcounts)) random.shuffle(enumerated_fcounts) aas = [self.enemy_indexes[2] == 0 and self.index > 0, False] for ((i, fcount), aa) in zip(enumerated_fcounts, aas): counts = fcount.old_data['counts'] candidates = [f for f in FormationCountObject.every if f.validate_boss(counts, allow_add=aa)] if not candidates: chosen = fcount else: chosen = random.choice(candidates) self.counts[i] = chosen.index if aa: old_monsters = [self.monsters[j] for (j, c) in enumerate(counts) if c > 0] avg_rank = (sum([m.rank for m in old_monsters]) / len(old_monsters)) avg_hp = (sum([m.hp for m in old_monsters]) / len(old_monsters)) candidates = [m for m in MonsterObject.ranked if m.intershuffle_valid and m.rank < avg_rank and m.hp < avg_hp] max_index = len(candidates) - 1 randval = random.random() randomness = (1-self.random_degree) if randomness > 0: randval = randval ** (1 / randomness) else: randval = 0 index = int(round((1-randval) * max_index)) chosen = candidates[index] self.enemy_indexes[2] = chosen.index return for (i, fcount) in enumerate(self.fcounts): counts = fcount.old_data['counts'] candidates = sorted( FormationCountObject.every, key=lambda fc: (fc.get_distance(counts), fc.signature)) max_index = len(candidates) - 1 randval = random.random() if self.random_degree > 0: randval = randval ** (1 / self.random_degree) else: randval = 0 assert 0 <= randval <= 1 index = int(round(randval * max_index)) chosen = candidates[index] self.counts[i] = chosen.index assert self.fcounts[i] is chosen
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): valids = [s for s in StatBonusObject.every if s.intershuffle_valid and all([getattr(s, attr) for attr in self.intershuffle_attributes])] for attr in self.intershuffle_attributes: while getattr(self, attr) == 0: setattr(self, attr, getattr(random.choice(valids), attr)) for attr in LEVEL_STATS: self.set_stat(attr, mutate_normal( getattr(self, attr), minimum=0, maximum=0xf))
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): for attr in ["common_drop", "rare_drop"]: value = getattr(self, attr) if value == 0: continue while True: i = ItemObject.superget(value - 1) i = i.get_similar() if ("fam" in get_activated_codes() and i.item_type == 2 and i.index in HP_HEALING_ITEMS): continue if ("gun" in get_activated_codes() and i.item_type == 3): i = WeaponObject.get(random.choice(GUNS)) if ("fist" in get_activated_codes() and i.item_type == 3): i = WeaponObject.get(random.choice(FISTS)) if ("ass" in get_activated_codes() and i.item_type == 3): i = WeaponObject.get(random.choice(KNIVES)) value = (value & 0xFF00) | (i.superindex + 1) setattr(self, attr, value) break
def get_similar(self): if self.rare: result = random.choice(self.every_rare) elif self.buyable: buyables = self.every_buyable index = buyables.index(self) index = mutate_normal(index, minimum=0, maximum=len(buyables)-1, random_degree=self.random_degree) result = buyables[index] else: result = self return result
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.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 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