Add 'Oops All <Boss> Mode#142
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the "Oops, all !" feature, which allows users to replace all bosses in the game with a single specified boss via a new -oops command-line argument. The changes include argument parsing and validation in args/bosses.py and the implementation of the replacement logic in data/enemy_formations.py, which also handles boss positioning and VRAM mold application. Reviewers suggested several improvements to simplify the code, such as using aggregated dictionaries for boss lookups, utilizing set operations for ID filtering, and employing the any() function for more idiomatic formation checks.
|
How does this mode work with the Bosses number objective condition? Previously, it was a unique boss counter to satisfy that objective condition...if let's say someone makes Unlock Kefka Bosses = 3, then do they softlock themselves into never beating the seed? |
This basically retains the original formation, just swapping in the actual "oops" boss into it. The number of bosses is counted up by the formation ID, so even though every single boss might be "Leader", the formations will be "Magi Master" or "Cranes", and would trigger any boss checks or requirements like that. So even if you have an objective to "Defeat Stooges", and your "Oops" boss is "Ultros 1", one of those "Ultros 1" bosses will be in the "Stooges" formation. |
- Improved validation of boss IDs to ensure only valid IDs are accepted. - Simplified the process of finding a boss's native mold by directly checking formations. - Added more descriptive error messages for invalid boss IDs.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces an "Oops, all !" feature, allowing players to replace all bosses with a specific boss enemy ID, name, or a random boss. This includes adding a new -oops command-line argument, parsing and validating the input, and modifying enemy formations to replace existing bosses with the target boss while adjusting positioning and applying the native mold. The review feedback suggests two main improvements: simplifying the argument parsing logic in args/bosses.py by using str.isdigit() instead of a try-except block for control flow, and refactoring the nested loop in data/enemy_formations.py to use Python's built-in any() function along with the formation.enemies() helper for cleaner and more Pythonic code.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| try: | ||
| # Try to parse as integer ID first | ||
| oops_id = int(args.oops) | ||
| if oops_id not in valid_boss_ids: | ||
| raise ValueError(f"Invalid boss ID: {oops_id}. Must be a valid boss enemy ID.") | ||
| args.oops = oops_id | ||
| except ValueError as e: | ||
| if "Invalid boss ID" in str(e): | ||
| raise e | ||
|
|
||
| # If not a valid integer ID, try to parse as normalized name | ||
| def normalize(name): | ||
| return "".join(c.lower() for c in name if c.isalnum()) | ||
|
|
||
| name_to_id = {} | ||
| for enemy_dict in [bosses.normal_enemy_name, bosses.dragon_enemy_name, bosses.statue_enemy_name, bosses.final_battle_enemy_name]: | ||
| for eid, name in enemy_dict.items(): | ||
| if eid not in excluded_final_battle_ids: | ||
| name_to_id[normalize(name)] = eid | ||
|
|
||
| normalized_input = normalize(args.oops) | ||
| if normalized_input in name_to_id: | ||
| args.oops = name_to_id[normalized_input] | ||
| elif normalized_input == "random": | ||
| args.oops = "random" | ||
| else: | ||
| raise ValueError( | ||
| f"Invalid boss ID or name: '{args.oops}'. " | ||
| f"Please check the enemy maps in data/bosses.py for correct names and IDs." | ||
| ) |
There was a problem hiding this comment.
Instead of using a try-except block to handle control flow and checking the exception string to decide whether to re-raise, you can check if the input is numeric using str.isdigit(). This makes the logic cleaner, more readable, and avoids relying on exception message parsing.
if args.oops.isdigit():
oops_id = int(args.oops)
if oops_id not in valid_boss_ids:
raise ValueError(f"Invalid boss ID: {oops_id}. Must be a valid boss enemy ID.")
args.oops = oops_id
else:
def normalize(name):
return "".join(c.lower() for c in name if c.isalnum())
name_to_id = {}
for enemy_dict in [bosses.normal_enemy_name, bosses.dragon_enemy_name, bosses.statue_enemy_name, bosses.final_battle_enemy_name]:
for eid, name in enemy_dict.items():
if eid not in excluded_final_battle_ids:
name_to_id[normalize(name)] = eid
normalized_input = normalize(args.oops)
if normalized_input in name_to_id:
args.oops = name_to_id[normalized_input]
elif normalized_input == "random":
args.oops = "random"
else:
raise ValueError(
f"Invalid boss ID or name: '{args.oops}'. "
f"Please check the enemy maps in data/bosses.py for correct names and IDs."
)| has_boss = False | ||
| for enemy_index in range(formation.ENEMY_CAPACITY): | ||
| if formation.enemy_slots & (1 << enemy_index): | ||
| if formation.enemy_ids[enemy_index] in boss_enemy_ids: | ||
| has_boss = True | ||
| break | ||
|
|
||
| if has_boss: |
There was a problem hiding this comment.
This nested loop can be simplified and made more Pythonic by using the built-in any() function along with the existing formation.enemies() helper method, which already filters and returns the active enemy IDs for the formation.
| has_boss = False | |
| for enemy_index in range(formation.ENEMY_CAPACITY): | |
| if formation.enemy_slots & (1 << enemy_index): | |
| if formation.enemy_ids[enemy_index] in boss_enemy_ids: | |
| has_boss = True | |
| break | |
| if has_boss: | |
| if any(enemy_id in boss_enemy_ids for enemy_id in formation.enemies()): |
Feature: "Oops, All X!" Randomizer Flag (-oops <id/name>)
Adds the -oops flag, which replaces all boss, dragon, and statue encounters with a single chosen boss.
Implementation Details
Input Handling:
Progression & Objectives:
Graphics & VRAM:
Notes: