Skip to content

Commit 4a249c9

Browse files
authored
Overhauled Celeste APWorld (ArchipelagoMW#2)
* Made static data distinctly separate from instantiated data and placed this in data.py * Created classes representing distinct ProgressionSystems to better handle different world generations and placed this in progression.py * Added handling to prevent goal level restrictions being set higher than physically completable * Removed items/locations after the goal level from generation * Removed items that don't contribute to progression (items from the goal level, and strawberries past the goal level requirement) as progression items. These are now just "useful" instead. * Strawberry items are now deduplicated, and now share the name "Strawberry".
1 parent 885c19d commit 4a249c9

10 files changed

+2615
-281
lines changed

worlds/celeste/__init__.py

+53-49
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44

55
from BaseClasses import Item, ItemClassification, MultiWorld, Tutorial
66
from worlds.AutoWorld import WebWorld, World
7-
8-
from .items import (
7+
from worlds.celeste.data import (
8+
BaseData,
99
CelesteItem,
10-
CelesteItemFactory,
1110
CelesteItemType,
12-
CelesteLocationFactory,
11+
CelesteLevel,
12+
CelesteLocation,
13+
CelesteSide,
14+
)
15+
from worlds.celeste.progression import BaseProgression, DefaultProgression
16+
17+
from .options import (
18+
ProgressionSystemEnum,
19+
VictoryConditionEnum,
20+
celeste_options,
21+
get_option_value,
1322
)
14-
from .options import VictoryConditionEnum, celeste_options, get_option_value
15-
from .regions import CelesteRegionFactory
1623

1724

1825
class CelesteWebWorld(WebWorld):
@@ -40,74 +47,71 @@ class CelesteWorld(World):
4047
topology_present = True
4148
web = CelesteWebWorld()
4249

43-
victory_condition: VictoryConditionEnum
44-
completion_level: int
50+
item_name_to_id = BaseData.item_name_to_id()
51+
location_name_to_id = BaseData.location_name_to_id()
4552

46-
item_factory: CelesteItemFactory
47-
location_factory: CelesteLocationFactory
48-
region_factory: CelesteRegionFactory
49-
50-
item_name_to_id = CelesteItemFactory.get_name_to_id()
51-
location_name_to_id = CelesteLocationFactory.get_name_to_id()
53+
progression_system: BaseProgression
5254

5355
required_client_version = (0, 4, 3)
5456

5557
def __init__(self, multiworld: MultiWorld, player: int):
5658
super().__init__(multiworld, player)
57-
self.completion_level = 10
58-
self.item_factory = CelesteItemFactory(self)
59-
self.location_factory = CelesteLocationFactory()
60-
self.region_factory = CelesteRegionFactory()
59+
self.progression_system = None
6160

6261
def generate_early(self) -> None:
63-
self.victory_condition = VictoryConditionEnum(
64-
get_option_value(self.multiworld, self.player, "victory_condition")
65-
)
66-
if self.victory_condition == VictoryConditionEnum.CHAPTER_9_FAREWELL:
67-
self.completion_level = 10
68-
elif self.victory_condition == VictoryConditionEnum.CHAPTER_8_CORE:
69-
self.completion_level = 9
70-
elif self.victory_condition == VictoryConditionEnum.CHAPTER_7_SUMMIT:
71-
self.completion_level = 7
62+
options = {x: get_option_value(self.multiworld, self.player, x) for x in celeste_options}
63+
64+
if options["progression_system"] == ProgressionSystemEnum.DEFAULT_PROGRESSION.value:
65+
self.progression_system = DefaultProgression(options)
7266

73-
def create_item(self, name: str) -> Item:
74-
return self.item_factory.create_item(name)
67+
def create_item(self, name: str) -> CelesteItem:
68+
uuid = self.item_name_to_id[name]
69+
70+
if self.progression_system is not None:
71+
item_dict = self.progression_system.items_dict(self.player, self.multiworld)
72+
if uuid in item_dict:
73+
return item_dict[uuid].copy()
74+
75+
raw_item = BaseData.get_item(uuid)
76+
return CelesteItem(
77+
raw_item[3], ItemClassification.filler, uuid, self.player, raw_item[0], raw_item[1], raw_item[2]
78+
)
7579

7680
def create_regions(self):
77-
self.region_factory.activate(self)
81+
regions = self.progression_system.regions(self.player, self.multiworld)
82+
self.multiworld.regions.extend(regions)
7883

7984
def create_items(self):
80-
item_table = self.item_factory.get_table(self)
85+
item_table = self.progression_system.items(self.player, self.multiworld)
8186

8287
for item in item_table:
83-
if item.level > self.completion_level:
84-
continue
85-
if item.level == self.completion_level and item.side == 0 and item.item_type == CelesteItemType.COMPLETION:
86-
continue
87-
self.multiworld.itempool.append(deepcopy(item))
88+
if item.name != self.progression_system.victory_item_name():
89+
self.multiworld.itempool.append(item.copy())
8890

8991
self.item_name_groups = {
9092
"cassettes": [item.name for item in item_table if item.item_type == CelesteItemType.CASSETTE],
91-
"completions": [item.name for item in item_table if item.item_type == CelesteItemType.COMPLETION],
92-
"gemhearts": [item.name for item in item_table if item.item_type == CelesteItemType.GEMHEART],
93-
"strawberries": [item.name for item in item_table if item.item_type == CelesteItemType.STRAWBERRY],
93+
"levels": [item.name for item in item_table if item.item_type == CelesteItemType.COMPLETION],
94+
"hearts": [item.name for item in item_table if item.item_type == CelesteItemType.GEMHEART],
9495
}
9596

9697
def generate_basic(self) -> None:
98+
victory_name = self.progression_system.victory_item_name()
99+
self.multiworld.get_location(victory_name, self.player).place_locked_item(self.create_item(victory_name))
97100
self.multiworld.completion_condition[self.player] = lambda state: state.has(
98-
f"Level {self.completion_level} A-Side Complete", self.player
101+
self.progression_system.victory_item_name(), self.player
99102
)
100103

101-
def pre_fill(self):
102-
item_table = self.item_factory.get_table(self)
103-
for item in item_table:
104-
if item.level > self.completion_level or (
105-
item.level == self.completion_level and item.side == 0 and item.item_type == CelesteItemType.COMPLETION
106-
):
107-
self.multiworld.get_location(item.name, self.player).place_locked_item(deepcopy(item))
108-
109104
def fill_slot_data(self):
110105
slot_data = {}
111106
for option_name in celeste_options:
112-
slot_data[option_name] = get_option_value(self.multiworld, self.player, option_name)
107+
current_option = self.progression_system.get_option(option_name)
108+
initial_option = get_option_value(self.multiworld, self.player, option_name)
109+
if current_option != initial_option:
110+
print(
111+
f"[WARNING] [CELESTE] Invalid options value {option_name} = {initial_option}.",
112+
f"Overridden as {current_option}.",
113+
)
114+
getattr(self.options, option_name).value = current_option
115+
slot_data[option_name] = current_option
116+
113117
return slot_data

0 commit comments

Comments
 (0)