forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
266 lines
21 KiB
Python
266 lines
21 KiB
Python
import settings
|
|
from typing import Dict, Any
|
|
from BaseClasses import MultiWorld, Region, Item, Tutorial
|
|
from worlds.AutoWorld import World, WebWorld
|
|
from Utils import visualize_regions
|
|
from worlds.generic.Rules import set_rule
|
|
from .items import (SonicFrontiersItem, SonicFrontiersItemData, item_list, kronos_amount, ares_amount, chaos_amount, ouranos_amount, fillers)
|
|
from .locations import (kronosRegion, SonicFrontiersAdvancement, aresRegion, chaosRegion, ouranosRegion, kronosMemoryTokenSet,
|
|
aresMemoryTokenSet, chaosMemoryTokenSet, ouranosMemoryTokenSet, kronosPurpleSet, kronosKocoSet, aresKocoSet,
|
|
aresPurpleSet, chaosKocoSet, chaosPurpleSet, ouranosKocoSet, ouranosPurpleSet, kronosNewKocoSet,
|
|
kronosMusicSet, aresMusicSet, aresNewKocoSet, chaosMusicSet, chaosNewKocoSet, ouranosMusicSet, ouranosNewKocoSet, all_items)
|
|
from .options import SonicFrontiersOptions
|
|
|
|
class SonicFrontiersWebWorld(WebWorld):
|
|
setup_en = Tutorial(
|
|
"Multiworld Setup Guide",
|
|
"A guide to playing Sonic Frontiers with Archipelago.",
|
|
"English",
|
|
"setup_en.md",
|
|
"setup/en",
|
|
["custom"]
|
|
)
|
|
|
|
tutorials = [setup_en]
|
|
|
|
class SonicFrontiersWorld(World):
|
|
game = "Sonic Frontiers"
|
|
topology_present = False
|
|
web = SonicFrontiersWebWorld()
|
|
item_name_to_id = {name: data.id for name, data in item_list.items()}
|
|
location_name_to_id = {name: data.id for name, data in all_items.items()}
|
|
|
|
options_dataclass = SonicFrontiersOptions
|
|
options: SonicFrontiersOptions
|
|
def create_kronos_island(self) -> Region:
|
|
return
|
|
def create_ares_island(self) -> Region:
|
|
return
|
|
|
|
def create_regions(self) -> None:
|
|
menu_region = Region("Menu", self.player, self.multiworld)
|
|
|
|
kronos_region = Region("Kronos", self.player, self.multiworld)
|
|
kronos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, kronos_region)for loc_name, loc_data in kronosRegion.items()]
|
|
|
|
if(self.options.memory_token_sanity):
|
|
kronos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, kronos_region)for loc_name, loc_data in kronosMemoryTokenSet.items()]
|
|
if(self.options.challenge_kocos):
|
|
kronos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, kronos_region)for loc_name, loc_data in kronosNewKocoSet.items()]
|
|
if(self.options.music_notes):
|
|
kronos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, kronos_region)for loc_name, loc_data in kronosMusicSet.items()]
|
|
if(self.options.purple_coin_sanity):
|
|
kronos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, kronos_region)for loc_name, loc_data in kronosPurpleSet.items()]
|
|
if(self.options.koco_sanity):
|
|
kronos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, kronos_region)for loc_name, loc_data in kronosKocoSet.items()]
|
|
menu_region.connect(kronos_region)
|
|
self.multiworld.regions += [menu_region, kronos_region]
|
|
|
|
if(self.options.goal > 0):
|
|
ares_region = Region("Ares", self.player, self.multiworld)
|
|
ares_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ares_region)for loc_name, loc_data in aresRegion.items()]
|
|
|
|
if(self.options.memory_token_sanity):
|
|
ares_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ares_region)for loc_name, loc_data in aresMemoryTokenSet.items()]
|
|
if(self.options.challenge_kocos):
|
|
ares_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ares_region)for loc_name, loc_data in aresNewKocoSet.items()]
|
|
if(self.options.music_notes):
|
|
ares_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ares_region)for loc_name, loc_data in aresMusicSet.items()]
|
|
if(self.options.purple_coin_sanity):
|
|
ares_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ares_region)for loc_name, loc_data in aresPurpleSet.items()]
|
|
if(self.options.koco_sanity):
|
|
ares_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ares_region)for loc_name, loc_data in aresKocoSet.items()]
|
|
self.multiworld.regions += [ares_region]
|
|
kronos_region.add_exits({"Ares": "Ares Entrance"})
|
|
|
|
if(self.options.goal > 1):
|
|
chaos_region = Region("Chaos", self.player, self.multiworld)
|
|
chaos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, chaos_region)for loc_name, loc_data in chaosRegion.items()]
|
|
if(self.options.memory_token_sanity):
|
|
chaos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, chaos_region)for loc_name, loc_data in chaosMemoryTokenSet.items()]
|
|
if(self.options.challenge_kocos):
|
|
chaos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, chaos_region)for loc_name, loc_data in chaosNewKocoSet.items()]
|
|
if(self.options.music_notes):
|
|
chaos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, chaos_region)for loc_name, loc_data in chaosMusicSet.items()]
|
|
if(self.options.purple_coin_sanity):
|
|
chaos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, chaos_region)for loc_name, loc_data in chaosPurpleSet.items()]
|
|
if(self.options.koco_sanity):
|
|
chaos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, chaos_region)for loc_name, loc_data in chaosKocoSet.items()]
|
|
self.multiworld.regions += [chaos_region]
|
|
ares_region.add_exits({"Chaos": "Chaos Entrance"})
|
|
|
|
if(self.options.goal > 2):
|
|
ouranos_region = Region("Ouranos", self.player, self.multiworld)
|
|
ouranos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ouranos_region)for loc_name, loc_data in ouranosRegion.items()]
|
|
if(self.options.memory_token_sanity):
|
|
ouranos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ouranos_region)for loc_name, loc_data in ouranosMemoryTokenSet.items()]
|
|
if(self.options.challenge_kocos):
|
|
ouranos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ouranos_region)for loc_name, loc_data in ouranosNewKocoSet.items()]
|
|
if(self.options.music_notes):
|
|
ouranos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ouranos_region)for loc_name, loc_data in ouranosMusicSet.items()]
|
|
if(self.options.purple_coin_sanity):
|
|
ouranos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ouranos_region)for loc_name, loc_data in ouranosPurpleSet.items()]
|
|
if(self.options.koco_sanity):
|
|
ouranos_region.locations += [SonicFrontiersAdvancement(self.player, loc_name, loc_data.id, ouranos_region)for loc_name, loc_data in ouranosKocoSet.items()]
|
|
self.multiworld.regions += [ouranos_region]
|
|
chaos_region.add_exits({"Ouranos": "Ouranos Entrance"})
|
|
|
|
if(self.options.goal == 0):
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach_location("Defeat Giganto", self.player)
|
|
if(self.options.goal == 1):
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach_location("Defeat Wyvern", self.player)
|
|
if(self.options.goal == 2):
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach_location("Defeat Knight", self.player)
|
|
if(self.options.goal == 3):
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach_location("Defeat Ouranos", self.player)
|
|
|
|
|
|
|
|
|
|
|
|
def set_rules(self) -> None:
|
|
|
|
for i in range(7):
|
|
set_rule(self.multiworld.get_location((f"1-2 All Missions ({i+1})"), self.player), lambda state: state.has("1-2 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"1-3 All Missions ({i+1})"), self.player), lambda state: state.has("1-3 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"1-4 All Missions ({i+1})"), self.player), lambda state: state.has("1-4 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"1-5 All Missions ({i+1})"), self.player), lambda state: state.has("1-5 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"1-6 All Missions ({i+1})"), self.player), lambda state: state.has("1-6 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"1-7 All Missions ({i+1})"), self.player), lambda state: state.has("1-7 Unlocked", self.player, 1))
|
|
if(self.options.goal > 0):
|
|
set_rule(self.multiworld.get_location((f"2-1 All Missions ({i+1})"), self.player), lambda state: state.has("2-1 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"2-2 All Missions ({i+1})"), self.player), lambda state: state.has("2-2 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"2-3 All Missions ({i+1})"), self.player), lambda state: state.has("2-3 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"2-4 All Missions ({i+1})"), self.player), lambda state: state.has("2-4 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"2-5 All Missions ({i+1})"), self.player), lambda state: state.has("2-5 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"2-6 All Missions ({i+1})"), self.player), lambda state: state.has("2-6 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"2-7 All Missions ({i+1})"), self.player), lambda state: state.has("2-7 Unlocked", self.player, 1))
|
|
if(self.options.goal > 1):
|
|
set_rule(self.multiworld.get_location((f"3-1 All Missions ({i+1})"), self.player), lambda state: state.has("3-1 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"3-2 All Missions ({i+1})"), self.player), lambda state: state.has("3-2 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"3-3 All Missions ({i+1})"), self.player), lambda state: state.has("3-3 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"3-4 All Missions ({i+1})"), self.player), lambda state: state.has("3-4 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"3-5 All Missions ({i+1})"), self.player), lambda state: state.has("3-5 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"3-6 All Missions ({i+1})"), self.player), lambda state: state.has("3-6 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"3-7 All Missions ({i+1})"), self.player), lambda state: state.has("3-7 Unlocked", self.player, 1)
|
|
and state.can_reach_location("Chaos Cyan Emerald", self.player))
|
|
if(self.options.goal > 2):
|
|
set_rule(self.multiworld.get_location((f"4-1 All Missions ({i+1})"), self.player), lambda state: state.has("4-1 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-2 All Missions ({i+1})"), self.player), lambda state: state.has("4-2 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-3 All Missions ({i+1})"), self.player), lambda state: state.has("4-3 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-4 All Missions ({i+1})"), self.player), lambda state: state.has("4-4 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-5 All Missions ({i+1})"), self.player), lambda state: state.has("4-5 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-6 All Missions ({i+1})"), self.player), lambda state: state.has("4-6 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-7 All Missions ({i+1})"), self.player), lambda state: state.has("4-7 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-8 All Missions ({i+1})"), self.player), lambda state: state.has("4-8 Unlocked", self.player, 1))
|
|
set_rule(self.multiworld.get_location((f"4-9 All Missions ({i+1})"), self.player), lambda state: state.has("4-9 Unlocked", self.player, 1))
|
|
|
|
set_rule(self.multiworld.get_location(("Kronos Blue Emerald"), self.player), lambda state: state.has("Kronos Vault Key", self.player, 2))
|
|
set_rule(self.multiworld.get_location(("Kronos Red Emerald"), self.player), lambda state: state.has("Kronos Vault Key", self.player, 5))
|
|
|
|
set_rule(self.multiworld.get_location(("Kronos Green Emerald"), self.player), lambda state: state.has("Kronos Vault Key", self.player, 5)
|
|
and state.has("Kronos Memory Treasure", self.player, 3) and state.has("Progressive Chaos Emerald", self.player, 2))
|
|
|
|
set_rule(self.multiworld.get_location(("Kronos Yellow Emerald"), self.player), lambda state: state.has("Kronos Vault Key", self.player, 13))
|
|
|
|
set_rule(self.multiworld.get_location(("Kronos Cyan Emerald"), self.player), lambda state: state.has("Kronos Vault Key", self.player, 13)
|
|
and state.has("Kronos Memory Treasure", self.player, 6) and state.has("Progressive Chaos Emerald", self.player, 4))
|
|
|
|
set_rule(self.multiworld.get_location(("Kronos White Emerald"), self.player), lambda state: state.has("Kronos Vault Key", self.player, 20))
|
|
if(self.options.goal > 0):
|
|
set_rule(self.multiworld.get_location(("Ares Blue Emerald"), self.player), lambda state: state.has("Ares Vault Key", self.player, 7))
|
|
set_rule(self.multiworld.get_location(("Ares Red Emerald"), self.player), lambda state: state.has("Ares Vault Key", self.player, 14))
|
|
set_rule(self.multiworld.get_location(("Ares Green Emerald"), self.player), lambda state: state.has("Ares Vault Key", self.player, 14) and state.has("Progressive Chaos Emerald", self.player, 8))
|
|
set_rule(self.multiworld.get_location(("Ares Yellow Emerald"), self.player), lambda state: state.has("Ares Vault Key", self.player, 20))
|
|
set_rule(self.multiworld.get_location(("Ares Cyan Emerald"), self.player), lambda state: state.has("Ares Vault Key", self.player, 20) and state.has("Progressive Chaos Emerald", self.player, 10))
|
|
set_rule(self.multiworld.get_location(("Ares White Emerald"), self.player), lambda state: state.has("Ares Vault Key", self.player, 24))
|
|
|
|
if(self.options.goal > 1):
|
|
set_rule(self.multiworld.get_location(("Chaos Blue Emerald"), self.player), lambda state: state.has("Chaos Vault Key", self.player, 7))
|
|
set_rule(self.multiworld.get_location(("Chaos Red Emerald"), self.player), lambda state: state.has("Chaos Vault Key", self.player, 14))
|
|
set_rule(self.multiworld.get_location(("Chaos Green Emerald"), self.player), lambda state: state.has("Chaos Vault Key", self.player, 14) and state.has("Progressive Chaos Emerald", self.player, 14))
|
|
set_rule(self.multiworld.get_location(("Chaos Yellow Emerald"), self.player), lambda state: state.has("Chaos Vault Key", self.player, 20))
|
|
set_rule(self.multiworld.get_location(("Chaos Cyan Emerald"), self.player), lambda state: state.has("Chaos Vault Key", self.player, 20) and state.has("Progressive Chaos Emerald", self.player, 16))
|
|
set_rule(self.multiworld.get_location(("Chaos White Emerald"), self.player), lambda state: state.has("Chaos Vault Key", self.player, 25))
|
|
if(self.options.goal > 2):
|
|
set_rule(self.multiworld.get_location(("Ouranos Blue Emerald"), self.player), lambda state: state.has("Ouranos Vault Key", self.player, 3))
|
|
set_rule(self.multiworld.get_location(("Ouranos Red Emerald"), self.player), lambda state: state.has("Ouranos Vault Key", self.player, 9))
|
|
set_rule(self.multiworld.get_location(("Ouranos Green Emerald"), self.player), lambda state: state.has("Ouranos Vault Key", self.player, 16))
|
|
set_rule(self.multiworld.get_location(("Ouranos Yellow Emerald"), self.player), lambda state: state.has("Ouranos Vault Key", self.player, 23))
|
|
set_rule(self.multiworld.get_location(("Ouranos Cyan Emerald"), self.player), lambda state: state.has("Ouranos Vault Key", self.player, 30))
|
|
set_rule(self.multiworld.get_location(("Ouranos White Emerald"), self.player), lambda state: state.has("Ouranos Vault Key", self.player, 33))
|
|
if(self.options.goal > 0):
|
|
set_rule(self.multiworld.get_entrance("Ares Entrance", self.player), lambda state: state.has("Progressive Chaos Emerald", self.player, 6)
|
|
and state.has("Kronos Memory Treasure", self.player, 9) and state.has("Kronos Vault Key", self.player, 20)
|
|
and state.has("Stomp Attack", self.player) and state.has("Parry", self.player))
|
|
|
|
if(self.options.goal > 1):
|
|
set_rule(self.multiworld.get_entrance("Chaos Entrance", self.player),
|
|
lambda state: state.has("Progressive Chaos Emerald", self.player, 12) and state.has("Ares Memory Treasure", self.player, 32) and state.has("Ares Vault Key", self.player, 24))
|
|
|
|
if(self.options.goal > 2):
|
|
set_rule(self.multiworld.get_entrance("Ouranos Entrance", self.player),
|
|
lambda state: state.has("Progressive Chaos Emerald", self.player, 18) and state.has("Chaos Memory Treasure", self.player, 20) and state.has("Chaos Vault Key", self.player, 25))
|
|
|
|
if(self.options.goal == 0):
|
|
set_rule(self.multiworld.get_location("Defeat Giganto", self.player), lambda state: state.has("Progressive Chaos Emerald", self.player, 6)
|
|
and state.has("Kronos Memory Treasure", self.player, 9) and state.has("Kronos Vault Key", self.player, 20)
|
|
and state.has("Stomp Attack", self.player) and state.has("Parry", self.player))
|
|
if(self.options.goal == 1):
|
|
set_rule(self.multiworld.get_location("Defeat Wyvern", self.player), lambda state: state.has("Progressive Chaos Emerald", self.player, 12)
|
|
and state.has("Ares Memory Treasure", self.player, 32) and state.has("Ares Vault Key", self.player, 24))
|
|
if(self.options.goal == 2):
|
|
set_rule(self.multiworld.get_location("Defeat Knight", self.player),
|
|
lambda state: state.has("Progressive Chaos Emerald", self.player, 18) and state.has("Chaos Memory Treasure", self.player, 20) and state.has("Chaos Vault Key", self.player, 25))
|
|
if(self.options.goal == 3):
|
|
set_rule(self.multiworld.get_location("Defeat Supreme", self.player),
|
|
lambda state: state.has("Progressive Chaos Emerald", self.player, 24) and state.has("Ouranos Memory Treasure", self.player, 24) and state.has("Ouranos Vault Key", self.player, 33))
|
|
|
|
def create_items(self) -> None:
|
|
numItems = 0
|
|
for name, quantity in kronos_amount.items():
|
|
for i in range(quantity):
|
|
item = self.create_item(name)
|
|
self.multiworld.itempool.append(item)
|
|
numItems += 1
|
|
if self.options.goal > 0:
|
|
for name, quantity in ares_amount.items():
|
|
for i in range(quantity):
|
|
item = self.create_item(name)
|
|
self.multiworld.itempool.append(item)
|
|
numItems += 1
|
|
if self.options.goal > 1:
|
|
for name, quantity in chaos_amount.items():
|
|
for i in range(quantity):
|
|
item = self.create_item(name)
|
|
self.multiworld.itempool.append(item)
|
|
numItems += 1
|
|
if self.options.goal > 2:
|
|
for name, quantity in ouranos_amount.items():
|
|
for i in range(quantity):
|
|
item = self.create_item(name)
|
|
self.multiworld.itempool.append(item)
|
|
numItems += 1
|
|
filler = len(self.multiworld.get_locations(self.player)) - numItems
|
|
for _ in range(filler):
|
|
name = self.random.choices(list(fillers.keys()), weights = list(fillers.values()))[0]
|
|
item = self.create_item(name)
|
|
self.multiworld.itempool.append(item)
|
|
def create_item(self, name: str) -> Item:
|
|
item_data = item_list[name]
|
|
item = SonicFrontiersItem(name, item_data.item_class, item_data.id, self.player)
|
|
return item
|
|
def fill_slot_data(self) -> Dict[str, Any]:
|
|
return {
|
|
"death_link": self.options.death_link.value,
|
|
"goal": self.options.goal.value,
|
|
"memory_token_sanity": self.options.memory_token_sanity.value,
|
|
"cyberspace_times": self.options.cyberspace_times.value,
|
|
"music_notes": self.options.music_notes.value,
|
|
"challenge_kocos": self.options.challenge_kocos.value,
|
|
"purple_coin_sanity": self.options.purple_coin_sanity.value,
|
|
"koco_sanity": self.options.koco_sanity.value,
|
|
}
|
|
|
|
|