Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions args/encounters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,29 @@ def parse(parser):
help = "Random encounters are randomized")
random.add_argument("-rechu", "--random-encounters-chupon", action = "store_true",
help = "All Random Encounters are replaced with Chupon (Coliseum)")
random.add_argument("-rews", "--random-encounters-world-shuffle", action = "store_true",
help = "Random encounters are shuffled by world")
random.add_argument("-rewr", "--random-encounters-world-random",
default = None, type = int, metavar = "PERCENT", choices = range(101),
help = "Random encounters are randomized with encounters from the same world")

fixed = encounters.add_mutually_exclusive_group()
fixed.add_argument("-fer", "--fixed-encounters-random",
default = None, type = int, metavar = "PERCENT", choices = range(101),
help = "Fixed encounters are randomized. Lete River, Serpent Trench, Mine Cart, Imperial Camp, ...")
fixed.add_argument("-fewr", "--fixed-encounters-world-random",
default = None, type = int, metavar = "PERCENT", choices = range(101),
help = "Fixed encounters are randomized with encounters from the same world. Lete River, Serpent Trench, Mine Cart, Imperial Camp, ...")

escapable = encounters.add_mutually_exclusive_group()
escapable.add_argument("-escr", "--encounters-escapable-random",
default = None, type = int, metavar = "PERCENT", choices = range(101),
help = "Percent of random encounters escapable including with warp or smoke bombs")

def process(args):
args.random_encounters_original = not args.random_encounters_shuffle and args.random_encounters_random is None
args.fixed_encounters_original = args.fixed_encounters_random is None
args.random_encounters_original = not args.random_encounters_shuffle and args.random_encounters_random is None \
and not args.random_encounters_world_shuffle and args.random_encounters_world_random is None
args.fixed_encounters_original = args.fixed_encounters_random is None and args.fixed_encounters_world_random is None
args.encounters_escapable_original = args.encounters_escapable_random is None

def flags(args):
Expand All @@ -37,9 +46,16 @@ def flags(args):
flags += f" -rer {args.random_encounters_random}"
elif args.random_encounters_chupon:
flags += " -rechu"
elif args.random_encounters_world_shuffle:
flags += " -rews"
elif args.fixed_encounters_world_random is not None:
flags += f" -rewr {args.fixed_encounters_world_random}"

if args.fixed_encounters_random is not None:
flags += f" -fer {args.fixed_encounters_random}"
elif args.fixed_encounters_world_random is not None:
flags += f" -fewr {args.fixed_encounters_world_random}"


if args.encounters_escapable_random is not None:
flags += f" -escr {args.encounters_escapable_random}"
Expand All @@ -56,14 +72,22 @@ def options(args):
random_encounters = "Random"
elif args.random_encounters_chupon:
random_encounters = "Chupon"
elif args.random_encounters_world_shuffle:
random_encounters = "WShuffle"
elif args.fixed_encounters_world_random is not None:
random_encounters = "WRandom"

result.append(("Random Encounters", random_encounters, "random_encounters"))
if args.random_encounters_random is not None:
result.append(("Boss Percent", f"{args.random_encounters_random}%", "random_encounters_random"))
elif args.fixed_encounters_world_random is not None:
result.append(("Boss Percent", f"{args.fixed_encounters_world_random}%", "fixed_encounters_world_random"))

fixed_encounters = "Original"
if args.fixed_encounters_random is not None:
fixed_encounters = "Random"
elif args.fixed_encounters_world_random is not None:
fixed_encounters = "WRandom"

result.append(("Fixed Encounters", fixed_encounters, "fixed_encounters"))
if args.fixed_encounters_random is not None:
Expand Down
47 changes: 47 additions & 0 deletions data/bosses.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,53 @@
487 : "Tritoch",
505 : "Kefka (Narshe)",
}

wob_formation_name = {
4 : "Marshal",
79 : "Rizopas",
387 : "Ultros 3",
409 : "Leader",
432 : "Whelk",
435 : "Vargas",
436 : "TunnelArmr",
437 : "GhostTrain",
438 : "Dadaluma",
439 : "Ifrit/Shiva",
440 : "Cranes",
441 : "Number 024",
442 : "Number 128",
449 : "FlameEater",
450 : "AtmaWeapon",
451 : "Nerapa",
459 : "Air Force",
473 : "Ultros 1",
474 : "Ultros 2",
477 : "Ultros/Chupon",
505 : "Kefka (Narshe)",
}

wor_formation_name = {
354 : "MagiMaster",
422 : "Phunbaba 3",
423 : "Phunbaba 4",
444 : "Umaro",
446 : "Guardian",
452 : "SrBehemoth",
454 : "Tentacles",
455 : "Dullahan",
456 : "Chadarnook",
460 : "Stooges",
462 : "Wrexsoul",
463 : "Doom Gaze",
464 : "Hidon",
468 : "Doom",
469 : "Goddess",
470 : "Poltrgeist",
482 : "Atma",
484 : "Inferno",
487 : "Tritoch",
}

normal_enemy_name = {
100 : "Marshal",
340 : "Piranha",
Expand Down
91 changes: 91 additions & 0 deletions data/enemies.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,71 @@ def shuffle_encounters(self, maps):

# NOTE: any remaining formations (due to extra_formations) are lost

def world_shuffle_encounters(self, maps):
import collections
# find all packs that are randomly encountered in zones
packs = collections.OrderedDict()
for zone in self.zones.zones:
if self.skip_shuffling_zone(maps, zone):
continue

for x in range(zone.PACK_COUNT):
if self.skip_shuffling_pack(zone.packs[x], zone.encounter_rates[x]):
continue

packs[self.packs.packs[zone.packs[x]]] = None

# find all formations that are randomly encountered in packs
wob_formations = []
wor_formations = []
wob_packs = []
wor_packs = []
for pack in packs:
#check if this pack has wob or wor formations and stash the formations and pack in the apporiate lists
is_wob = self.formations.is_wob(pack.formations[0])
if is_wob:
wob_packs.append(pack)
else:
wor_packs.append(pack)
for y in range(pack.FORMATION_COUNT):
if self.skip_shuffling_formation(pack.formations[y]):
continue

if pack.extra_formations[y]:
# pack has extra formations (i.e. each formation is randomized with the subsequent 3 formations)
# unfortunately, this means there are more formations than packs to put them in, so some formations are lost
for x in range(4):
if is_wob:
wob_formations.append(pack.formations[y] + x)
else:
wor_formations.append(pack.formations[y] + x)
else:
if is_wob:
wob_formations.append(pack.formations[y])
else:
wor_formations.append(pack.formations[y])

# shuffle the randomly encounterable formations
import random
random.shuffle(wob_formations)
random.shuffle(wor_formations)

for pack in wob_packs:
for y in range(pack.FORMATION_COUNT):
if self.skip_shuffling_formation(pack.formations[y]):
continue

pack.formations[y] = wob_formations.pop()

for pack in wor_packs:
for y in range(pack.FORMATION_COUNT):
if self.skip_shuffling_formation(pack.formations[y]):
continue

pack.formations[y] = wor_formations.pop()

# NOTE: any remaining formations (due to extra_formations) are lost

def chupon_encounters(self, maps):
# find all packs that are randomly encountered in zones
packs = []
Expand Down Expand Up @@ -306,6 +371,28 @@ def randomize_encounters(self, maps):

self.packs.randomize_packs(packs, boss_percent)

def randomize_encounters_by_world(self, maps):
# find all packs that are randomly encountered in zones
wob_packs = []
wor_packs = []
boss_percent = self.args.random_encounters_world_random / 100.0
for zone in self.zones.zones:
if self.skip_shuffling_zone(maps, zone):
continue

for x in range(zone.PACK_COUNT):
if self.skip_shuffling_pack(zone.packs[x], zone.encounter_rates[x]):
continue
pack = zone.packs[x]
is_wob = self.formations.is_wob(self.packs.packs[pack].formations[0])
if is_wob:
wob_packs.append(pack)
else:
wor_packs.append(pack)

self.packs.randomize_wob_packs(wob_packs, boss_percent)
self.packs.randomize_wor_packs(wor_packs, boss_percent)

def randomize_loot(self):
for enemy in self.enemies:
self.set_common_steal(enemy.id, self.items.get_random())
Expand Down Expand Up @@ -390,6 +477,10 @@ def mod(self, maps):
self.shuffle_encounters(maps)
elif self.args.random_encounters_chupon:
self.chupon_encounters(maps)
elif self.args.random_encounters_world_shuffle:
self.world_shuffle_encounters(maps)
elif self.args.random_encounters_world_random is not None:
self.randomize_encounters_by_world(maps)
elif not self.args.random_encounters_original:
self.randomize_encounters(maps)

Expand Down
44 changes: 44 additions & 0 deletions data/enemy_formations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class EnemyFormations():
ENEMIES_END = 0xf83bf
ENEMIES_SIZE = 15

WOR_ENEMIES_START_INDEX = 192

PHUNBABA3 = bosses.name_formation["Phunbaba 3"]
DOOM_GAZE = bosses.name_formation["Doom Gaze"]
ALL_STATUES = list(bosses.statue_formation_name)
Expand All @@ -29,22 +31,37 @@ def __init__(self, rom, args, enemies):

self.dragons = list(bosses.dragon_formation_name)
self.bosses = list(bosses.normal_formation_name)
self.wob_bosses = list(bosses.wob_formation_name)
self.wor_bosses = list(bosses.wor_formation_name)

# formations not to include in "normal" (i.e. non-boss/dragon) pool
self.non_normal = [*self.dragons, *self.bosses, 4, 40, 42, 43, 59, 60, 63, 252, 335,
*range(384, 387), *range(388, 394), 420, 421, 424, *range(434, 465),
*range(467, 472), *range(473, 476), 477, 481, 482, 484, 485, *range(487, 576)]
non_normal_set = set(self.non_normal)

# the method for forming this list and the next was flawed/how it would be used wasn't understood.
# revisit and redefine these in a simpilier way.
self.wob = [*range(0, 103), *range(104, 114), *range(115, 126), 135, 136,
*range(139, 171), *range(174, 192), 210, *range(356, 362),
*range(373, 384), *range(402, 409), *range(410,412), *range(416,420), 434, 479]
self.wob_set = set(self.wob)

self.normal = []
self.formations = []
self.formation_names = []
self.wob_normal = []
self.wor_normal = []
for formation_index in range(len(self.flags_data)):
formation = EnemyFormation(formation_index, self.flags_data[formation_index], self.enemies_data[formation_index])
self.formations.append(formation)

if formation_index not in non_normal_set:
self.normal.append(formation_index)
if formation_index in self.wob_set:
self.wob_normal.append(formation_index)
else:
self.wor_normal.append(formation_index)

# name the formation based on enemies and their counts
enemy_count = {}
Expand Down Expand Up @@ -88,10 +105,21 @@ def has_enemy(self, formation_id, enemy_id):
return True
return False

def is_wob(self, formation_id):
return formation_id in self.wob_set

def get_random_normal(self):
import random
return random.choice(self.normal)

def get_random_wob_normal(self):
import random
return random.choice(self.wob_normal)

def get_random_wor_normal(self):
import random
return random.choice(self.wor_normal)

def get_random_boss(self, exclude = None):
import random
if exclude is None:
Expand All @@ -100,6 +128,22 @@ def get_random_boss(self, exclude = None):
possible_bosses = [boss_id for boss_id in self.bosses if boss_id not in exclude]
return random.choice(possible_bosses)

def get_random_wob_boss(self, exclude = None):
import random
if exclude is None:
return random.choice(self.wob_bosses)

possible_bosses = [boss_id for boss_id in self.wob_bosses if boss_id not in exclude]
return random.choice(possible_bosses)

def get_random_wor_boss(self, exclude = None):
import random
if exclude is None:
return random.choice(self.wor_bosses)

possible_bosses = [boss_id for boss_id in self.wor_bosses if boss_id not in exclude]
return random.choice(possible_bosses)

def get_random_dragon(self):
import random
return random.choice(self.dragons)
Expand Down
Loading