mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00

The static class with the "disable forced good item" field is gone. Now, certain tests that want to check for specific access progression can run a method that removes the forced good item and adds it back to the pool. Tests that don't care about this will collect the forced good item like normal. This should prevent the intermittent fill failures on complex doors unit tests, since the forced good item should provide enough locations to fill in.
133 lines
5.1 KiB
Python
133 lines
5.1 KiB
Python
"""
|
|
Archipelago init file for Lingo
|
|
"""
|
|
from logging import warning
|
|
|
|
from BaseClasses import Item, ItemClassification, Tutorial
|
|
from worlds.AutoWorld import WebWorld, World
|
|
from .items import ALL_ITEM_TABLE, LingoItem
|
|
from .locations import ALL_LOCATION_TABLE
|
|
from .options import LingoOptions
|
|
from .player_logic import LingoPlayerLogic
|
|
from .regions import create_regions
|
|
from .static_logic import Room, RoomEntrance
|
|
|
|
|
|
class LingoWebWorld(WebWorld):
|
|
theme = "grass"
|
|
tutorials = [Tutorial(
|
|
"Multiworld Setup Guide",
|
|
"A guide to playing Lingo with Archipelago.",
|
|
"English",
|
|
"setup_en.md",
|
|
"setup/en",
|
|
["hatkirby"]
|
|
)]
|
|
|
|
|
|
class LingoWorld(World):
|
|
"""
|
|
Lingo is a first person indie puzzle game in the vein of The Witness. You find yourself in a mazelike, non-Euclidean
|
|
world filled with 800 word puzzles that use a variety of different mechanics.
|
|
"""
|
|
game = "Lingo"
|
|
web = LingoWebWorld()
|
|
|
|
base_id = 444400
|
|
topology_present = True
|
|
data_version = 1
|
|
|
|
options_dataclass = LingoOptions
|
|
options: LingoOptions
|
|
|
|
item_name_to_id = {
|
|
name: data.code for name, data in ALL_ITEM_TABLE.items()
|
|
}
|
|
location_name_to_id = {
|
|
name: data.code for name, data in ALL_LOCATION_TABLE.items()
|
|
}
|
|
|
|
player_logic: LingoPlayerLogic
|
|
|
|
def generate_early(self):
|
|
if not (self.options.shuffle_doors or self.options.shuffle_colors):
|
|
if self.multiworld.players == 1:
|
|
warning(f"{self.multiworld.get_player_name(self.player)}'s Lingo world doesn't have any progression"
|
|
f" items. Please turn on Door Shuffle or Color Shuffle if that doesn't seem right.")
|
|
else:
|
|
raise Exception(f"{self.multiworld.get_player_name(self.player)}'s Lingo world doesn't have any"
|
|
f" progression items. Please turn on Door Shuffle or Color Shuffle.")
|
|
|
|
self.player_logic = LingoPlayerLogic(self)
|
|
|
|
def create_regions(self):
|
|
create_regions(self, self.player_logic)
|
|
|
|
def create_items(self):
|
|
pool = [self.create_item(name) for name in self.player_logic.real_items]
|
|
|
|
if self.player_logic.forced_good_item != "":
|
|
new_item = self.create_item(self.player_logic.forced_good_item)
|
|
location_obj = self.multiworld.get_location("Second Room - Good Luck", self.player)
|
|
location_obj.place_locked_item(new_item)
|
|
|
|
item_difference = len(self.player_logic.real_locations) - len(pool)
|
|
if item_difference:
|
|
trap_percentage = self.options.trap_percentage
|
|
traps = int(item_difference * trap_percentage / 100.0)
|
|
non_traps = item_difference - traps
|
|
|
|
if non_traps:
|
|
skip_percentage = self.options.puzzle_skip_percentage
|
|
skips = int(non_traps * skip_percentage / 100.0)
|
|
non_skips = non_traps - skips
|
|
|
|
filler_list = [":)", "The Feeling of Being Lost", "Wanderlust", "Empty White Hallways"]
|
|
for i in range(0, non_skips):
|
|
pool.append(self.create_item(filler_list[i % len(filler_list)]))
|
|
|
|
for i in range(0, skips):
|
|
pool.append(self.create_item("Puzzle Skip"))
|
|
|
|
if traps:
|
|
traps_list = ["Slowness Trap", "Iceland Trap", "Atbash Trap"]
|
|
|
|
for i in range(0, traps):
|
|
pool.append(self.create_item(traps_list[i % len(traps_list)]))
|
|
|
|
self.multiworld.itempool += pool
|
|
|
|
def create_item(self, name: str) -> Item:
|
|
item = ALL_ITEM_TABLE[name]
|
|
|
|
classification = item.classification
|
|
if hasattr(self, "options") and self.options.shuffle_paintings and len(item.painting_ids) > 0\
|
|
and len(item.door_ids) == 0 and all(painting_id not in self.player_logic.painting_mapping
|
|
for painting_id in item.painting_ids)\
|
|
and "pilgrim_painting2" not in item.painting_ids:
|
|
# If this is a "door" that just moves one or more paintings, and painting shuffle is on and those paintings
|
|
# go nowhere, then this item should not be progression. The Pilgrim Room painting is special and needs to be
|
|
# excluded from this.
|
|
classification = ItemClassification.filler
|
|
|
|
return LingoItem(name, classification, item.code, self.player)
|
|
|
|
def set_rules(self):
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
|
|
|
|
def fill_slot_data(self):
|
|
slot_options = [
|
|
"death_link", "victory_condition", "shuffle_colors", "shuffle_doors", "shuffle_paintings", "shuffle_panels",
|
|
"mastery_achievements", "level_2_requirement", "location_checks", "early_color_hallways"
|
|
]
|
|
|
|
slot_data = {
|
|
"seed": self.random.randint(0, 1000000),
|
|
**self.options.as_dict(*slot_options),
|
|
}
|
|
|
|
if self.options.shuffle_paintings:
|
|
slot_data["painting_entrance_to_exit"] = self.player_logic.painting_mapping
|
|
|
|
return slot_data
|