Skip to content

Commit 885c19d

Browse files
authored
Merge pull request ArchipelagoMW#1 from doshyw/doshyw/add-extra-completion-conditions
Added extra completion conditions and fixed bugs
2 parents d77ba7b + b347800 commit 885c19d

File tree

4 files changed

+67
-27
lines changed

4 files changed

+67
-27
lines changed

worlds/celeste/__init__.py

+33-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pylint: disable=missing-class-docstring, missing-module-docstring, fixme
22
from copy import deepcopy
3+
from typing import List
34

45
from BaseClasses import Item, ItemClassification, MultiWorld, Tutorial
56
from worlds.AutoWorld import WebWorld, World
@@ -10,7 +11,7 @@
1011
CelesteItemType,
1112
CelesteLocationFactory,
1213
)
13-
from .options import celeste_options, get_option_value
14+
from .options import VictoryConditionEnum, celeste_options, get_option_value
1415
from .regions import CelesteRegionFactory
1516

1617

@@ -39,19 +40,36 @@ class CelesteWorld(World):
3940
topology_present = True
4041
web = CelesteWebWorld()
4142

43+
victory_condition: VictoryConditionEnum
44+
completion_level: int
45+
4246
item_factory: CelesteItemFactory
4347
location_factory: CelesteLocationFactory
4448
region_factory: CelesteRegionFactory
4549

4650
item_name_to_id = CelesteItemFactory.get_name_to_id()
4751
location_name_to_id = CelesteLocationFactory.get_name_to_id()
4852

53+
required_client_version = (0, 4, 3)
54+
4955
def __init__(self, multiworld: MultiWorld, player: int):
5056
super().__init__(multiworld, player)
57+
self.completion_level = 10
5158
self.item_factory = CelesteItemFactory(self)
5259
self.location_factory = CelesteLocationFactory()
5360
self.region_factory = CelesteRegionFactory()
5461

62+
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
72+
5573
def create_item(self, name: str) -> Item:
5674
return self.item_factory.create_item(name)
5775

@@ -62,6 +80,10 @@ def create_items(self):
6280
item_table = self.item_factory.get_table(self)
6381

6482
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
6587
self.multiworld.itempool.append(deepcopy(item))
6688

6789
self.item_name_groups = {
@@ -72,10 +94,17 @@ def create_items(self):
7294
}
7395

7496
def generate_basic(self) -> None:
75-
self.multiworld.get_location("Level 10 A-Side Complete", self.player).place_locked_item(
76-
CelesteItem("Victory", ItemClassification.progression, None, self.player, CelesteItemType.COMPLETION, 10, 0)
97+
self.multiworld.completion_condition[self.player] = lambda state: state.has(
98+
f"Level {self.completion_level} A-Side Complete", self.player
7799
)
78-
self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
100+
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))
79108

80109
def fill_slot_data(self):
81110
slot_data = {}

worlds/celeste/docs/en_Celeste.md

+5-10
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,17 @@ greyed out cannot be pressed, blocking access to Chapters/Sides that are not yet
3535

3636
## What is the goal for a Celeste world?
3737

38-
At the moment, the only available goal for a Celeste world is to complete "Chapter 10: Farewell". This is done by
39-
receiving one of the three `Level 9 X-Side Completion` items from the multi-world, and then accessing and playing
40-
through Chapter 10.
38+
The following goals can be selected for a Celeste world:
39+
- Completing "Chapter 7: The Summit" A-Side.
40+
- Completing "Chapter 8: Core" A-Side.
41+
- Completing "Chapter 9: Farewell" A-Side.
4142

4243
There is a set of options that allow you to configure how many items of different types need to have been collected
43-
prior to passing through the Crystal Heart Gate in Chapter 10. It defaults to matching the original story progression
44-
(i.e., requiring 15 different Crystal Hearts and nothing else), but can be modified to make it either easier or harder
45-
to pass through the gate. The required number of Cassettes, Crystal Hearts, Level Completions, and Strawberries can all
46-
be configured.
44+
prior to accessing the goal level. The required number of Cassettes, Crystal Hearts, Level Completions, and Strawberries can all be configured.
4745

4846
The following goals are currently being planned for addition:
49-
- Completing "Chapter 7: The Summit" A-Side.
50-
- Completing "Chapter 8: Core" A-Side.
5147
- Completing some set of Sides (e.g., all A-Sides, all A and B-Sides, etc) for all Chapters in-game.
5248

53-
5449
The following configuration options are also being planned:
5550
- Toggle for whether the end-game item checks are based on receiving items from the multi-world or completing location
5651
checks.

worlds/celeste/items.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pathlib import Path
77
from typing import Any, Dict, List, Optional
88

9-
from BaseClasses import Item, ItemClassification, Location, LocationProgressType, Region
9+
from BaseClasses import Item, ItemClassification, Location, Region
1010
from worlds.AutoWorld import World
1111

1212
from .options import get_option_value
@@ -91,17 +91,15 @@ def __init__(
9191

9292
@staticmethod
9393
def create_from_pandas(world: World, row: Dict[str, Any]) -> "CelesteLocation":
94-
code = row["id"] if row["level"] < 10 else None
95-
location = CelesteLocation(world.player, row["level"], row["side"], f"{row['name']}", code)
94+
location = CelesteLocation(world.player, row["level"], row["side"], f"{row['name']}", row["id"])
9695
if location.level == 9:
9796
if location.side == 0:
9897
location.access_rule = lambda state: state.has_group("gemhearts", world.player, 4)
9998
elif location.side == 1:
10099
location.access_rule = lambda state: state.has_group("gemhearts", world.player, 15)
101100
elif location.side == 2:
102101
location.access_rule = lambda state: state.has_group("gemhearts", world.player, 23)
103-
if location.level == 10:
104-
location.progress_type = LocationProgressType.EXCLUDED
102+
if location.level == world.completion_level:
105103
location.access_rule = (
106104
lambda state: state.has_group(
107105
"gemhearts", world.player, get_option_value(world.multiworld, world.player, "hearts_required")
@@ -132,15 +130,15 @@ def __init__(self, world: World):
132130
def _load_table(self, world: World, force: bool = False) -> None:
133131
if force or not self._loaded or self._world != world:
134132
json_rows = get_json_data(PATH_ITEMS)
135-
self._table = [CelesteItem.create_from_pandas(world, row) for row in json_rows if row["level"] < 10]
133+
self._table = [CelesteItem.create_from_pandas(world, row) for row in json_rows]
136134
self._map = {item.name: item for item in self._table}
137135
self._world = world
138136
self._loaded = True
139137

140138
@staticmethod
141139
def get_name_to_id() -> Dict[str, int]:
142140
json_rows = get_json_data(PATH_ITEMS)
143-
return {f"{row['name']}": row["id"] for row in json_rows if row["level"] < 10}
141+
return {f"{row['name']}": row["id"] for row in json_rows}
144142

145143
def create_item(self, item: str) -> CelesteItem:
146144
self._load_table(self._world)

worlds/celeste/options.py

+24-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# pylint: disable=missing-class-docstring, missing-module-docstring, fixme, unused-import
22

3+
from enum import Enum
34
from typing import Dict, Union
45

56
from BaseClasses import MultiWorld
6-
from Options import DefaultOnToggle, Range, Toggle
7+
from Options import Choice, DefaultOnToggle, Range, Toggle
78

89

910
class BerriesRequired(Range):
10-
"""Number of Strawberries required to pass through the Crystal Heart Gate in Chapter 9: Farewell."""
11+
"""Number of Strawberries required to access the goal level."""
1112

1213
display_name = "Strawberry Requirement"
1314
range_start = 0
@@ -16,7 +17,7 @@ class BerriesRequired(Range):
1617

1718

1819
class CassettesRequired(Range):
19-
"""Number of Cassettes required to pass through the Crystal Heart Gate in Chapter 9: Farewell."""
20+
"""Number of Cassettes required to access the goal level."""
2021

2122
display_name = "Cassette Requirement"
2223
range_start = 0
@@ -25,28 +26,45 @@ class CassettesRequired(Range):
2526

2627

2728
class HeartsRequired(Range):
28-
"""Number of Crystal Hearts required to pass through the Crystal Heart Gate in Chapter 9: Farewell."""
29+
"""Number of Crystal Hearts required to access the goal level."""
2930

3031
display_name = "Crystal Heart Requirement"
3132
range_start = 0
3233
range_end = 24
33-
default = 15
34+
default = 0
3435

3536

3637
class LevelsRequired(Range):
37-
"""Number of Level Completions required to pass through the Crystal Heart Gate in Chapter 9: Farewell."""
38+
"""Number of Level Completions required to access the goal level."""
3839

3940
display_name = "Level Completion Requirement"
4041
range_start = 0
4142
range_end = 24
4243
default = 0
4344

4445

46+
class VictoryConditionEnum(Enum):
47+
CHAPTER_7_SUMMIT = 0
48+
CHAPTER_8_CORE = 1
49+
CHAPTER_9_FAREWELL = 2
50+
51+
52+
class VictoryCondition(Choice):
53+
"""Selects the Chapter whose Completion is the Victory Condition for the World."""
54+
55+
display_name = "Victory Condition"
56+
option_chapter_7_summit = VictoryConditionEnum.CHAPTER_7_SUMMIT.value
57+
option_chapter_8_core = VictoryConditionEnum.CHAPTER_8_CORE.value
58+
option_chapter_9_farewell = VictoryConditionEnum.CHAPTER_9_FAREWELL.value
59+
default = VictoryConditionEnum.CHAPTER_7_SUMMIT.value
60+
61+
4562
celeste_options: Dict[str, type] = {
4663
"berries_required": BerriesRequired,
4764
"cassettes_required": CassettesRequired,
4865
"hearts_required": HeartsRequired,
4966
"levels_required": LevelsRequired,
67+
"victory_condition": VictoryCondition,
5068
}
5169

5270

0 commit comments

Comments
 (0)