mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Almost all of the events have been eradicated, which significantly improves both generation speed and playthrough calculation. Previously, checking for access to a location involved checking for access to each panel in the location, as well as recursively checking for access to any panels required by those panels. This potentially performed the same check multiple times. The access requirements for locations are now calculated and flattened in generate_early, so that the access function can directly check for the required rooms, doors, and colors. These flattened access requirements are also used for Entrance checking, and register_indirect_condition is used to make sure that can_reach(Region) is safe to use. The Mastery and Level 2 rules now just run a bunch of access rules and count the number of them that succeed, instead of relying on event items. Finally: the Level 2 panel hunt is now enabled even when Level 2 is not the victory condition, as I feel that generation is fast enough now for that to be acceptable.
122 lines
4.4 KiB
Python
122 lines
4.4 KiB
Python
"""
|
|
Archipelago init file for Lingo
|
|
"""
|
|
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
|
|
from .testing import LingoTestOptions
|
|
|
|
|
|
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):
|
|
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):
|
|
# 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.
|
|
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
|