about summary refs log tree commit diff stats
path: root/data/maps/the_darkroom/rooms/Second Room.txtpb
blob: 221989527ff330af9690eab0254aeadc58fad685 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
name: "Second Room"
panel_display_name: "Second Room"
panels {
  name: "BISON"
  path: "Panels/Room 2/panel_1"
  clue: "bison"
  answer: "bison"
  symbols: PLANET
}
panels {
  name: "FISH"
  path: "Panels/Room 2/panel_2"
  clue: "fish"
  answer: "fish"
  symbols: PLANET
}
panels {
  name: "SHEEP"
  path: "Panels/Room 2/panel_3"
  clue: "sheep"
  answer: "sheep"
  symbols: PLANET
  required_door { name: "Double Letter Panel Blockers" }
}
panels {
  name: "KOI"
  path: "Panels/Room 2/panel_4"
  clue: "koi"
  answer: "koi"
  symbols: PLANET
}
panels {
  name: "TUNA"
  path: "Panels/Room 2/panel_5"
  clue: "tuna"
  answer: "tuna"
  symbols: PLANET
}
ports {
  name: "ENTRY"
  display_name: "Second Room Entrance"
  path: "Components/Warps/worldport3"
  destination { x: 38 y: 0 z: 10 }
  rotation: 0
}
Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
"""
Archipelago init file for Lingo 2
"""
from typing import ClassVar

from BaseClasses import ItemClassification, Item, Tutorial
from settings import Group, UserFilePath
from worlds.AutoWorld import WebWorld, World
from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS
from .options import Lingo2Options
from .player_logic import Lingo2PlayerLogic
from .regions import create_regions, shuffle_entrances, connect_ports_from_ut
from .static_logic import Lingo2StaticLogic
from .version import APWORLD_VERSION
from ..LauncherComponents import Component, Type, components, launch as launch_component


class Lingo2WebWorld(WebWorld):
    rich_text_options_doc = True
    theme = "grass"
    tutorials = [Tutorial(
        "Multiworld Setup Guide",
        "A guide to playing Lingo 2 with Archipelago.",
        "English",
        "en_Lingo_2.md",
        "setup/en",
        ["hatkirby"]
    )]


class Lingo2Settings(Group):
    class ExecutableFile(UserFilePath):
        """Path to the Lingo 2 executable"""
        is_exe = True

    exe_file: ExecutableFile = ExecutableFile()


class Lingo2World(World):
    """
    Lingo 2 is a first person indie puzzle game where you solve word puzzles in a labyrinthe world. Compared to its
    predecessor, Lingo 2 has new mechanics, more areas, and a unique progression system where you have to unlock letters
    before using them in puzzle solutions.
    """
    game = "Lingo 2"
    web = Lingo2WebWorld()

    settings: ClassVar[Lingo2Settings]
    settings_key = "lingo2_options"

    topology_present = True

    options_dataclass = Lingo2Options
    options: Lingo2Options

    static_logic = Lingo2StaticLogic()
    item_name_to_id = static_logic.item_name_to_id
    location_name_to_id = static_logic.location_name_to_id
    item_name_groups = static_logic.item_name_groups
    location_name_groups = static_logic.location_name_groups

    player_logic: Lingo2PlayerLogic

    port_pairings: dict[int, int]

    def generate_early(self):
        self.player_logic = Lingo2PlayerLogic(self)
        self.port_pairings = {}

    def create_regions(self):
        create_regions(self)

    def connect_entrances(self):
        if self.options.shuffle_worldports:
            if hasattr(self.multiworld, "re_gen_passthrough") and "Lingo 2" in self.multiworld.re_gen_passthrough:
                slot_value = self.multiworld.re_gen_passthrough["Lingo 2"]["port_pairings"]
                self.port_pairings = {int(fp): int(tp) for fp, tp in slot_value.items()}

                connect_ports_from_ut(self.port_pairings, self)
            else:
                shuffle_entrances(self)

        from Utils import visualize_regions

        visualize_regions(self.multiworld.get_region("Menu", self.player), "my_world.puml")

    def create_items(self):
        pool = [self.create_item(name) for name in self.player_logic.real_items]

        total_locations = sum(len(locs) for locs in self.player_logic.locations_by_room.values())

        item_difference = total_locations - len(pool)

        if self.options.trap_percentage > 0:
            num_traps = int(item_difference * self.options.trap_percentage / 100)
            item_difference = item_difference - num_traps

            trap_names = []
            trap_weights = []
            for letter_name, weight in self.static_logic.letter_weights.items():
                trap_names.append(f"Anti {letter_name}")
                trap_weights.append(weight)

            bad_letters = self.random.choices(trap_names, weights=trap_weights, k=num_traps)
            pool += [self.create_item(trap_name) for trap_name in bad_letters]

        for i in range(0, item_difference):
            pool.append(self.create_item(self.get_filler_item_name()))

        self.multiworld.itempool += pool

    def create_item(self, name: str) -> Item:
        return Lingo2Item(name, ItemClassification.filler if name == self.get_filler_item_name() else
                                ItemClassification.trap if name in ANTI_COLLECTABLE_TRAPS else
                                ItemClassification.progression,
                          self.item_name_to_id.get(name), 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 = [
            "cyan_door_behavior",
            "daedalus_roof_access",
            "keyholder_sanity",
            "shuffle_control_center_colors",
            "shuffle_doors",
            "shuffle_gallery_paintings",
            "shuffle_letters",
            "shuffle_symbols",
            "shuffle_worldports",
            "strict_cyan_ending",
            "strict_purple_ending",
            "victory_condition",
        ]

        slot_data: dict[str, object] = {
            **self.options.as_dict(*slot_options),
            "version": [self.static_logic.get_data_version(), APWORLD_VERSION],
        }

        if self.options.shuffle_worldports:
            slot_data["port_pairings"] = self.port_pairings

        return slot_data

    def get_filler_item_name(self) -> str:
        return "A Job Well Done"

    # for the universal tracker, doesn't get called in standard gen
    # docs: https://github.com/FarisTheAncient/Archipelago/blob/tracker/worlds/tracker/docs/re-gen-passthrough.md
    @staticmethod
    def interpret_slot_data(slot_data: dict[str, object]) -> dict[str, object]:
        # returning slot_data so it regens, giving it back in multiworld.re_gen_passthrough
        # we are using re_gen_passthrough over modifying the world here due to complexities with ER
        return slot_data


def launch_client(*args):
    from .context import client_main
    launch_component(client_main, name="Lingo2Client", args=args)


component = Component("Lingo 2 Client", component_type=Type.CLIENT, func=launch_client,
                      description="Open Lingo 2.", supports_uri=True, game_name="Lingo 2")
components.append(component)