Skip to content

Commit

Permalink
MM2: minor bugfixes (#4190)
Browse files Browse the repository at this point in the history
* move special cases to be outside strict

* Update text.py

* fix wily machine edge case, incorrect weapons, and time stopper failsafe

* bump world version

* weakness checking is inclusive

* Update __init__.py

* add air shooter to edge case validation
  • Loading branch information
Silvris authored Nov 18, 2024
1 parent baf291d commit bd5c8ec
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 29 deletions.
6 changes: 3 additions & 3 deletions worlds/mm2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ class MM2World(World):
location_name_groups = location_groups
web = MM2WebWorld()
rom_name: bytearray
world_version: Tuple[int, int, int] = (0, 3, 1)
world_version: Tuple[int, int, int] = (0, 3, 2)
wily_5_weapons: Dict[int, List[int]]

def __init__(self, world: MultiWorld, player: int):
def __init__(self, multiworld: MultiWorld, player: int):
self.rom_name = bytearray()
self.rom_name_available_event = threading.Event()
super().__init__(world, player)
super().__init__(multiworld, player)
self.weapon_damage = deepcopy(weapon_damage)
self.wily_5_weapons = {}

Expand Down
53 changes: 28 additions & 25 deletions worlds/mm2/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,28 +133,6 @@ def set_rules(world: "MM2World") -> None:
# Wily Machine needs all three weaknesses present, so allow
elif 4 > world.weapon_damage[weapon][i] > 0:
world.weapon_damage[weapon][i] = 0
# handle special cases
for boss in range(14):
for weapon in (1, 3, 6, 8):
if (0 < world.weapon_damage[weapon][boss] < minimum_weakness_requirement[weapon] and
not any(world.weapon_damage[i][boss] > 0 for i in range(1, 8) if i != weapon)):
# Weapon does not have enough possible ammo to kill the boss, raise the damage
if boss == 9:
if weapon != 3:
# Atomic Fire and Crash Bomber cannot be Picopico-kun's only weakness
world.weapon_damage[weapon][boss] = 0
weakness = world.random.choice((2, 3, 4, 5, 7, 8))
world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness]
elif boss == 11:
if weapon == 1:
# Atomic Fire cannot be Boobeam Trap's only weakness
world.weapon_damage[weapon][boss] = 0
weakness = world.random.choice((2, 3, 4, 5, 6, 7, 8))
world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness]
else:
world.weapon_damage[weapon][boss] = minimum_weakness_requirement[weapon]
starting = world.options.starting_robot_master.value
world.weapon_damage[0][starting] = 1

for p_boss in world.options.plando_weakness:
for p_weapon in world.options.plando_weakness[p_boss]:
Expand All @@ -168,6 +146,28 @@ def set_rules(world: "MM2World") -> None:
world.weapon_damage[weapons_to_id[p_weapon]][bosses[p_boss]] \
= world.options.plando_weakness[p_boss][p_weapon]

# handle special cases
for boss in range(14):
for weapon in (1, 2, 3, 6, 8):
if (0 < world.weapon_damage[weapon][boss] < minimum_weakness_requirement[weapon] and
not any(world.weapon_damage[i][boss] >= minimum_weakness_requirement[weapon]
for i in range(9) if i != weapon)):
# Weapon does not have enough possible ammo to kill the boss, raise the damage
if boss == 9:
if weapon in (1, 6):
# Atomic Fire and Crash Bomber cannot be Picopico-kun's only weakness
world.weapon_damage[weapon][boss] = 0
weakness = world.random.choice((2, 3, 4, 5, 7, 8))
world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness]
elif boss == 11:
if weapon == 1:
# Atomic Fire cannot be Boobeam Trap's only weakness
world.weapon_damage[weapon][boss] = 0
weakness = world.random.choice((2, 3, 4, 5, 6, 7, 8))
world.weapon_damage[weakness][boss] = minimum_weakness_requirement[weakness]
else:
world.weapon_damage[weapon][boss] = minimum_weakness_requirement[weapon]

if world.weapon_damage[0][world.options.starting_robot_master.value] < 1:
world.weapon_damage[0][world.options.starting_robot_master.value] = weapon_damage[0][world.options.starting_robot_master.value]

Expand Down Expand Up @@ -209,30 +209,33 @@ def set_rules(world: "MM2World") -> None:
continue
highest, wp = max(zip(weapon_weight.values(), weapon_weight.keys()))
uses = weapon_energy[wp] // weapon_costs[wp]
used_weapons[boss].add(wp)
if int(uses * boss_damage[wp]) > boss_health[boss]:
used = ceil(boss_health[boss] / boss_damage[wp])
weapon_energy[wp] -= weapon_costs[wp] * used
boss_health[boss] = 0
used_weapons[boss].add(wp)
elif highest <= 0:
# we are out of weapons that can actually damage the boss
# so find the weapon that has the most uses, and apply that as an additional weakness
# it should be impossible to be out of energy, simply because even if every boss took 1 from
# Quick Boomerang and no other, it would only be 28 off from defeating all 9, which Metal Blade should
# be able to cover
wp, max_uses = max((weapon, weapon_energy[weapon] // weapon_costs[weapon]) for weapon in weapon_weight
if weapon != 0)
if weapon != 0 and (weapon != 8 or boss != 12))
# Wily Machine cannot under any circumstances take damage from Time Stopper, prevent this
world.weapon_damage[wp][boss] = minimum_weakness_requirement[wp]
used = min(int(weapon_energy[wp] // weapon_costs[wp]),
ceil(boss_health[boss] // minimum_weakness_requirement[wp]))
ceil(boss_health[boss] / minimum_weakness_requirement[wp]))
weapon_energy[wp] -= weapon_costs[wp] * used
boss_health[boss] -= int(used * minimum_weakness_requirement[wp])
weapon_weight.pop(wp)
used_weapons[boss].add(wp)
else:
# drain the weapon and continue
boss_health[boss] -= int(uses * boss_damage[wp])
weapon_energy[wp] -= weapon_costs[wp] * uses
weapon_weight.pop(wp)
used_weapons[boss].add(wp)

world.wily_5_weapons = {boss: sorted(used_weapons[boss]) for boss in used_weapons}

Expand Down
2 changes: 1 addition & 1 deletion worlds/mm2/text.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import DefaultDict
from collections import defaultdict

MM2_WEAPON_ENCODING: DefaultDict[str, int] = defaultdict(lambda x: 0x6F, {
MM2_WEAPON_ENCODING: DefaultDict[str, int] = defaultdict(lambda: 0x6F, {
' ': 0x40,
'A': 0x41,
'B': 0x42,
Expand Down

0 comments on commit bd5c8ec

Please sign in to comment.