Files
Grinch-AP/worlds/celeste64/__init__.py

211 lines
9.5 KiB
Python
Raw Normal View History

from copy import deepcopy
from typing import Dict, List, Tuple
from BaseClasses import ItemClassification, Location, Region, Tutorial
from worlds.AutoWorld import WebWorld, World
from .Items import Celeste64Item, unlockable_item_data_table, move_item_data_table, item_data_table,\
checkpoint_item_data_table, item_table
from .Locations import Celeste64Location, strawberry_location_data_table, friend_location_data_table,\
sign_location_data_table, car_location_data_table, checkpoint_location_data_table,\
location_table
from .Names import ItemName, LocationName
from .Options import Celeste64Options, celeste_64_option_groups, resolve_options
class Celeste64WebWorld(WebWorld):
theme = "ice"
setup_en = Tutorial(
tutorial_name="Start Guide",
description="A guide to playing Celeste 64 in Archipelago.",
language="English",
file_name="guide_en.md",
link="guide/en",
authors=["PoryGone"]
)
tutorials = [setup_en]
option_groups = celeste_64_option_groups
class Celeste64World(World):
"""Relive the magic of Celeste Mountain alongside Madeline in this small, heartfelt 3D platformer.
Created in a week(ish) by the Celeste team to celebrate the games sixth anniversary 🍓"""
# Class Data
game = "Celeste 64"
web = Celeste64WebWorld()
options_dataclass = Celeste64Options
options: Celeste64Options
location_name_to_id = location_table
item_name_to_id = item_table
# Instance Data
strawberries_required: int
active_logic_mapping: Dict[str, List[List[str]]]
active_region_logic_mapping: Dict[Tuple[str], List[List[str]]]
madeline_one_dash_hair_color: int
madeline_two_dash_hair_color: int
madeline_no_dash_hair_color: int
madeline_feather_hair_color: int
def generate_early(self) -> None:
resolve_options(self)
def create_item(self, name: str) -> Celeste64Item:
# Only make required amount of strawberries be Progression
if getattr(self, "strawberries_required", None) and name == ItemName.strawberry:
classification: ItemClassification = ItemClassification.filler
self.prog_strawberries = getattr(self, "prog_strawberries", 0)
if self.prog_strawberries < self.strawberries_required:
classification = ItemClassification.progression_skip_balancing
self.prog_strawberries += 1
return Celeste64Item(name, classification, item_data_table[name].code, self.player)
else:
return Celeste64Item(name, item_data_table[name].type, item_data_table[name].code, self.player)
def create_items(self) -> None:
item_pool: List[Celeste64Item] = []
location_count: int = 30
if self.options.friendsanity:
location_count += 9
if self.options.signsanity:
location_count += 5
if self.options.carsanity:
location_count += 2
item_pool += [self.create_item(name)
for name in unlockable_item_data_table.keys()
if name not in self.options.start_inventory]
chosen_start_item: str = ""
if self.options.move_shuffle:
if self.options.logic_difficulty == "standard":
possible_unwalls: List[str] = [name for name in move_item_data_table.keys()
if name != ItemName.skid_jump]
if self.options.checkpointsanity:
possible_unwalls.extend([name for name in checkpoint_item_data_table.keys()
if name != ItemName.checkpoint_1 and name != ItemName.checkpoint_10])
# If the start_inventory already includes a move or checkpoint, don't worry about giving it one
if not [item for item in possible_unwalls if item in self.multiworld.precollected_items[self.player]]:
chosen_start_item = self.random.choice(possible_unwalls)
if self.options.carsanity:
intro_car_loc: Location = self.multiworld.get_location(LocationName.car_1, self.player)
intro_car_loc.place_locked_item(self.create_item(chosen_start_item))
location_count -= 1
else:
self.multiworld.push_precollected(self.create_item(chosen_start_item))
item_pool += [self.create_item(name)
for name in move_item_data_table.keys()
if name not in self.multiworld.precollected_items[self.player]
and name != chosen_start_item]
else:
for start_move in move_item_data_table.keys():
self.multiworld.push_precollected(self.create_item(start_move))
if self.options.checkpointsanity:
location_count += 9
goal_checkpoint_loc: Location = self.multiworld.get_location(LocationName.checkpoint_10, self.player)
goal_checkpoint_loc.place_locked_item(self.create_item(ItemName.checkpoint_10))
item_pool += [self.create_item(name)
for name in checkpoint_item_data_table.keys()
if name not in self.multiworld.precollected_items[self.player]
and name != ItemName.checkpoint_10
and name != chosen_start_item]
else:
for item_name in checkpoint_item_data_table.keys():
checkpoint_loc: Location = self.multiworld.get_location(item_name, self.player)
checkpoint_loc.place_locked_item(self.create_item(item_name))
real_total_strawberries: int = min(self.options.total_strawberries.value, location_count - len(item_pool))
self.strawberries_required = int(real_total_strawberries * (self.options.strawberries_required_percentage / 100))
item_pool += [self.create_item(ItemName.strawberry) for _ in range(real_total_strawberries)]
filler_item_count: int = location_count - len(item_pool)
item_pool += [self.create_item(ItemName.raspberry) for _ in range(filler_item_count)]
self.multiworld.itempool += item_pool
def create_regions(self) -> None:
from .Regions import region_data_table
# Create regions.
for region_name in region_data_table.keys():
region = Region(region_name, self.player, self.multiworld)
self.multiworld.regions.append(region)
# Create locations.
for region_name, region_data in region_data_table.items():
region = self.multiworld.get_region(region_name, self.player)
region.add_locations({
location_name: location_data.address for location_name, location_data in strawberry_location_data_table.items()
if location_data.region == region_name
}, Celeste64Location)
if self.options.friendsanity:
region.add_locations({
location_name: location_data.address for location_name, location_data in friend_location_data_table.items()
if location_data.region == region_name
}, Celeste64Location)
if self.options.signsanity:
region.add_locations({
location_name: location_data.address for location_name, location_data in sign_location_data_table.items()
if location_data.region == region_name
}, Celeste64Location)
if self.options.carsanity:
region.add_locations({
location_name: location_data.address for location_name, location_data in car_location_data_table.items()
if location_data.region == region_name
}, Celeste64Location)
region.add_locations({
location_name: location_data.address for location_name, location_data in checkpoint_location_data_table.items()
if location_data.region == region_name
}, Celeste64Location)
from .Rules import connect_region
connect_region(self, region, region_data_table[region_name].connecting_regions)
# Have to do this here because of other games using State in a way that's bad
from .Rules import set_rules
set_rules(self)
def get_filler_item_name(self) -> str:
return ItemName.raspberry
def fill_slot_data(self):
return {
"death_link": self.options.death_link.value,
"death_link_amnesty": self.options.death_link_amnesty.value,
"strawberries_required": self.strawberries_required,
"move_shuffle": self.options.move_shuffle.value,
"friendsanity": self.options.friendsanity.value,
"signsanity": self.options.signsanity.value,
"carsanity": self.options.carsanity.value,
"checkpointsanity": self.options.checkpointsanity.value,
"madeline_one_dash_hair_color": self.madeline_one_dash_hair_color,
"madeline_two_dash_hair_color": self.madeline_two_dash_hair_color,
"madeline_no_dash_hair_color": self.madeline_no_dash_hair_color,
"madeline_feather_hair_color": self.madeline_feather_hair_color,
"badeline_chaser_source": self.options.badeline_chaser_source.value,
"badeline_chaser_frequency": self.options.badeline_chaser_frequency.value,
"badeline_chaser_speed": self.options.badeline_chaser_speed.value,
}