fix animal duplication bug

This commit is contained in:
Silvris
2024-05-18 02:54:56 -05:00
parent aa46e34119
commit 139f222b92
6 changed files with 88 additions and 2 deletions

View File

@@ -9,7 +9,7 @@ from .items import item_table, item_names, copy_ability_table, animal_friend_tab
trap_item_table, copy_ability_access_table, star_item_weights, total_filler_weights, animal_friend_spawn_table,\
lookup_item_to_id
from .locations import location_table, KDL3Location, level_consumables, consumable_locations, star_locations
from .names.animal_friend_spawns import animal_friend_spawns
from .names.animal_friend_spawns import animal_friend_spawns, problematic_sets
from .names.enemy_abilities import vanilla_enemies, enemy_mapping, enemy_restrictive
from .regions import create_levels, default_levels
from .options import KDL3Options, kdl3_option_groups
@@ -213,6 +213,24 @@ class KDL3World(World):
self.collect(allstate, self.create_item(item))
self.random.shuffle(locations)
fill_restrictive(self.multiworld, allstate, locations, items, True, True)
# Need to ensure all of these are unique items, and replace them if they aren't
for spawns in problematic_sets:
placed = [self.get_location(spawn).item for spawn in spawns]
placed_names = set([item.name for item in placed])
if len(placed_names) != len(placed):
# have a duplicate
animals = []
for spawn in spawns:
spawn_location = self.get_location(spawn)
if spawn_location.item.name not in animals:
animals.append(spawn_location.item.name)
else:
new_animal = self.random.choice([x for x in ["Rick Spawn", "Coo Spawn", "Kine Spawn",
"ChuChu Spawn", "Nago Spawn", "Pitch Spawn"]
if x not in placed_names])
spawn_location.item = self.create_item(new_animal)
# logically, this should be sound pre-ER. May need to adjust around it with ER in the future
else:
animal_friends = animal_friend_spawns.copy()
for animal in animal_friends:

View File

@@ -1,3 +1,5 @@
from typing import List
grass_land_1_a1 = "Grass Land 1 - Animal 1" # Nago
grass_land_1_a2 = "Grass Land 1 - Animal 2" # Rick
grass_land_2_a1 = "Grass Land 2 - Animal 1" # ChuChu
@@ -197,3 +199,12 @@ animal_friend_spawns = {
iceberg_6_a5: "ChuChu Spawn",
iceberg_6_a6: "Nago Spawn",
}
problematic_sets: List[List[str]] = [
# Animal groups that must be guaranteed unique. Potential for softlocks on future-ER if not.
[ripple_field_4_a1, ripple_field_4_a2, ripple_field_4_a3],
[sand_canyon_3_a1, sand_canyon_3_a2, sand_canyon_3_a3],
[cloudy_park_6_a1, cloudy_park_6_a2, cloudy_park_6_a3],
[iceberg_6_a1, iceberg_6_a2, iceberg_6_a3],
[iceberg_6_a4, iceberg_6_a5, iceberg_6_a6]
]

View File

@@ -1,5 +1,5 @@
from worlds.generic.Rules import set_rule, add_rule
from .names import location_name, enemy_abilities
from .names import location_name, enemy_abilities, animal_friend_spawns
from .locations import location_table
from .options import GoalSpeed
import typing
@@ -302,6 +302,13 @@ def set_rules(world: "KDL3World") -> None:
set_rule(world.multiworld.get_location(enemy_abilities.Sand_Canyon_4_E10, world.player),
lambda state: can_reach_kine(state, world.player) or can_reach_chuchu(state, world.player))
# animal friend rules
set_rule(world.multiworld.get_location(animal_friend_spawns.iceberg_4_a2, world.player),
lambda state: can_reach_coo(state, world.player) and can_reach_burning(state, world.player))
set_rule(world.multiworld.get_location(animal_friend_spawns.iceberg_4_a3, world.player),
lambda state: can_reach_chuchu(state, world.player) and can_reach_coo(state, world.player)
and can_reach_burning(state, world.player))
for boss_flag, purification, i in zip(["Level 1 Boss - Purified", "Level 2 Boss - Purified",
"Level 3 Boss - Purified", "Level 4 Boss - Purified",
"Level 5 Boss - Purified"],

View File

@@ -240,6 +240,9 @@ MainLoopHook:
BEQ .Return ; return if we are
LDA $5541 ; gooey status
BPL .Slowness ; gooey is already spawned
LDA $39D1 ; is kirby alive?
BEQ .Slowness ; branch if he isn't
; maybe BMI here too?
LDA $8080
CMP #$0000 ; did we get a gooey trap
BEQ .Slowness ; branch if we did not
@@ -432,17 +435,47 @@ AnimalFriendSpawn:
BNE .Return
XBA
PHA
PHX
PHA
LDX #$0000
.CheckSpawned:
LDA $05CA, X
BNE .Continue
LDA #$0002
CMP $074A, X
BNE .ContinueCheck
PLA
PHA
XBA
CMP $07CA, X
BEQ .AlreadySpawned
.ContinueCheck:
INX
INX
BRA .CheckSpawned
.Continue:
PLA
PLX
ASL
TAY
PLA
INC
CMP $8000, Y ; do we have this animal friend
BEQ .Return ; we have this animal friend
.False:
INX
.Return:
PLY
LDA #$9999
RTL
.AlreadySpawned:
PLA
PLX
ASL
TAY
PLA
BRA .False
WriteBWRAM:
LDY #$6001 ;starting addr

View File

@@ -1,6 +1,7 @@
from typing import List, Tuple, Optional
from . import KDL3TestBase
from ..room import KDL3Room
from ..names import animal_friend_spawns
class TestCopyAbilityShuffle(KDL3TestBase):
@@ -174,6 +175,14 @@ class TestAnimalShuffle(KDL3TestBase):
self.assertTrue(sand_canyon_6.item is not None and sand_canyon_6.item.name in
{"Kine Spawn", "Coo Spawn"}, f"Multiworld did not place Coo/Kine, Seed: {self.multiworld.seed}")
def test_problematic(self) -> None:
for spawns in animal_friend_spawns.problematic_sets:
placed = [self.multiworld.get_location(spawn, 1).item for spawn in spawns]
placed_names = set([item.name for item in placed])
self.assertEqual(len(placed), len(placed_names),
f"Duplicate animal placed in problematic locations:"
f" {[spawn.location for spawn in placed]}")
class TestAllShuffle(KDL3TestBase):
options = {
@@ -238,6 +247,14 @@ class TestAllShuffle(KDL3TestBase):
self.assertTrue(sand_canyon_6.item is not None and sand_canyon_6.item.name in
{"Kine Spawn", "Coo Spawn"}, f"Multiworld did not place Coo/Kine, Seed: {self.multiworld.seed}")
def test_problematic(self) -> None:
for spawns in animal_friend_spawns.problematic_sets:
placed = [self.multiworld.get_location(spawn, 1).item for spawn in spawns]
placed_names = set([item.name for item in placed])
self.assertEqual(len(placed), len(placed_names),
f"Duplicate animal placed in problematic locations:"
f" {[spawn.location for spawn in placed]}")
def test_cutter_and_burning_reachable(self) -> None:
rooms = self.multiworld.worlds[1].rooms
copy_abilities = self.multiworld.worlds[1].copy_abilities