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 full_randomize(cls): super(ShopObject, cls).full_randomize() for pretty_shop_type in ["Magic", "Weapons", "Armor", "Items"]: shops = [s for s in ShopObject.ranked if s.rank > 0 and s.pretty_shop_type == pretty_shop_type] itemranks = defaultdict(set) all_items = set([]) avg = 0 for n, s in enumerate(shops): items = [i for i in s.items if i] itemranks[n] |= set(items) all_items |= set(items) avg += len(items) avg /= float(len(shops)) for n, s in enumerate(shops): num_items = int(round(mutate_normal(avg, minimum=1, maximum=8))) chosen_items = set([]) while len(chosen_items) < num_items: chosen_rank = mutate_normal(n, minimum=0, maximum=len(shops)-1) candidates = sorted([i for i in itemranks[chosen_rank] if i not in chosen_items]) if not candidates: a = n b = len(shops) / 2 a, b = min(a, b), max(a, b) n = random.randint(a, b) continue item = random.choice(candidates) chosen_items.add(item) s.items = sorted(chosen_items) all_items -= chosen_items all_items = sorted(all_items) while all_items: item = all_items.pop() candidates = [s for s in shops if len(s.items) < 8] s = random.choice(candidates) s.items.append(item)
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 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 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.") cls.randomized = True xps = sorted([mutate_normal(l.xp, minimum=1, maximum=65535) for l in cls.every]) prev = 0 assert len(cls.every) == len(xps) for i, (l, xp) in enumerate(zip(cls.every, xps)): factor = min(i / (len(xps)/2.0), 1.0) xp = int(round((xp + (xp * factor))/2)) while xp <= prev: xp += 1 l.xp = xp prev = xp
def get_item_similar_price(price=None, magic=False): if magic: shops = ShopObject.get_magic_shops() else: shops = ShopObject.get_nonmagic_shops() items = set([]) for s in shops: items |= set(s.items) if magic: items = sorted([(PriceObject.get(i+0x100).price, i) for i in items]) else: items = sorted([(PriceObject.get(i).price, i) for i in items]) newprice = mutate_normal(price, minimum=1, maximum=65000) items = items[:1] + [i for (p, i) in items if p <= newprice] chosen = items[-1] return chosen
def mutate(self): if not self.mutate_valid: return chance = random.random() price = self.rank if chance <= 0.85: if chance <= 0.70: # item self.treasure_type = 0x40 else: # magic self.treasure_type = 0x20 self.value = get_item_similar_price(price, magic=self.is_magic) else: # gold price = mutate_normal(price, minimum=1, maximum=65000) exponent = 0 while price >= 100: price /= 10 exponent += 1 self.treasure_type = exponent self.value = price
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 1 <= self.level <= 99: new_level = mutate_normal(self.level, minimum=1, maximum=99) old_divisibility = divisibility_rank(self.level) new_divisibility = divisibility_rank(new_level) if new_divisibility < old_divisibility: if not self.is_boss: self.level = new_level else: difference = float(new_level) / self.level if random.random() < difference: self.level = new_level elif not self.is_boss and random.choice([True, False]): self.level = new_level oldimmunities = self.status_immunities for attr in ["elemental_immunities", "absorptions", "weaknesses"]: if not self.is_boss: self.bit_shuffle(attr) else: self.bit_random_add(attr) if not self.is_boss: self.bit_shuffle("cant_evade") self.bit_random_add("cant_evade") self.bit_random_remove("cant_evade") oldstatus = self.status self.bit_random_add("status_immunities") self.bit_random_add("status", rate=0.1) newstatus = self.status newstatus = newstatus & (newstatus ^ oldimmunities) self.status = (oldstatus & oldimmunities) | newstatus self.bit_random_add("command_immunity")
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.") cls.randomized = True curves = defaultdict(list) for character_index in range(5): c = CharacterObject.get(character_index) for attr in LEVEL_STATS: value = getattr(c, attr) for l in cls.every: if l.character_id == c.index and l.level <= 20: value += getattr(l, attr) value = mutate_normal(value, maximum=255) fixed_points = [(1, 0), (20, value)] for _ in xrange(3): dex = random.randint(1, len(fixed_points)-1) lower_level, lower_value = fixed_points[dex-1] upper_level, upper_value = fixed_points[dex] if upper_level - lower_level < 4: continue level_interval = (upper_level - lower_level) / 2 value_interval = (upper_value - lower_value) / 2 level = (lower_level + random.randint(0, level_interval) + random.randint(0, level_interval)) if level <= lower_level or level >= upper_level: continue value = (lower_value + random.randint(0, value_interval) + random.randint(0, value_interval)) fixed_points.append((level, value)) fixed_points = sorted(fixed_points) for ((l1, v1), (l2, v2)) in zip(fixed_points, fixed_points[1:]): ldist = l2 - l1 vdist = v2 - v1 for l in range(l1+1, l2): factor = (l - l1) / float(ldist) v = v1 + (factor * vdist) fixed_points.append((l, int(round(v)))) fixed_points = sorted(fixed_points) levels, values = zip(*fixed_points) assert len(fixed_points) == 20 assert levels == tuple(sorted(levels)) assert values == tuple(sorted(values)) increases = [] for v1, v2 in zip(values, values[1:]): increases.append(v2-v1) frontload_factor = random.random() * random.random() if attr in ["defense", "magic_defense"]: frontload_factor *= random.random() frontloaded = 0 for n, inc in enumerate(increases): max_index = len(increases) - 1 factor = (((max_index-n) / float(max_index)) * frontload_factor) amount = int(round(inc * factor)) frontloaded += amount increases[n] = (inc - amount) frontloaded = max(frontloaded, 1) while max(increases) > 15: i = increases.index(max(increases)) increases[i] = increases[i] - 1 choices = [n for (n, v) in enumerate(increases) if v < 15] if random.randint(0, len(choices)) == 0: frontloaded += 1 elif choices: i = random.choice(choices) increases[i] = increases[i] + 1 curves[attr].append((frontloaded, increases)) for attr in LEVEL_STATS: attr_curves = curves[attr] random.shuffle(attr_curves) for character_index in xrange(5): (base, increases) = attr_curves.pop() c = CharacterObject.get(character_index) if c.index == 0 and attr in ["max_hp", "attack"]: # ensure basic starting stats for Mario while base < 20: base += 1 for i in range(len(increases)): if increases[i] > 0: increases[i] = increases[i] - 1 break getattr(c, attr) setattr(c, attr, base) assert len(increases) == 19 for s in StatGrowthObject.every: if s.character_id == c.index: if increases: s.set_stat(attr, increases.pop(0)) else: s.set_stat(attr, mutate_normal(2))
def mutate(self): if not self.is_equipment: return score = self.stat_point_value num_up = bin(random.randint(1, 31)).count('1') num_down = bin(random.randint(0, 31)).count('1') while True: if random.choice([True, False, False]): ups = [attr for attr in EQUIP_STATS if 1 <= getattr(self, attr) <= 127] if ups: break ups = random.sample(EQUIP_STATS, num_up) if set(ups) & set(self.primary_stats): break ups = dict([(u, 0) for u in ups]) if random.choice([True, False, False]): downs = [attr for attr in EQUIP_STATS if getattr(self, attr) >= 128] else: downs = random.sample(EQUIP_STATS, num_down) downs = dict([(d, 0) for d in downs if d not in ups]) if downs: if score != 0: downpoints = random.randint(0, random.randint(0, score)) else: downpoints = random.randint(0, random.randint(0, random.randint(0, 100))) while downpoints > 0: attr = random.choice(downs.keys()) downs[attr] += 1 downpoints -= 1 score += 1 while score > 0: attr = random.choice(ups.keys()) ups[attr] += 1 if attr in self.primary_stats: score -= 1 else: score -= 2 for attr in EQUIP_STATS: setattr(self, attr, 0) for attr in ups: setattr(self, attr, min(mutate_normal( ups[attr], minimum=1, maximum=127), 127)) for attr in downs: value = min(mutate_normal( downs[attr], minimum=1, maximum=127), 127) if value: setattr(self, attr, 256 - value) if self.is_weapon and self.get_bit("geno"): assert self.equippable == 8 return equippable = self.equippable & 0xE0 num_equippable = random.randint(1,random.randint(1, 5)) for _ in xrange(num_equippable): equippable |= (1 << random.randint(0, 4)) if self.is_weapon: equippable = equippable & 0xF7 assert not equippable & 8 if not equippable: return self.equippable = equippable
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 full_randomize(cls): # fix debug bombs before this if hasattr(cls, "after_order"): for cls2 in cls.after_order: if not (hasattr(cls2, "randomized") and cls2.randomized): raise Exception("Randomize order violated.") cls.randomized = True assignments = {} # phase 1: frog coin shops frog_candidates = [i for i in ItemObject.every if i.price and (i.rare or i.is_consumable or i.is_accessory) and not i.banned] frog_not_rare = [i for i in frog_candidates if not i.rare] unfrog = random.randint( random.randint(0, len(frog_not_rare)), len(frog_not_rare)) unfrog = random.sample(frog_not_rare, unfrog) for i in sorted(unfrog, key=lambda i2: i2.index): frog_candidates.remove(i) frog_chosen = random.sample(frog_candidates, 25) disciple_shop = 3 frog_coin_emporium = 6 one_only = [i for i in frog_chosen if (i.is_equipment and bin(i.equippable).count("1") == 1) or (i.is_consumable and i.reuseable)] num_choose = min(10, len(one_only)) num_choose = random.randint(random.randint(0, num_choose), num_choose) num_choose = min(num_choose, len(one_only)) chosen = random.sample(one_only, num_choose) choose_again = [i for i in frog_chosen if i not in chosen and ( i in one_only or i.is_equipment)] num_choose = 10 - len(chosen) num_choose = random.randint(random.randint(0, num_choose), num_choose) num_choose = min(num_choose, len(choose_again)) if num_choose and choose_again: chosen += random.sample(choose_again, num_choose) num_choose = 10 - len(chosen) if num_choose: choose_again = [i for i in frog_chosen if i not in chosen] random.shuffle(choose_again) chosen += choose_again[:num_choose] assert len(chosen) == 10 assignments[disciple_shop] = chosen assignments[frog_coin_emporium] = [ i for i in frog_chosen if i not in chosen] # phase 2: non-frog coin shops carryover = [i for i in frog_candidates if i not in assignments[disciple_shop] and i not in assignments[frog_coin_emporium]] random.shuffle(carryover) num_choose = random.randint(0, random.randint(0, len(carryover))) carryover = carryover[:num_choose] shop_items = carryover + [i for i in ItemObject.every if i not in assignments[disciple_shop] and i not in assignments[frog_coin_emporium] and not i.banned and not i.rare] shop_items = sorted(set(shop_items), key=lambda i: i.rank) juice_bar_partial = [9, 10, 11] # full: 12 special_conditions = { 0: lambda i: i.is_consumable or ( i.is_equipment and i.equippable & 0b10001), 1: lambda i: i.is_consumable, 2: lambda i: i.is_equipment and i.equippable & 0b11001, 4: lambda i: i.is_consumable or ( i.is_equipment and i.equippable & 0b11001), 8: lambda i: i.is_consumable and ( (i.misc_attack not in [1, 2, 4, 5] and not i.get_bit("status_nullification")) or i.get_bit("all")), 12: lambda i: special_conditions[8](i) and not i.reuseable, 13: lambda i: i.is_weapon, 14: lambda i: i.is_armor, 15: lambda i: i.is_accessory, 16: lambda i: i.is_consumable, 18: lambda i: i.is_consumable, 19: lambda i: i.is_equipment, 20: lambda i: special_conditions[8](i), 24: lambda i: i.is_consumable, } done_already = set([]) for p in range(25): if p in juice_bar_partial + [disciple_shop, frog_coin_emporium]: continue shop = ShopObject.get(p) if p == 12: num_items = 15 else: num_items = len([i for i in shop.items if i != 0xFF]) num_items = mutate_normal(num_items, minimum=1, maximum=15) valid_items = list(shop_items) if p in special_conditions: valid_items = [i for i in valid_items if special_conditions[p](i)] temp = [i for i in valid_items if i not in done_already or (i.is_consumable and not i.reuseable and not i.rare and not i.get_bit("all") and (i.misc_attack in [1, 2, 4] or i.get_bit("status_nullification")))] if temp and p not in [12, 13, 14, 20]: valid_items = temp extras = [i for i in valid_items if i not in temp] extras = random.sample(extras, random.randint(0, len(extras))) valid_items = sorted(set(valid_items + extras), key=lambda i: i.rank) assert valid_items num_items = min(num_items, len(valid_items)) if p != 20 and len(valid_items) > num_items: valid_items = valid_items[:random.randint( num_items, random.randint(num_items, len(valid_items)))] consumables = [i for i in valid_items if i.is_consumable] others = [i for i in valid_items if i not in consumables] if consumables and others and num_items >= 4: num_con = (random.randint(0, num_items) + random.randint(0, num_items)) / 2 num_con = max(num_con, num_items-num_con) num_con = min(num_con, num_items-2) num_oth = num_items-num_con num_con = min(num_con, len(consumables)) num_oth = min(num_oth, len(others)) valid_items = (random.sample(consumables, num_con) + random.sample(others, num_oth)) num_items = num_con + num_oth chosen_items = random.sample(valid_items, num_items) assignments[p] = chosen_items for i in chosen_items: done_already.add(i) # phase 2.5: juice bar for n, p in enumerate(sorted(juice_bar_partial, reverse=True)): n = len(juice_bar_partial) - n previous_items = assignments[p+1] minimum = n maximum = len(previous_items)-1 average = (minimum + maximum) / 2 num_items = random.randint( random.randint(minimum, average), maximum) chosen_items = random.sample(previous_items, num_items) assignments[p] = chosen_items # phase 3: repricing repriced = set([]) for p, items in assignments.items(): for item in items: if item in repriced: continue if p in [disciple_shop, frog_coin_emporium]: item.become_frog_coin_item() else: if not item.unbecome_frog_coin_item() and item.rare: PriceObject.get(item.index).price = max( item.price, int(item.rank)) price = min(999, max(2, item.price)) price = mutate_normal(price, minimum=2, maximum=999) PriceObject.get(item.index).price = price repriced.add(item) for p, items in assignments.items(): final = [0xFF] * 15 items = sorted(items, key=lambda i: ITEM_ORDER.index(i.index)) final[:len(items)] = [i.index for i in items] ShopObject.get(p).items = final ShopObject.get(20).set_bit("discount50", True)