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 mutate_spell_levels(cls, class_index): lus = [ lu for lu in LevelUpObject.every if lu.class_index == class_index ] indexes = [ i for (i, lu) in enumerate(lus) if lu.get_bit("spell_level") ] if not indexes: return new_indexes = [] for i in indexes: while True: n = mutate_normal(i, 1, 40, random_degree=cls.random_degree) if n not in new_indexes: new_indexes.append(n) break if len(new_indexes) > 1: remaining = 8 - len(new_indexes) highest = max(new_indexes) new_indexes.extend(random.sample(range(highest + 1, 50), remaining)) assert len(new_indexes) == 8 assert len(new_indexes) in [1, 8] for i, lu in enumerate(lus): if i in new_indexes: lu.set_bit("spell_level", True) else: lu.set_bit("spell_level", False)
def shuffle_bits(value, size=8): numbits = bin(value).count("1") if numbits: digits = random.sample(range(size), numbits) newvalue = 0 for d in digits: newvalue |= (1 << d) value = newvalue return value
def randomize_all(cls): f = open(get_outfile(), "r+b") f.seek(addresses.hammer3) num_items = ord(f.read(1)) indexes = map(ord, f.read(num_items)) f.close() sios = [ShopIndexObject.get(i) for i in indexes] hard_mode = "chaos" in get_activated_codes() total_new_items = [] for item_type in [2, 3, 4]: subsios = [sio for sio in sios if sio.item_type == item_type] new_items = [] candidates = [ i for i in ItemObject.every if i.item_type == item_type and i.price > 0 ] candidates = sorted(candidates, key=lambda c: (c.price, random.random())) max_index = len(candidates) - 1 while len(new_items) < len(subsios): if hard_mode: index = random.randint(0, random.randint(0, max_index)) else: index = random.randint(0, max_index) chosen = candidates[index] if ("fam" in get_activated_codes() and item_type == 2 and chosen.index in HP_HEALING_ITEMS): continue restricted_items = None if "gun" in get_activated_codes() and item_type == 3: restricted_items = [WeaponObject.get(i) for i in GUNS] if "fist" in get_activated_codes() and item_type == 3: restricted_items = [WeaponObject.get(i) for i in FISTS] if "ass" in get_activated_codes() and item_type == 3: restricted_items = [WeaponObject.get(i) for i in KNIVES] if restricted_items is not None: temp = [i for i in restricted_items if i not in new_items] if temp: restricted_items = temp chosen = random.choice(restricted_items) if chosen in new_items and restricted_items is None: continue new_items.append(chosen) new_items = sorted(new_items, key=lambda ni: ni.index) total_new_items.extend(new_items) sios = [ShopIndexObject.get(i) for i in xrange(len(total_new_items))] for sio, ni in zip(sios, total_new_items): sio.item_type = ni.item_type sio.item_index = ni.index f = open(get_outfile(), "r+b") previous = list(sios) for address in ["hammer3", "hammer2", "hammer1"]: f.seek(getattr(addresses, address)) num_items = ord(f.read(1)) f.seek(getattr(addresses, address) + 1) chosen_sios = random.sample(previous, num_items) chosen_sios = sorted(chosen_sios, key=lambda sio: sio.index) for sio in chosen_sios: f.write(chr(sio.index)) sio.shop_rank = int(address[-1]) sio.inserted_item = False previous = chosen_sios f.close()
def do_fiesta(): print "Please enter a number to choose an option:" print "1. Choose my own jobs." print "2. Randomize my jobs." while True: x = int(raw_input("? ")) if x in [1, 2]: break print if x == 1: print "JOB LIST" namestrs = [ "{0:>2}. {1}".format(jco.job_index + 1, jco.name) for jco in sorted(JobCrystalObject.every, key=lambda j: j.job_index) ] maxlen = max(map(len, namestrs)) + 2 num_per_row = 79 / maxlen num_rows = len(namestrs) / float(num_per_row) if num_rows != int(num_rows): num_rows += 1 num_rows = int(num_rows) ss = ["" for _ in xrange(int(num_rows))] while namestrs: namestr = namestrs.pop(0) s = ss.pop(0) s += ("{0:%s}" % maxlen).format(namestr) ss.append(s) for s in sorted(ss): print s print chosen_jobs = [] for element in ["Wind", "Water", "Fire", "Earth"]: while True: x = raw_input("%s job? " % element) try: x = int(x) - 1 assert x >= 0 x = [ jco for jco in JobCrystalObject.every if jco.job_index == x ][0] chosen_jobs.append(x) break except: pass print "Your chosen jobs are: " + ", ".join(jco.name for jco in chosen_jobs) print else: JobCrystalObject.class_reseed("fiesta1") fight_jobs = [ jco for jco in JobCrystalObject.every if jco.has_fight_command and jco.job_abilities ] wind_job = random.choice(fight_jobs) candidates = [ jco for jco in JobCrystalObject.every if jco.job_abilities and jco is not wind_job ] chosen_jobs = [wind_job] + random.sample(candidates, 3) assert len(set(chosen_jobs)) == 4 JobCrystalObject.class_reseed("fiesta2") crystal_indexes = [jco.crystal_index for jco in chosen_jobs] for jco in JobCrystalObject.every: if jco.rank <= 2: jco.crystal_index = crystal_indexes[0] elif jco.rank <= 3: jco.crystal_index = crystal_indexes[1] elif jco.rank <= 5: jco.crystal_index = crystal_indexes[2] else: jco.crystal_index = crystal_indexes[3] NONELEMENTAL_SKILLS = [ 0x8, 0xc, 0xd, 0xe, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x2a, 0x2b, 0x5f, 0x61, 0x62, 0x90 ] ability_indexes = [ a.ability for jco in chosen_jobs for a in jco.job_abilities ] if not set(ability_indexes) & set(NONELEMENTAL_SKILLS): print( "WARNING! These jobs will not learn a " "reliable source of non-elemental damage.") print("At least one of them has the Fight skill.") x = raw_input("Are you sure you want to continue? (y/n) ") if x and x.lower()[0] == 'n': remove(get_outfile()) exit(0)
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
class FormationObject(TableObject): flag = "f" flag_description = "enemy formations" def __repr__(self): present = bin(self.enemies_present)[2:] hidden = bin(self.enemies_hidden)[2:] present = "{0:0>8}".format(present) hidden = "{0:0>8}".format(hidden) s = "%x: " % self.index for i, (p, h) in enumerate(zip(present, hidden)): index, x, y = (getattr(self, "monster%s" % i), getattr(self, "monster%s_x" % i), getattr(self, "monster%s_y" % i)) m = MonsterObject.get(index) if h == "1" or p == "1": s += "%x %s" % (index, m.name.strip()) if m in self.leaders: s += "*" if h != "1" and p == "1": s += " (%s, %s); " % (x, y) if h == "1": assert p == "1" s += " (hidden, %s, %s); " % (x, y) s = s.strip().rstrip(";").strip() return s @property def vram_used(self): if self.enemies_hidden: return None return sum([e.vram_value for e in self.enemies]) @property def coordinates(self): coordinates = [] for i in xrange(8): if self.enemies_present & (1 << (7-i)): coordinates.append((getattr(self, "monster%s_x" % i), getattr(self, "monster%s_y" % i))) return coordinates @property def rank(self): enemies = sorted(self.enemies, key=lambda m: m.rank, reverse=True) rank = 0 for i, e in enumerate(enemies): rank += e.rank / (i+1) return rank @property def bosses(self): bosses = [e for e in self.enemies if e.is_boss] return bosses @property def enemies(self): enemies = bin(self.enemies_present | self.enemies_hidden)[2:] return self.get_enemy_list(enemies) def get_enemy_list(self, bitmask): bitmask = "{0:0>8}".format(bitmask) enemy_list = [] for (i, c) in enumerate(bitmask): if c == "1": m = MonsterObject.get(getattr(self, "monster%s" % i)) enemy_list.append(m) return enemy_list @property def leaders(self): if not hasattr(self, "_leaders"): for f in FormationObject.every: f._leaders = set([]) for p in PackObject.every: common_enemies = set(p.common_enemies) for f in p.formations: f._leaders |= common_enemies for f in FormationObject.every: if not f._leaders: f._leaders = list(f.enemies) f._leaders = sorted(f._leaders, key=lambda m: m.index) return self._leaders @classproperty def valid_coordinates(cls): if hasattr(cls, "_valid_coordinates"): return cls._valid_coordinates cls._valid_coordinates = set([]) for f in FormationObject.every: if not f.bosses: bitmask = f.enemies_present & (0xFF ^ f.enemies_hidden) for i in xrange(8): if bitmask & (1 << (7-i)): (x, y) = (getattr(f, "monster%s_x" % i), getattr(f, "monster%s_y" % i)) else: continue if (x, y) == (0, 0): break cls._valid_coordinates.add((x, y)) cls._valid_coordinates = sorted(cls._valid_coordinates) xs, ys = zip(*cls._valid_coordinates) cls.lower_x, cls.upper_x = min(xs), max(xs) cls.lower_y, cls.upper_y = min(ys), max(ys) return cls.valid_coordinates @property def meta(self): return FormMetaObject.get(self.index) @property def has_event(self): if self.meta.event == 0xFF: return False else: return True @property def music(self): if self.meta.misc & 0xc0 == 0xc0: return None return (self.meta.misc >> 2) & 0x7 @property def inescapable(self): return self.meta.misc & 3 def set_music(self, value): if value is None: self.meta.misc &= 0xE3 self.meta.misc |= 0xC0 else: self.meta.misc &= 0xE3 self.meta.misc |= (value << 2) 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 get_collective_distance(p, points): distances = [get_distance(p, p2) for p2 in points] return reduce(lambda a, b: a*b, distances, 1) def select_most_distance(candidates, done_coordinates): score = lambda p: get_collective_distance(p, done_coordinates) chosen = max(candidates, key=lambda c: score(c)) return chosen self.enemies_present = 0 done_coordinates = [] for i in range(8): if i < len(chosen_enemies): e = chosen_enemies[i].index if not done_coordinates: (x, y) = random.choice(self.valid_coordinates) (x, y) = mutate_coordinate((x, y)) else: candidates = random.sample(self.valid_coordinates, len(chosen_enemies)*2) candidates = map(mutate_coordinate, candidates) (x, y) = select_most_distance(candidates, done_coordinates) done_coordinates.append((x, y)) self.enemies_present |= (1 << (7-i)) else: e = 0 setattr(self, "monster%s" % i, e) setattr(self, "monster%s_x" % i, 0) setattr(self, "monster%s_y" % i, 0) done_coordinates = sorted(done_coordinates) for i, (x, y) in enumerate(done_coordinates): setattr(self, "monster%s_x" % i, x) setattr(self, "monster%s_y" % i, 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)