Skip to content

Commit 0372e49

Browse files
committed
sm64ex: Refactor Regions
1 parent c7d4c2f commit 0372e49

File tree

3 files changed

+111
-86
lines changed

3 files changed

+111
-86
lines changed

worlds/sm64ex/Regions.py

+43-24
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,43 @@
55
locHMC_table, locLLL_table, locSSL_table, locDDD_table, locSL_table, \
66
locWDW_table, locTTM_table, locTHI_table, locTTC_table, locRR_table, \
77
locPSS_table, locSA_table, locBitDW_table, locTotWC_table, locCotMC_table, \
8-
locVCutM_table, locBitFS_table, locWMotR_table, locBitS_table, locSS_table
9-
10-
# List of all courses, including secrets, without BitS as that one is static
11-
sm64courses = ["Bob-omb Battlefield", "Whomp's Fortress", "Jolly Roger Bay", "Cool, Cool Mountain", "Big Boo's Haunt",
12-
"Hazy Maze Cave", "Lethal Lava Land", "Shifting Sand Land", "Dire, Dire Docks", "Snowman's Land",
13-
"Wet-Dry World", "Tall, Tall Mountain", "Tiny-Huge Island", "Tick Tock Clock", "Rainbow Ride",
14-
"The Princess's Secret Slide", "The Secret Aquarium", "Bowser in the Dark World", "Tower of the Wing Cap",
15-
"Cavern of the Metal Cap", "Vanish Cap under the Moat", "Bowser in the Fire Sea", "Wing Mario over the Rainbow"]
16-
17-
# sm64paintings is list of entrances, format LEVEL | AREA. String Reference below
18-
sm64paintings = [91,241,121,51,41,71,221,81,231,101,111,361,132,131,141,151]
19-
sm64paintings_s = ["BOB", "WF", "JRB", "CCM", "BBH", "HMC", "LLL", "SSL", "DDD", "SL", "WDW", "TTM", "THI Tiny", "THI Huge", "TTC", "RR"]
20-
# sm64secrets is list of secret areas
21-
sm64secrets = [271, 201, 171, 291, 281, 181, 191, 311]
22-
sm64secrets_s = ["PSS", "SA", "BitDW", "TOTWC", "COTMC", "VCUTM", "BitFS", "WMOTR"]
23-
24-
sm64entrances = sm64paintings + sm64secrets
25-
sm64entrances_s = sm64paintings_s + sm64secrets_s
26-
sm64_internalloc_to_string = dict(zip(sm64paintings+sm64secrets, sm64entrances_s))
27-
sm64_internalloc_to_regionid = dict(zip(sm64paintings+sm64secrets, list(range(13)) + [12,13,14] + list(range(15,15+len(sm64secrets)))))
8+
locVCutM_table, locBitFS_table, locWMotR_table, locBitS_table, locSS_table
9+
10+
# sm64paintings is dict of entrances, format LEVEL | AREA
11+
sm64_level_to_paintings = {
12+
91: "Bob-omb Battlefield",
13+
241: "Whomp's Fortress",
14+
121: "Jolly Roger Bay",
15+
51: "Cool, Cool Mountain",
16+
41: "Big Boo's Haunt",
17+
71: "Hazy Maze Cave",
18+
221: "Lethal Lava Land",
19+
81: "Shifting Sand Land",
20+
231: "Dire, Dire Docks",
21+
101: "Snowman's Land",
22+
111: "Wet-Dry World",
23+
361: "Tall, Tall Mountain",
24+
132: "Tiny-Huge Island (Tiny)",
25+
131: "Tiny-Huge Island (Huge)",
26+
141: "Tick Tock Clock",
27+
151: "Rainbow Ride"
28+
}
29+
sm64_paintings_to_level = { painting: level for (level,painting) in sm64_level_to_paintings.items() }
30+
# sm64secrets is list of secret areas, same format
31+
sm64_level_to_secrets = {
32+
271: "The Princess's Secret Slide",
33+
201: "The Secret Aquarium",
34+
171: "Bowser in the Dark World",
35+
291: "Tower of the Wing Cap",
36+
281: "Cavern of the Metal Cap",
37+
181: "Vanish Cap under the Moat",
38+
191: "Bowser in the Fire Sea",
39+
311: "Wing Mario over the Rainbow"
40+
}
41+
sm64_secrets_to_level = { secret: level for (level,secret) in sm64_level_to_secrets.items() }
42+
43+
sm64_entrances_to_level = { **sm64_paintings_to_level, **sm64_secrets_to_level }
44+
sm64_level_to_entrances = { **sm64_level_to_paintings, **sm64_level_to_secrets }
2845

2946
def create_regions(world: MultiWorld, player: int):
3047
regSS = Region("Menu", player, world, "Castle Area")
@@ -137,11 +154,13 @@ def create_regions(world: MultiWorld, player: int):
137154
regTTM.locations.append(SM64Location(player, "TTM: 100 Coins", location_table["TTM: 100 Coins"], regTTM))
138155
world.regions.append(regTTM)
139156

140-
regTHI = create_region("Tiny-Huge Island", player, world)
141-
create_default_locs(regTHI, locTHI_table, player)
157+
regTHIT = create_region("Tiny-Huge Island (Tiny)", player, world)
158+
create_default_locs(regTHIT, locTHI_table, player)
142159
if (world.EnableCoinStars[player].value):
143-
regTHI.locations.append(SM64Location(player, "THI: 100 Coins", location_table["THI: 100 Coins"], regTHI))
144-
world.regions.append(regTHI)
160+
regTHIT.locations.append(SM64Location(player, "THI: 100 Coins", location_table["THI: 100 Coins"], regTHIT))
161+
world.regions.append(regTHIT)
162+
regTHIH = create_region("Tiny-Huge Island (Huge)", player, world)
163+
world.regions.append(regTHIH)
145164

146165
regFloor3 = create_region("Third Floor", player, world)
147166
world.regions.append(regFloor3)

worlds/sm64ex/Rules.py

+63-56
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,84 @@
11
from ..generic.Rules import add_rule
2-
from .Regions import connect_regions, sm64courses, sm64paintings, sm64secrets, sm64entrances
3-
4-
def fix_reg(entrance_ids, reg, invalidspot, swaplist, world):
5-
if entrance_ids.index(reg) == invalidspot: # Unlucky :C
6-
swaplist.remove(invalidspot)
7-
rand = world.random.choice(swaplist)
8-
entrance_ids[invalidspot], entrance_ids[rand] = entrance_ids[rand], entrance_ids[invalidspot]
9-
swaplist.append(invalidspot)
10-
swaplist.remove(rand)
11-
12-
def set_rules(world, player: int, area_connections):
13-
destination_regions = list(range(13)) + [12,13,14] + list(range(15,15+len(sm64secrets))) # Two instances of Destination Course THI. Past normal course idx are secret regions
14-
secret_entrance_ids = list(range(len(sm64paintings), len(sm64paintings) + len(sm64secrets)))
15-
course_entrance_ids = list(range(len(sm64paintings)))
16-
if world.AreaRandomizer[player].value >= 1: # Some randomization is happening, randomize Courses
17-
world.random.shuffle(course_entrance_ids)
2+
from .Regions import connect_regions, sm64_level_to_paintings, sm64_paintings_to_level, sm64_level_to_secrets, sm64_entrances_to_level, sm64_level_to_entrances
3+
4+
def shuffle_dict_keys(world, obj: dict) -> dict:
5+
keys = list(obj.keys())
6+
values = list(obj.values())
7+
world.random.shuffle(keys)
8+
return dict(zip(keys,values))
9+
10+
def fix_reg(entrance_ids, entrance, destination, swapdict, world):
11+
if entrance_ids[entrance] == destination: # Unlucky :C
12+
rand = world.random.choice(swapdict.keys())
13+
entrance_ids[entrance], entrance_ids[swapdict[rand]] = rand, entrance_ids[entrance]
14+
swapdict[rand] = entrance_ids[entrance]
15+
swapdict.pop(entrance)
16+
17+
def set_rules(world, player: int, area_connections: dict):
18+
randomized_level_to_paintings = sm64_level_to_paintings.copy()
19+
randomized_level_to_secrets = sm64_level_to_secrets.copy()
20+
if world.AreaRandomizer[player].value == 1: # Some randomization is happening, randomize Courses
21+
randomized_level_to_paintings = shuffle_dict_keys(world,sm64_level_to_paintings)
1822
if world.AreaRandomizer[player].value == 2: # Randomize Secrets as well
19-
world.random.shuffle(secret_entrance_ids)
20-
entrance_ids = course_entrance_ids + secret_entrance_ids
23+
randomized_level_to_secrets = shuffle_dict_keys(world,sm64_level_to_secrets)
24+
randomized_entrances = { **randomized_level_to_paintings, **randomized_level_to_secrets }
2125
if world.AreaRandomizer[player].value == 3: # Randomize Courses and Secrets in one pool
22-
world.random.shuffle(entrance_ids)
26+
randomized_entrances = shuffle_dict_keys(world,randomized_entrances)
2327
# Guarantee first entrance is a course
24-
swaplist = list(range(len(entrance_ids)))
25-
if entrance_ids.index(0) > 15: # Unlucky :C
26-
rand = world.random.randint(0,15)
27-
entrance_ids[entrance_ids.index(0)], entrance_ids[rand] = entrance_ids[rand], entrance_ids[entrance_ids.index(0)]
28-
swaplist.remove(entrance_ids.index(0))
28+
swapdict = { entrance: level for (level,entrance) in randomized_entrances }
29+
if randomized_entrances[91] not in sm64_paintings_to_level.keys(): # Unlucky :C (91 -> BoB Entrance)
30+
rand = world.random.choice(sm64_paintings_to_level.values())
31+
randomized_entrances[91], randomized_entrances[swapdict[rand]] = rand, randomized_entrances[91]
32+
swapdict[rand] = randomized_entrances[91]
33+
swapdict.pop("Bob-omb Battlefield")
2934
# Guarantee COTMC is not mapped to HMC, cuz thats impossible
30-
fix_reg(entrance_ids, 20, 5, swaplist, world)
35+
fix_reg(randomized_entrances, "Cavern of the Metal Cap", "Hazy Maze Cave", swapdict, world)
3136
# Guarantee BITFS is not mapped to DDD
32-
fix_reg(entrance_ids, 22, 8, swaplist, world)
33-
if entrance_ids.index(22) == 5: # If BITFS is mapped to HMC...
34-
fix_reg(entrance_ids, 20, 8, swaplist, world) # ... then dont allow COTMC to be mapped to DDD
35-
temp_assign = dict(zip(entrance_ids,destination_regions)) # Used for Rules only
37+
fix_reg(randomized_entrances, "Bowser in the Fire Sea", "Dire, Dire Docks", swapdict, world)
38+
if randomized_entrances[191] == "Hazy Maze Cave": # If BITFS is mapped to HMC...
39+
fix_reg(randomized_entrances, "Cavern of the Metal Cap", "Dire, Dire Docks", swapdict, world) # ... then dont allow COTMC to be mapped to DDD
3640

3741
# Destination Format: LVL | AREA with LVL = LEVEL_x, AREA = Area as used in sm64 code
38-
area_connections.update({sm64entrances[entrance]: destination for entrance, destination in zip(entrance_ids,sm64entrances)})
42+
area_connections.update({entrance_lvl: sm64_entrances_to_level[destination] for (entrance_lvl,destination) in randomized_entrances.items()})
43+
randomized_entrances_s = {sm64_level_to_entrances[entrance_lvl]: destination for (entrance_lvl,destination) in randomized_entrances.items()}
3944

40-
connect_regions(world, player, "Menu", sm64courses[temp_assign[0]]) # BOB
41-
connect_regions(world, player, "Menu", sm64courses[temp_assign[1]], lambda state: state.has("Power Star", player, 1)) # WF
42-
connect_regions(world, player, "Menu", sm64courses[temp_assign[2]], lambda state: state.has("Power Star", player, 3)) # JRB
43-
connect_regions(world, player, "Menu", sm64courses[temp_assign[3]], lambda state: state.has("Power Star", player, 3)) # CCM
44-
connect_regions(world, player, "Menu", sm64courses[temp_assign[4]], lambda state: state.has("Power Star", player, 12)) # BBH
45-
connect_regions(world, player, "Menu", sm64courses[temp_assign[16]], lambda state: state.has("Power Star", player, 1)) # PSS
46-
connect_regions(world, player, "Menu", sm64courses[temp_assign[17]], lambda state: state.has("Power Star", player, 3)) # SA
47-
connect_regions(world, player, "Menu", sm64courses[temp_assign[19]], lambda state: state.has("Power Star", player, 10)) # TOTWC
48-
connect_regions(world, player, "Menu", sm64courses[temp_assign[18]], lambda state: state.has("Power Star", player, world.FirstBowserStarDoorCost[player].value)) # BITDW
45+
connect_regions(world, player, "Menu", randomized_entrances_s["Bob-omb Battlefield"])
46+
connect_regions(world, player, "Menu", randomized_entrances_s["Whomp's Fortress"], lambda state: state.has("Power Star", player, 1))
47+
connect_regions(world, player, "Menu", randomized_entrances_s["Jolly Roger Bay"], lambda state: state.has("Power Star", player, 3))
48+
connect_regions(world, player, "Menu", randomized_entrances_s["Cool, Cool Mountain"], lambda state: state.has("Power Star", player, 3))
49+
connect_regions(world, player, "Menu", randomized_entrances_s["Big Boo's Haunt"], lambda state: state.has("Power Star", player, 12))
50+
connect_regions(world, player, "Menu", randomized_entrances_s["The Princess's Secret Slide"], lambda state: state.has("Power Star", player, 1))
51+
connect_regions(world, player, "Menu", randomized_entrances_s["The Secret Aquarium"], lambda state: state.has("Power Star", player, 3))
52+
connect_regions(world, player, "Menu", randomized_entrances_s["Tower of the Wing Cap"], lambda state: state.has("Power Star", player, 10))
53+
connect_regions(world, player, "Menu", randomized_entrances_s["Bowser in the Dark World"], lambda state: state.has("Power Star", player, world.FirstBowserStarDoorCost[player].value))
4954

5055
connect_regions(world, player, "Menu", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1))
5156

52-
connect_regions(world, player, "Basement", sm64courses[temp_assign[5]]) # HMC
53-
connect_regions(world, player, "Basement", sm64courses[temp_assign[6]]) # LLL
54-
connect_regions(world, player, "Basement", sm64courses[temp_assign[7]]) # SSL
55-
connect_regions(world, player, "Basement", sm64courses[temp_assign[8]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value)) # DDD
56-
connect_regions(world, player, "Hazy Maze Cave", sm64courses[temp_assign[20]]) # COTMC
57-
connect_regions(world, player, "Basement", sm64courses[temp_assign[21]]) # VCUTM
58-
connect_regions(world, player, "Basement", sm64courses[temp_assign[22]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value) and
59-
state.can_reach("DDD: Board Bowser's Sub", 'Location', player)) # BITFS
57+
connect_regions(world, player, "Basement", randomized_entrances_s["Hazy Maze Cave"])
58+
connect_regions(world, player, "Basement", randomized_entrances_s["Lethal Lava Land"])
59+
connect_regions(world, player, "Basement", randomized_entrances_s["Shifting Sand Land"])
60+
connect_regions(world, player, "Basement", randomized_entrances_s["Dire, Dire Docks"], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value))
61+
connect_regions(world, player, "Hazy Maze Cave", randomized_entrances_s["Cavern of the Metal Cap"])
62+
connect_regions(world, player, "Basement", randomized_entrances_s["Vanish Cap under the Moat"])
63+
connect_regions(world, player, "Basement", randomized_entrances_s["Bowser in the Fire Sea"], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value) and
64+
state.can_reach("DDD: Board Bowser's Sub", 'Location', player))
6065

6166
connect_regions(world, player, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player) or state.has("Progressive Key", player, 2))
6267

63-
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[9]]) # SL
64-
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[10]]) # WDW
65-
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[11]]) # TTM
66-
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[12]]) # THI Tiny
67-
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[13]]) # THI Huge
68+
connect_regions(world, player, "Second Floor", randomized_entrances_s["Snowman's Land"])
69+
connect_regions(world, player, "Second Floor", randomized_entrances_s["Wet-Dry World"])
70+
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tall, Tall Mountain"])
71+
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Tiny)"])
72+
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Huge)"])
73+
connect_regions(world, player, "Tiny-Huge Island (Tiny)", "Tiny-Huge Island (Huge)")
74+
connect_regions(world, player, "Tiny-Huge Island (Huge)", "Tiny-Huge Island (Tiny)")
6875

6976
connect_regions(world, player, "Second Floor", "Third Floor", lambda state: state.has("Power Star", player, world.SecondFloorStarDoorCost[player].value))
7077

71-
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[14]]) # TTC
72-
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[15]]) # RR
73-
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[23]]) # WMOTR
74-
connect_regions(world, player, "Third Floor", "Bowser in the Sky", lambda state: state.has("Power Star", player, world.StarsToFinish[player].value)) # BITS
78+
connect_regions(world, player, "Third Floor", randomized_entrances_s["Tick Tock Clock"])
79+
connect_regions(world, player, "Third Floor", randomized_entrances_s["Rainbow Ride"])
80+
connect_regions(world, player, "Third Floor", randomized_entrances_s["Wing Mario over the Rainbow"])
81+
connect_regions(world, player, "Third Floor", "Bowser in the Sky", lambda state: state.has("Power Star", player, world.StarsToFinish[player].value))
7582

7683
#Special Rules for some Locations
7784
add_rule(world.get_location("BoB: Mario Wings to the Sky", player), lambda state: state.has("Cannon Unlock BoB", player))

worlds/sm64ex/__init__.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .Locations import location_table, SM64Location
66
from .Options import sm64_options
77
from .Rules import set_rules
8-
from .Regions import create_regions, sm64courses, sm64entrances_s, sm64_internalloc_to_string, sm64_internalloc_to_regionid
8+
from .Regions import create_regions, sm64_level_to_entrances
99
from BaseClasses import Item, Tutorial, ItemClassification
1010
from ..AutoWorld import World, WebWorld
1111

@@ -55,8 +55,8 @@ def set_rules(self):
5555
# Write area_connections to spoiler log
5656
for entrance, destination in self.area_connections.items():
5757
self.multiworld.spoiler.set_entrance(
58-
sm64_internalloc_to_string[entrance] + " Entrance",
59-
sm64_internalloc_to_string[destination],
58+
sm64_level_to_entrances[entrance] + " Entrance",
59+
sm64_level_to_entrances[destination],
6060
'entrance', self.player)
6161

6262
def create_item(self, name: str) -> Item:
@@ -182,8 +182,7 @@ def modify_multidata(self, multidata):
182182
if self.topology_present:
183183
er_hint_data = {}
184184
for entrance, destination in self.area_connections.items():
185-
regionid = sm64_internalloc_to_regionid[destination]
186-
region = self.multiworld.get_region(sm64courses[regionid], self.player)
185+
region = self.multiworld.get_region(sm64_level_to_entrances[destination], self.player)
187186
for location in region.locations:
188-
er_hint_data[location.address] = sm64_internalloc_to_string[entrance]
187+
er_hint_data[location.address] = sm64_level_to_entrances[entrance]
189188
multidata['er_hint_data'][self.player] = er_hint_data

0 commit comments

Comments
 (0)