1040 lines
39 KiB
Python
1040 lines
39 KiB
Python
from worlds.generic.Rules import set_rule, add_rule
|
|
from BaseClasses import CollectionState
|
|
from typing import Dict
|
|
from .Regions import Stages
|
|
|
|
|
|
def graffitiM(state: CollectionState, player: int, limit: bool, spots: int) -> bool:
|
|
return state.count_group_exclusive("graffitim", player) * 7 >= spots if limit \
|
|
else state.has_group("graffitim", player)
|
|
|
|
|
|
def graffitiL(state: CollectionState, player: int, limit: bool, spots: int) -> bool:
|
|
return state.count_group_exclusive("graffitil", player) * 6 >= spots if limit \
|
|
else state.has_group("graffitil", player)
|
|
|
|
|
|
def graffitiXL(state: CollectionState, player: int, limit: bool, spots: int) -> bool:
|
|
return state.count_group_exclusive("graffitixl", player) * 4 >= spots if limit \
|
|
else state.has_group("graffitixl", player)
|
|
|
|
|
|
def skateboard(state: CollectionState, player: int, movestyle: int) -> bool:
|
|
return True if movestyle == 2 else state.has_group("skateboard", player)
|
|
|
|
|
|
def inline_skates(state: CollectionState, player: int, movestyle: int) -> bool:
|
|
return True if movestyle == 3 else state.has_group("skates", player)
|
|
|
|
|
|
def bmx(state: CollectionState, player: int, movestyle: int) -> bool:
|
|
return True if movestyle == 1 else state.has_group("bmx", player)
|
|
|
|
|
|
def camera(state: CollectionState, player: int) -> bool:
|
|
return state.has("Camera App", player)
|
|
|
|
|
|
def is_girl(state: CollectionState, player: int) -> bool:
|
|
return state.has_group("girl", player)
|
|
|
|
|
|
def current_chapter(state: CollectionState, player: int, chapter: int) -> bool:
|
|
return state.has("Chapter Completed", player, chapter-1)
|
|
|
|
|
|
def versum_hill_entrance(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 20)
|
|
|
|
|
|
def versum_hill_ch1_roadblock(state: CollectionState, player: int, limit: bool) -> bool:
|
|
return graffitiL(state, player, limit, 10)
|
|
|
|
|
|
def versum_hill_challenge1(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 50)
|
|
|
|
|
|
def versum_hill_challenge2(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 58)
|
|
|
|
|
|
def versum_hill_challenge3(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 65)
|
|
|
|
|
|
def versum_hill_all_challenges(state: CollectionState, player: int) -> bool:
|
|
return versum_hill_challenge3(state, player)
|
|
|
|
|
|
def versum_hill_basketball_court(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 90)
|
|
|
|
|
|
def versum_hill_oldhead(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 120)
|
|
|
|
|
|
def versum_hill_crew_battle(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
rep(state, player, 90)
|
|
and graffitiM(state, player, limit, 98)
|
|
)
|
|
else:
|
|
return (
|
|
rep(state, player, 90)
|
|
and graffitiM(state, player, limit, 27)
|
|
)
|
|
|
|
|
|
def versum_hill_rietveld(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
current_chapter(state, player, 2)
|
|
and graffitiM(state, player, limit, 114)
|
|
)
|
|
else:
|
|
return (
|
|
current_chapter(state, player, 2)
|
|
and graffitiM(state, player, limit, 67)
|
|
)
|
|
|
|
|
|
def versum_hill_rave(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
if current_chapter(state, player, 4):
|
|
return (
|
|
graffitiL(state, player, limit, 90)
|
|
and graffitiXL(state, player, limit, 51)
|
|
)
|
|
elif current_chapter(state, player, 3):
|
|
return (
|
|
graffitiL(state, player, limit, 89)
|
|
and graffitiXL(state, player, limit, 51)
|
|
)
|
|
else:
|
|
return (
|
|
graffitiL(state, player, limit, 85)
|
|
and graffitiXL(state, player, limit, 48)
|
|
)
|
|
else:
|
|
return (
|
|
graffitiL(state, player, limit, 26)
|
|
and graffitiXL(state, player, limit, 10)
|
|
)
|
|
|
|
|
|
def millennium_square_entrance(state: CollectionState, player: int) -> bool:
|
|
return current_chapter(state, player, 2)
|
|
|
|
|
|
def brink_terminal_entrance(state: CollectionState, player: int) -> bool:
|
|
return (
|
|
is_girl(state, player)
|
|
and rep(state, player, 180)
|
|
and current_chapter(state, player, 2)
|
|
)
|
|
|
|
|
|
def brink_terminal_challenge1(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 188)
|
|
|
|
|
|
def brink_terminal_challenge2(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 200)
|
|
|
|
|
|
def brink_terminal_challenge3(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 220)
|
|
|
|
|
|
def brink_terminal_all_challenges(state: CollectionState, player: int) -> bool:
|
|
return brink_terminal_challenge3(state, player)
|
|
|
|
|
|
def brink_terminal_plaza(state: CollectionState, player: int) -> bool:
|
|
return brink_terminal_all_challenges(state, player)
|
|
|
|
|
|
def brink_terminal_tower(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 280)
|
|
|
|
|
|
def brink_terminal_oldhead_underground(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 250)
|
|
|
|
|
|
def brink_terminal_oldhead_dock(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 320)
|
|
|
|
|
|
def brink_terminal_crew_battle(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
rep(state, player, 280)
|
|
and graffitiL(state, player, limit, 103)
|
|
)
|
|
else:
|
|
return (
|
|
rep(state, player, 280)
|
|
and graffitiL(state, player, limit, 62)
|
|
)
|
|
|
|
|
|
def brink_terminal_mesh(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
graffitiM(state, player, limit, 114)
|
|
and graffitiXL(state, player, limit, 45)
|
|
)
|
|
else:
|
|
return (
|
|
graffitiM(state, player, limit, 67)
|
|
and graffitiXL(state, player, limit, 45)
|
|
)
|
|
|
|
|
|
def millennium_mall_entrance(state: CollectionState, player: int) -> bool:
|
|
return (
|
|
rep(state, player, 380)
|
|
and current_chapter(state, player, 3)
|
|
)
|
|
|
|
|
|
def millennium_mall_oldhead_ceiling(state: CollectionState, player: int, limit: bool) -> bool:
|
|
return (
|
|
rep(state, player, 580)
|
|
or millennium_mall_theater(state, player, limit)
|
|
)
|
|
|
|
|
|
def millennium_mall_switch(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
graffitiM(state, player, limit, 114)
|
|
and current_chapter(state, player, 3)
|
|
)
|
|
else:
|
|
return (
|
|
graffitiM(state, player, limit, 72)
|
|
and current_chapter(state, player, 3)
|
|
)
|
|
|
|
|
|
def millennium_mall_big(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return millennium_mall_switch(state, player, limit, glitched)
|
|
|
|
|
|
def millennium_mall_oldhead_race(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 530)
|
|
|
|
|
|
def millennium_mall_challenge1(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 434)
|
|
|
|
|
|
def millennium_mall_challenge2(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 442)
|
|
|
|
|
|
def millennium_mall_challenge3(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 450)
|
|
|
|
|
|
def millennium_mall_challenge4(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 458)
|
|
|
|
|
|
def millennium_mall_all_challenges(state: CollectionState, player: int) -> bool:
|
|
return millennium_mall_challenge4(state, player)
|
|
|
|
|
|
def millennium_mall_theater(state: CollectionState, player: int, limit: bool) -> bool:
|
|
return (
|
|
rep(state, player, 491)
|
|
and graffitiM(state, player, limit, 78)
|
|
)
|
|
|
|
|
|
def millennium_mall_crew_battle(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
rep(state, player, 491)
|
|
and graffitiM(state, player, limit, 114)
|
|
and graffitiL(state, player, limit, 107)
|
|
)
|
|
else:
|
|
return (
|
|
rep(state, player, 491)
|
|
and graffitiM(state, player, limit, 78)
|
|
and graffitiL(state, player, limit, 80)
|
|
)
|
|
|
|
|
|
def pyramid_island_entrance(state: CollectionState, player: int) -> bool:
|
|
return current_chapter(state, player, 4)
|
|
|
|
|
|
def pyramid_island_gate(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 620)
|
|
|
|
|
|
def pyramid_island_oldhead(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 780)
|
|
|
|
|
|
def pyramid_island_challenge1(state: CollectionState, player: int) -> bool:
|
|
return (
|
|
rep(state, player, 630)
|
|
and current_chapter(state, player, 4)
|
|
)
|
|
|
|
|
|
def pyramid_island_race(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
pyramid_island_challenge1(state, player)
|
|
and graffitiL(state, player, limit, 108)
|
|
)
|
|
else:
|
|
return (
|
|
pyramid_island_challenge1(state, player)
|
|
and graffitiL(state, player, limit, 93)
|
|
)
|
|
|
|
|
|
def pyramid_island_challenge2(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 650)
|
|
|
|
|
|
def pyramid_island_challenge3(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 660)
|
|
|
|
|
|
def pyramid_island_all_challenges(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
graffitiM(state, player, limit, 114)
|
|
and rep(state, player, 660)
|
|
)
|
|
else:
|
|
return (
|
|
graffitiM(state, player, limit, 88)
|
|
and rep(state, player, 660)
|
|
)
|
|
|
|
|
|
def pyramid_island_upper_half(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return pyramid_island_all_challenges(state, player, limit, glitched)
|
|
|
|
|
|
def pyramid_island_crew_battle(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
rep(state, player, 730)
|
|
and graffitiL(state, player, limit, 108)
|
|
)
|
|
else:
|
|
return (
|
|
rep(state, player, 730)
|
|
and graffitiL(state, player, limit, 97)
|
|
)
|
|
|
|
|
|
def pyramid_island_top(state: CollectionState, player: int) -> bool:
|
|
return current_chapter(state, player, 5)
|
|
|
|
|
|
def mataan_entrance(state: CollectionState, player: int) -> bool:
|
|
return current_chapter(state, player, 2)
|
|
|
|
|
|
def mataan_smoke_wall(state: CollectionState, player: int) -> bool:
|
|
return (
|
|
current_chapter(state, player, 5)
|
|
and rep(state, player, 850)
|
|
)
|
|
|
|
|
|
def mataan_challenge1(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
current_chapter(state, player, 5)
|
|
and rep(state, player, 864)
|
|
and graffitiL(state, player, limit, 108)
|
|
)
|
|
else:
|
|
return (
|
|
current_chapter(state, player, 5)
|
|
and rep(state, player, 864)
|
|
and graffitiL(state, player, limit, 98)
|
|
)
|
|
|
|
|
|
def mataan_deep_city(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return mataan_challenge1(state, player, limit, glitched)
|
|
|
|
|
|
def mataan_oldhead(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 935)
|
|
|
|
|
|
def mataan_challenge2(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
rep(state, player, 880)
|
|
and graffitiXL(state, player, limit, 59)
|
|
)
|
|
else:
|
|
return (
|
|
rep(state, player, 880)
|
|
and graffitiXL(state, player, limit, 57)
|
|
)
|
|
|
|
|
|
def mataan_challenge3(state: CollectionState, player: int) -> bool:
|
|
return rep(state, player, 920)
|
|
|
|
|
|
def mataan_all_challenges(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return (
|
|
mataan_challenge2(state, player, limit, glitched)
|
|
and mataan_challenge3(state, player)
|
|
)
|
|
|
|
|
|
def mataan_smoke_wall2(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return (
|
|
mataan_all_challenges(state, player, limit, glitched)
|
|
and rep(state, player, 960)
|
|
)
|
|
|
|
|
|
def mataan_crew_battle(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
if glitched:
|
|
return (
|
|
mataan_smoke_wall2(state, player, limit, glitched)
|
|
and graffitiM(state, player, limit, 122)
|
|
and graffitiXL(state, player, limit, 59)
|
|
)
|
|
else:
|
|
return (
|
|
mataan_smoke_wall2(state, player, limit, glitched)
|
|
and graffitiM(state, player, limit, 117)
|
|
and graffitiXL(state, player, limit, 57)
|
|
)
|
|
|
|
|
|
def mataan_deepest(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return mataan_crew_battle(state, player, limit, glitched)
|
|
|
|
|
|
def mataan_faux(state: CollectionState, player: int, limit: bool, glitched: bool) -> bool:
|
|
return (
|
|
mataan_deepest(state, player, limit, glitched)
|
|
and graffitiM(state, player, limit, 122)
|
|
)
|
|
|
|
|
|
def spots_s_glitchless(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 10
|
|
conditions: Dict[str, int] = {
|
|
"versum_hill_entrance": 1,
|
|
"versum_hill_ch1_roadblock": 11,
|
|
"chapter2": 12,
|
|
"versum_hill_oldhead": 1,
|
|
"brink_terminal_entrance": 9,
|
|
"brink_terminal_plaza": 3,
|
|
"brink_terminal_tower": 0,
|
|
"chapter3": 6,
|
|
"brink_terminal_oldhead_dock": 1,
|
|
"millennium_mall_entrance": 3,
|
|
"millennium_mall_switch": 4,
|
|
"millennium_mall_theater": 3,
|
|
"chapter4": 2,
|
|
"pyramid_island_gate": 5,
|
|
"pyramid_island_upper_half": 8,
|
|
"pyramid_island_oldhead": 2,
|
|
"mataan_smoke_wall": 3,
|
|
"mataan_deep_city": 5,
|
|
"mataan_oldhead": 3,
|
|
"mataan_deepest": 2
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
else:
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = 5 + (state.count_group_exclusive("characters", player) * 5)
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
return total
|
|
|
|
|
|
def spots_s_glitched(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 75
|
|
conditions: Dict[str, int] = {
|
|
"brink_terminal_entrance": 13,
|
|
"chapter3": 6
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
else:
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = 5 + (state.count_group_exclusive("characters", player) * 5)
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
return total
|
|
|
|
|
|
def spots_m_glitchless(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 4
|
|
conditions: Dict[str, int] = {
|
|
"versum_hill_entrance": 3,
|
|
"versum_hill_ch1_roadblock": 13,
|
|
"versum_hill_all_challenges": 3,
|
|
"chapter2": 16,
|
|
"versum_hill_oldhead": 4,
|
|
"brink_terminal_entrance": 13,
|
|
"brink_terminal_plaza": 4,
|
|
"brink_terminal_tower": 0,
|
|
"chapter3": 3,
|
|
"brink_terminal_oldhead_dock": 4,
|
|
"millennium_mall_entrance": 5,
|
|
"millennium_mall_big": 6,
|
|
"millennium_mall_theater": 4,
|
|
"chapter4": 2,
|
|
"millennium_mall_oldhead_ceiling": 1,
|
|
"pyramid_island_gate": 3,
|
|
"pyramid_island_upper_half": 8,
|
|
"chapter5": 2,
|
|
"pyramid_island_oldhead": 5,
|
|
"mataan_deep_city": 7,
|
|
"skateboard": 1,
|
|
"mataan_oldhead": 1,
|
|
"mataan_smoke_wall2": 1,
|
|
"mataan_deepest": 10
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
elif access_name != "skateboard":
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = state.count_group_exclusive("graffitim", player) * 7
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
if state.has_group("graffitim", player):
|
|
return total
|
|
else:
|
|
return 0
|
|
|
|
|
|
def spots_m_glitched(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 99
|
|
conditions: Dict[str, int] = {
|
|
"brink_terminal_entrance": 21,
|
|
"chapter3": 3
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
else:
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = state.count_group_exclusive("graffitim", player) * 7
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
if state.has_group("graffitim", player):
|
|
return total
|
|
else:
|
|
return 0
|
|
|
|
|
|
def spots_l_glitchless(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 7
|
|
conditions: Dict[str, int] = {
|
|
"inline_skates": 1,
|
|
"versum_hill_entrance": 2,
|
|
"versum_hill_ch1_roadblock": 13,
|
|
"versum_hill_all_challenges": 1,
|
|
"chapter2": 14,
|
|
"versum_hill_oldhead": 2,
|
|
"brink_terminal_entrance": 10,
|
|
"brink_terminal_plaza": 2,
|
|
"brink_terminal_oldhead_underground": 1,
|
|
"brink_terminal_tower": 1,
|
|
"chapter3": 4,
|
|
"brink_terminal_oldhead_dock": 4,
|
|
"millennium_mall_entrance": 3,
|
|
"millennium_mall_big": 8,
|
|
"millennium_mall_theater": 4,
|
|
"chapter4": 5,
|
|
"millennium_mall_oldhead_ceiling": 3,
|
|
"pyramid_island_gate": 4,
|
|
"pyramid_island_upper_half": 5,
|
|
"pyramid_island_crew_battle": 1,
|
|
"chapter5": 1,
|
|
"pyramid_island_oldhead": 2,
|
|
"mataan_smoke_wall": 1,
|
|
"mataan_deep_city": 2,
|
|
"skateboard": 1,
|
|
"mataan_oldhead": 2,
|
|
"mataan_deepest": 7
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
elif not (access_name == "inline_skates" or access_name == "skateboard"):
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = state.count_group_exclusive("graffitil", player) * 6
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
if state.has_group("graffitil", player):
|
|
return total
|
|
else:
|
|
return 0
|
|
|
|
|
|
def spots_l_glitched(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 88
|
|
conditions: Dict[str, int] = {
|
|
"brink_terminal_entrance": 18,
|
|
"chapter3": 4,
|
|
"chapter4": 1
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
else:
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = state.count_group_exclusive("graffitil", player) * 6
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
if state.has_group("graffitil", player):
|
|
return total
|
|
else:
|
|
return 0
|
|
|
|
|
|
def spots_xl_glitchless(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 3
|
|
conditions: Dict[str, int] = {
|
|
"versum_hill_ch1_roadblock": 6,
|
|
"versum_hill_basketball_court": 1,
|
|
"chapter2": 9,
|
|
"brink_terminal_entrance": 3,
|
|
"brink_terminal_plaza": 1,
|
|
"brink_terminal_oldhead_underground": 1,
|
|
"brink_terminal_tower": 1,
|
|
"chapter3": 3,
|
|
"brink_terminal_oldhead_dock": 2,
|
|
"millennium_mall_entrance": 2,
|
|
"millennium_mall_big": 5,
|
|
"millennium_mall_theater": 5,
|
|
"chapter4": 3,
|
|
"millennium_mall_oldhead_ceiling": 1,
|
|
"pyramid_island_upper_half": 5,
|
|
"pyramid_island_oldhead": 3,
|
|
"mataan_smoke_wall": 2,
|
|
"mataan_deep_city": 2,
|
|
"mataan_oldhead": 2,
|
|
"mataan_deepest": 2
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
else:
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = state.count_group_exclusive("graffitixl", player) * 4
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
if state.has_group("graffitixl", player):
|
|
return total
|
|
else:
|
|
return 0
|
|
|
|
|
|
def spots_xl_glitched(state: CollectionState, player: int, limit: bool, access_cache: Dict[str, bool]) -> int:
|
|
total: int = 51
|
|
conditions: Dict[str, int] = {
|
|
"brink_terminal_entrance": 7,
|
|
"chapter3": 3,
|
|
"chapter4": 1
|
|
}
|
|
|
|
for access_name, graffiti_count in conditions.items():
|
|
if access_cache[access_name]:
|
|
total += graffiti_count
|
|
else:
|
|
break
|
|
|
|
if limit:
|
|
sprayable: int = state.count_group_exclusive("graffitixl", player) * 4
|
|
if total <= sprayable:
|
|
return total
|
|
else:
|
|
return sprayable
|
|
else:
|
|
if state.has_group("graffitixl", player):
|
|
return total
|
|
else:
|
|
return 0
|
|
|
|
|
|
def build_access_cache(state: CollectionState, player: int, movestyle: int, limit: bool, glitched: bool) -> Dict[str, bool]:
|
|
funcs: Dict[str, tuple] = {
|
|
"versum_hill_entrance": (state, player),
|
|
"versum_hill_ch1_roadblock": (state, player, limit),
|
|
"versum_hill_oldhead": (state, player),
|
|
"versum_hill_all_challenges": (state, player),
|
|
"versum_hill_basketball_court": (state, player),
|
|
"brink_terminal_entrance": (state, player),
|
|
"brink_terminal_oldhead_underground": (state, player),
|
|
"brink_terminal_oldhead_dock": (state, player),
|
|
"brink_terminal_plaza": (state, player),
|
|
"brink_terminal_tower": (state, player),
|
|
"millennium_mall_entrance": (state, player),
|
|
"millennium_mall_switch": (state, player, limit, glitched),
|
|
"millennium_mall_oldhead_ceiling": (state, player, limit),
|
|
"millennium_mall_big": (state, player, limit, glitched),
|
|
"millennium_mall_theater": (state, player, limit),
|
|
"pyramid_island_gate": (state, player),
|
|
"pyramid_island_oldhead": (state, player),
|
|
"pyramid_island_upper_half": (state, player, limit, glitched),
|
|
"pyramid_island_crew_battle": (state, player, limit, glitched),
|
|
"mataan_smoke_wall": (state, player),
|
|
"mataan_deep_city": (state, player, limit, glitched),
|
|
"mataan_oldhead": (state, player),
|
|
"mataan_smoke_wall2": (state, player, limit, glitched),
|
|
"mataan_deepest": (state, player, limit, glitched)
|
|
}
|
|
|
|
access_cache: Dict[str, bool] = {
|
|
"skateboard": skateboard(state, player, movestyle),
|
|
"inline_skates": inline_skates(state, player, movestyle),
|
|
"chapter2": current_chapter(state, player, 2),
|
|
"chapter3": current_chapter(state, player, 3),
|
|
"chapter4": current_chapter(state, player, 4),
|
|
"chapter5": current_chapter(state, player, 5)
|
|
}
|
|
|
|
stop: bool = False
|
|
for fname, fvars in funcs.items():
|
|
if stop:
|
|
access_cache[fname] = False
|
|
continue
|
|
func = globals()[fname]
|
|
access: bool = func(*fvars)
|
|
access_cache[fname] = access
|
|
if not access and "oldhead" not in fname:
|
|
stop = True
|
|
|
|
return access_cache
|
|
|
|
|
|
def graffiti_spots(state: CollectionState, player: int, movestyle: int, limit: bool, glitched: bool, spots: int) -> bool:
|
|
access_cache = build_access_cache(state, player, movestyle, limit, glitched)
|
|
|
|
total: int = 0
|
|
|
|
if glitched:
|
|
total = spots_s_glitched(state, player, limit, access_cache) \
|
|
+ spots_m_glitched(state, player, limit, access_cache) \
|
|
+ spots_l_glitched(state, player, limit, access_cache) \
|
|
+ spots_xl_glitched(state, player, limit, access_cache)
|
|
else:
|
|
total = spots_s_glitchless(state, player, limit, access_cache) \
|
|
+ spots_m_glitchless(state, player, limit, access_cache) \
|
|
+ spots_l_glitchless(state, player, limit, access_cache) \
|
|
+ spots_xl_glitchless(state, player, limit, access_cache)
|
|
|
|
return total >= spots
|
|
|
|
|
|
def rep(state: CollectionState, player: int, required: int) -> bool:
|
|
return state.has("rep", player, required)
|
|
|
|
|
|
def rules(brcworld):
|
|
multiworld = brcworld.multiworld
|
|
player = brcworld.player
|
|
|
|
movestyle = brcworld.options.starting_movestyle
|
|
limit = brcworld.options.limited_graffiti
|
|
glitched = brcworld.options.logic
|
|
extra = brcworld.options.extra_rep_required
|
|
photos = not brcworld.options.skip_polo_photos
|
|
|
|
# entrances
|
|
for e in multiworld.get_region(Stages.BT1, player).entrances:
|
|
set_rule(e, lambda state: brink_terminal_entrance(state, player))
|
|
|
|
if not glitched:
|
|
# versum hill
|
|
for e in multiworld.get_region(Stages.VH1, player).entrances:
|
|
set_rule(e, lambda state: versum_hill_entrance(state, player))
|
|
for e in multiworld.get_region(Stages.VH2, player).entrances:
|
|
set_rule(e, lambda state: versum_hill_ch1_roadblock(state, player, limit))
|
|
for e in multiworld.get_region(Stages.VHO, player).entrances:
|
|
set_rule(e, lambda state: versum_hill_oldhead(state, player))
|
|
for e in multiworld.get_region(Stages.VH3, player).entrances:
|
|
set_rule(e, lambda state: versum_hill_all_challenges(state, player))
|
|
for e in multiworld.get_region(Stages.VH4, player).entrances:
|
|
set_rule(e, lambda state: versum_hill_basketball_court(state, player))
|
|
|
|
# millennium square
|
|
for e in multiworld.get_region(Stages.MS, player).entrances:
|
|
set_rule(e, lambda state: millennium_square_entrance(state, player))
|
|
|
|
# brink terminal
|
|
for e in multiworld.get_region(Stages.BTO1, player).entrances:
|
|
set_rule(e, lambda state: brink_terminal_oldhead_underground(state, player))
|
|
for e in multiworld.get_region(Stages.BTO2, player).entrances:
|
|
set_rule(e, lambda state: brink_terminal_oldhead_dock(state, player))
|
|
for e in multiworld.get_region(Stages.BT2, player).entrances:
|
|
set_rule(e, lambda state: brink_terminal_plaza(state, player))
|
|
for e in multiworld.get_region(Stages.BT3, player).entrances:
|
|
set_rule(e, lambda state: brink_terminal_tower(state, player))
|
|
|
|
# millennium mall
|
|
for e in multiworld.get_region(Stages.MM1, player).entrances:
|
|
set_rule(e, lambda state: millennium_mall_entrance(state, player))
|
|
for e in multiworld.get_region(Stages.MMO1, player).entrances:
|
|
set_rule(e, lambda state: millennium_mall_oldhead_ceiling(state, player, limit))
|
|
for e in multiworld.get_region(Stages.MM2, player).entrances:
|
|
set_rule(e, lambda state: millennium_mall_big(state, player, limit, glitched))
|
|
for e in multiworld.get_region(Stages.MMO2, player).entrances:
|
|
set_rule(e, lambda state: millennium_mall_oldhead_race(state, player))
|
|
for e in multiworld.get_region(Stages.MM3, player).entrances:
|
|
set_rule(e, lambda state: millennium_mall_theater(state, player, limit))
|
|
|
|
# pyramid island
|
|
for e in multiworld.get_region(Stages.PI1, player).entrances:
|
|
set_rule(e, lambda state: pyramid_island_entrance(state, player))
|
|
for e in multiworld.get_region(Stages.PI2, player).entrances:
|
|
set_rule(e, lambda state: pyramid_island_gate(state, player))
|
|
for e in multiworld.get_region(Stages.PIO, player).entrances:
|
|
set_rule(e, lambda state: pyramid_island_oldhead(state, player))
|
|
for e in multiworld.get_region(Stages.PI3, player).entrances:
|
|
set_rule(e, lambda state: pyramid_island_upper_half(state, player, limit, glitched))
|
|
for e in multiworld.get_region(Stages.PI4, player).entrances:
|
|
set_rule(e, lambda state: pyramid_island_top(state, player))
|
|
|
|
# mataan
|
|
for e in multiworld.get_region(Stages.MA1, player).entrances:
|
|
set_rule(e, lambda state: mataan_entrance(state, player))
|
|
for e in multiworld.get_region(Stages.MA2, player).entrances:
|
|
set_rule(e, lambda state: mataan_smoke_wall(state, player))
|
|
for e in multiworld.get_region(Stages.MA3, player).entrances:
|
|
set_rule(e, lambda state: mataan_deep_city(state, player, limit, glitched))
|
|
for e in multiworld.get_region(Stages.MAO, player).entrances:
|
|
set_rule(e, lambda state: mataan_oldhead(state, player))
|
|
for e in multiworld.get_region(Stages.MA4, player).entrances:
|
|
set_rule(e, lambda state: mataan_smoke_wall2(state, player, limit, glitched))
|
|
for e in multiworld.get_region(Stages.MA5, player).entrances:
|
|
set_rule(e, lambda state: mataan_deepest(state, player, limit, glitched))
|
|
|
|
# locations
|
|
# hideout
|
|
set_rule(multiworld.get_location("Hideout: BMX garage skateboard", player),
|
|
lambda state: bmx(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Hideout: Unlock phone app", player),
|
|
lambda state: current_chapter(state, player, 2))
|
|
set_rule(multiworld.get_location("Hideout: Vinyl joins the crew", player),
|
|
lambda state: current_chapter(state, player, 4))
|
|
set_rule(multiworld.get_location("Hideout: Solace joins the crew", player),
|
|
lambda state: current_chapter(state, player, 5))
|
|
|
|
# versum hill
|
|
set_rule(multiworld.get_location("Versum Hill: Wallrunning challenge reward", player),
|
|
lambda state: versum_hill_challenge1(state, player))
|
|
set_rule(multiworld.get_location("Versum Hill: Manual challenge reward", player),
|
|
lambda state: versum_hill_challenge2(state, player))
|
|
set_rule(multiworld.get_location("Versum Hill: Corner challenge reward", player),
|
|
lambda state: versum_hill_challenge3(state, player))
|
|
set_rule(multiworld.get_location("Versum Hill: BMX gate outfit", player),
|
|
lambda state: bmx(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Versum Hill: Glass floor skates", player),
|
|
lambda state: inline_skates(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Versum Hill: Basketball court shortcut CD", player),
|
|
lambda state: current_chapter(state, player, 2))
|
|
set_rule(multiworld.get_location("Versum Hill: Rave joins the crew", player),
|
|
lambda state: versum_hill_rave(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Versum Hill: Frank joins the crew", player),
|
|
lambda state: current_chapter(state, player, 2))
|
|
set_rule(multiworld.get_location("Versum Hill: Rietveld joins the crew", player),
|
|
lambda state: versum_hill_rietveld(state, player, limit, glitched))
|
|
if photos:
|
|
set_rule(multiworld.get_location("Versum Hill: Big Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Versum Hill: Trash Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Versum Hill: Fruit stand Polo", player),
|
|
lambda state: camera(state, player))
|
|
|
|
# millennium square
|
|
if photos:
|
|
set_rule(multiworld.get_location("Millennium Square: Half pipe Polo", player),
|
|
lambda state: camera(state, player))
|
|
|
|
# brink terminal
|
|
set_rule(multiworld.get_location("Brink Terminal: Upside grind challenge reward", player),
|
|
lambda state: brink_terminal_challenge1(state, player))
|
|
set_rule(multiworld.get_location("Brink Terminal: Manual challenge reward", player),
|
|
lambda state: brink_terminal_challenge2(state, player))
|
|
set_rule(multiworld.get_location("Brink Terminal: Score challenge reward", player),
|
|
lambda state: brink_terminal_challenge3(state, player))
|
|
set_rule(multiworld.get_location("Brink Terminal: BMX gate graffiti", player),
|
|
lambda state: bmx(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Brink Terminal: Mesh's skateboard", player),
|
|
lambda state: brink_terminal_mesh(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Brink Terminal: Rooftop glass CD", player),
|
|
lambda state: inline_skates(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Brink Terminal: Mesh joins the crew", player),
|
|
lambda state: brink_terminal_mesh(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Brink Terminal: Eclipse joins the crew", player),
|
|
lambda state: current_chapter(state, player, 3))
|
|
if photos:
|
|
set_rule(multiworld.get_location("Brink Terminal: Behind glass Polo", player),
|
|
lambda state: camera(state, player))
|
|
|
|
# millennium mall
|
|
set_rule(multiworld.get_location("Millennium Mall: Glass cylinder CD", player),
|
|
lambda state: inline_skates(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Millennium Mall: Trick challenge reward", player),
|
|
lambda state: millennium_mall_challenge1(state, player))
|
|
set_rule(multiworld.get_location("Millennium Mall: Slide challenge reward", player),
|
|
lambda state: millennium_mall_challenge2(state, player))
|
|
set_rule(multiworld.get_location("Millennium Mall: Fish challenge reward", player),
|
|
lambda state: millennium_mall_challenge3(state, player))
|
|
set_rule(multiworld.get_location("Millennium Mall: Score challenge reward", player),
|
|
lambda state: millennium_mall_challenge4(state, player))
|
|
set_rule(multiworld.get_location("Millennium Mall: Atrium BMX gate BMX", player),
|
|
lambda state: bmx(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Millennium Mall: Shine joins the crew", player),
|
|
lambda state: current_chapter(state, player, 4))
|
|
set_rule(multiworld.get_location("Millennium Mall: DOT.EXE joins the crew", player),
|
|
lambda state: current_chapter(state, player, 4))
|
|
|
|
# pyramid island
|
|
set_rule(multiworld.get_location("Pyramid Island: BMX gate BMX", player),
|
|
lambda state: bmx(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Pyramid Island: Score challenge reward", player),
|
|
lambda state: pyramid_island_challenge1(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Score challenge 2 reward", player),
|
|
lambda state: pyramid_island_challenge2(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Quarter pipe challenge reward", player),
|
|
lambda state: pyramid_island_challenge3(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Shortcut glass CD", player),
|
|
lambda state: inline_skates(state, player, movestyle))
|
|
set_rule(multiworld.get_location("Pyramid Island: Maze outfit", player),
|
|
lambda state: skateboard(state, player, movestyle))
|
|
if not glitched:
|
|
add_rule(multiworld.get_location("Pyramid Island: Rise joins the crew", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Devil Theory joins the crew", player),
|
|
lambda state: current_chapter(state, player, 5))
|
|
if photos:
|
|
set_rule(multiworld.get_location("Pyramid Island: Polo pile 1", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Polo pile 2", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Polo pile 3", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Polo pile 4", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Maze glass Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Maze classroom Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Maze vent Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Big maze Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Maze desk Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Pyramid Island: Maze forklift Polo", player),
|
|
lambda state: camera(state, player))
|
|
|
|
# mataan
|
|
set_rule(multiworld.get_location("Mataan: Race challenge reward", player),
|
|
lambda state: mataan_challenge1(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Mataan: Wallrunning challenge reward", player),
|
|
lambda state: mataan_challenge2(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Mataan: Score challenge reward", player),
|
|
lambda state: mataan_challenge3(state, player))
|
|
if photos:
|
|
set_rule(multiworld.get_location("Mataan: Trash Polo", player),
|
|
lambda state: camera(state, player))
|
|
set_rule(multiworld.get_location("Mataan: Shopping Polo", player),
|
|
lambda state: camera(state, player))
|
|
|
|
# events
|
|
set_rule(multiworld.get_location("Versum Hill: Complete Chapter 1", player),
|
|
lambda state: versum_hill_crew_battle(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Brink Terminal: Complete Chapter 2", player),
|
|
lambda state: brink_terminal_crew_battle(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Millennium Mall: Complete Chapter 3", player),
|
|
lambda state: millennium_mall_crew_battle(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Pyramid Island: Complete Chapter 4", player),
|
|
lambda state: pyramid_island_crew_battle(state, player, limit, glitched))
|
|
set_rule(multiworld.get_location("Defeat Faux", player),
|
|
lambda state: mataan_faux(state, player, limit, glitched))
|
|
|
|
if extra:
|
|
add_rule(multiworld.get_location("Defeat Faux", player),
|
|
lambda state: rep(state, player, 1000))
|
|
|
|
# graffiti spots
|
|
spots: int = 0
|
|
while spots < 385:
|
|
spots += 5
|
|
set_rule(multiworld.get_location(f"Tagged {spots} Graffiti Spots", player),
|
|
lambda state, spot_count=spots: graffiti_spots(state, player, movestyle, limit, glitched, spot_count))
|
|
|
|
set_rule(multiworld.get_location("Tagged 389 Graffiti Spots", player),
|
|
lambda state: graffiti_spots(state, player, movestyle, limit, glitched, 389))
|