Skip to content
Open
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
8 changes: 7 additions & 1 deletion args/bosses.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def parse(parser):
help = "Boss battles shuffled")
bosses_battles.add_argument("-bbr", "--boss-battles-random", action = "store_true",
help = "Boss battles randomized")
bosses_battles.add_argument("-bbws", "--boss-battles-world-shuffle", action = "store_true",
help = "Boss battles shuffled by world")

dragons = bosses.add_mutually_exclusive_group()
dragons.add_argument("-drloc", "--dragon-boss-location", default = DEFAULT_DRAGON_PROTOCOL, type = str.lower, choices = BossLocations.ALL,
Expand Down Expand Up @@ -41,7 +43,7 @@ def process(args):
args.dragon_boss_location = BossLocations.MIX
args.mix_bosses_dragons = None
# if neither shuffling or randomizing bosses, and we try to mix the dragons/statues, simply shuffle them instead
vanilla_locations = not (args.boss_battles_shuffle or args.boss_battles_random)
vanilla_locations = not (args.boss_battles_shuffle or args.boss_battles_random or args.boss_battles_world_shuffle)
if vanilla_locations and args.dragon_boss_location == BossLocations.MIX:
args.dragon_boss_location = BossLocations.SHUFFLE
if vanilla_locations and args.statue_boss_location == BossLocations.MIX:
Expand All @@ -54,6 +56,8 @@ def flags(args):
flags += " -bbs"
elif args.boss_battles_random:
flags += " -bbr"
elif args.boss_battles_world_shuffle:
flags += " -bbws"

if args.dragon_boss_location:
flags += f" -drloc {args.dragon_boss_location}"
Expand Down Expand Up @@ -82,6 +86,8 @@ def options(args):
boss_battles = "Shuffle"
elif args.boss_battles_random:
boss_battles = "Random"
elif args.boss_battles_world_shuffle:
boss_battles = "WShuffle"

dragon_battles = DEFAULT_DRAGON_PROTOCOL
if args.dragon_boss_location:
Expand Down
46 changes: 46 additions & 0 deletions data/bosses.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,52 @@
401 : "MagiMaster",
}

wor_pack_name = {
338 : "SrBehemoth",
340 : "Tentacles",
341 : "Dullahan",
342 : "Chadarnook",
346 : "Stooges",
348 : "Wrexsoul",
349 : "Doom Gaze",
350 : "Hidon",
354 : "Doom",
355 : "Goddess",
356 : "Poltrgeist",
368 : "Atma",
370 : "Inferno",
373 : "Umaro",
375 : "Tritoch",
386 : "Phunbaba 3",
387 : "Phunbaba 4",
396 : "Guardian", # defeatable guardian in kefka's tower
401 : "MagiMaster",
}

wob_pack_name = {
262 : "Marshal",
274 : "Rizopas",
302 : "Leader",
313 : "Kefka (Narshe)",
320 : "Whelk",
322 : "Vargas",
323 : "TunnelArmr",
324 : "GhostTrain",
325 : "Dadaluma",
326 : "Ifrit/Shiva",
327 : "Cranes",
328 : "Number 024",
329 : "Number 128",
335 : "FlameEater",
336 : "AtmaWeapon",
337 : "Nerapa",
345 : "Air Force",
359 : "Ultros 1",
360 : "Ultros 2",
363 : "Ultros/Chupon",
381 : "Ultros 3",
}

# These ids are repeated in normal_pack_name as well
# This is intentional as they are used to iterate over ALL bosses for things like objective conditions
statue_pack_name = {
Expand Down
2 changes: 1 addition & 1 deletion data/enemy_formations.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def mod(self):
self.formations[387].event_script = 0
self.formations[387].enable_event_script = 0

if self.args.boss_battles_shuffle or self.args.boss_battles_random:
if self.args.boss_battles_shuffle or self.args.boss_battles_random or self.args.boss_battles_world_shuffle:
# second srbehemoth only appears as a front attack with shuffled/random boss battles
self.formations[424].disable_front_attack = 0
self.formations[424].disable_back_attack = 1
Expand Down
51 changes: 51 additions & 0 deletions data/enemy_packs.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,34 @@ def _replaceable_bosses(self):

return replaceable + self._replaceable_dragons() + self._replaceable_statues()

# Returns the list of all world of ruin boss packs that can be used during randomization
def _replaceable_wor_bosses(self):
dragon_packs = list(bosses.dragon_pack_name)
statue_packs = list(bosses.statue_pack_name)
boss_packs = list(bosses.wor_pack_name)
replaceable = [boss for boss in boss_packs if boss not in statue_packs and boss not in dragon_packs]

if not self.args.shuffle_random_phunbaba3:
self.event_boss_replacements[self.PHUNBABA3] = self.PHUNBABA3
if self.PHUNBABA3 in replaceable:
replaceable.remove(self.PHUNBABA3)

if not self.args.doom_gaze_no_escape:
# if doom gaze can escape, don't shuffle/randomize him
# possibly having multiple doom gazes while trying to keep track of hp is awkward
# how would that work with him being in his original spot and the others? How to know when to get bahamut esper?
self.event_boss_replacements[self.DOOM_GAZE] = self.DOOM_GAZE

if self.DOOM_GAZE in replaceable:
replaceable.remove(self.DOOM_GAZE)

return replaceable + self._replaceable_dragons() + self._replaceable_statues()

# Returns the list of all world of balance boss packs that can be used during randomization
def _replaceable_wob_bosses(self):
replaceable = list(bosses.wob_pack_name)
return replaceable

# Statue locations that become available for the general boss pool
def _replaceable_statues(self):
import random
Expand Down Expand Up @@ -145,6 +173,26 @@ def shuffle_event_bosses(self):

self.phunbaba3_safety_check(bosses_to_replace)

def world_shuffle_event_bosses(self):
import random

wob_bosses_to_replace = self._replaceable_wob_bosses()
wob_bosses_possible = wob_bosses_to_replace.copy()

random.shuffle(wob_bosses_possible)
for index, boss in enumerate(wob_bosses_to_replace):
self.event_boss_replacements[boss] = wob_bosses_possible[index]

wor_bosses_to_replace = self._replaceable_wor_bosses()
wor_bosses_possible = wor_bosses_to_replace.copy()

random.shuffle(wor_bosses_possible)
for index, boss in enumerate(wor_bosses_to_replace):
self.event_boss_replacements[boss] = wor_bosses_possible[index]

# I don't think this is needed because phunbaba 3 should be in wor but just in case
self.phunbaba3_safety_check(wob_bosses_to_replace)
Comment on lines +193 to +194

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The safety check for Phunbaba 3 is redundant and unreachable under world shuffle. Number 128 is a World of Balance boss, whereas Phunbaba 3 is a World of Ruin boss. Since the two pools are kept strictly separate during world shuffle, Phunbaba 3 can never be assigned to the Number 128 location. We can safely remove this redundant call and comment to keep the codebase clean and maintainable.


def randomize_event_bosses(self):
import args, random, objectives
from constants.objectives.conditions import names as possible_condition_names
Expand Down Expand Up @@ -377,6 +425,9 @@ def mod(self):
self.shuffle_event_bosses()
elif self.args.boss_battles_random:
self.randomize_event_bosses()
elif self.args.boss_battles_world_shuffle:
self.world_shuffle_event_bosses()


self._handle_original_shuffle_dragons()
self._handle_original_shuffle_statues()
Expand Down
4 changes: 2 additions & 2 deletions data/enemy_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,13 @@ def mod(self):
if self.args.doom_gaze_no_escape:
self.doom_gaze_no_escape_mod()

if self.args.boss_battles_shuffle or self.args.boss_battles_random:
if self.args.boss_battles_shuffle or self.args.boss_battles_random or self.args.boss_battles_world_shuffle:
self.doom_gaze_event_bit_mod()

if self.args.wrexsoul_no_zinger:
self.wrexsoul_no_zinger_mod()

if self.args.boss_battles_shuffle or self.args.boss_battles_random:
if self.args.boss_battles_shuffle or self.args.boss_battles_random or self.args.boss_battles_world_shuffle:
# the animation chadarnook uses to switch between demon and painting
# breaks with other battle backgrounds, they turn weird colors and look very glitchy
self.chadarnook_flashing_mod()
Expand Down
2 changes: 1 addition & 1 deletion event/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def init_event_bits(self, space):
def get_boss(self, original_boss_name, log_change = True):
pack_id = self.enemies.get_event_boss(original_boss_name)

if (self.args.boss_battles_shuffle or self.args.boss_battles_random) and log_change:
if (self.args.boss_battles_shuffle or self.args.boss_battles_random or self.args.boss_battles_world_shuffle) and log_change:
boss_name = self.enemies.packs.get_name(pack_id)
self.log_change(original_boss_name, boss_name)
return pack_id
Expand Down