From c456854263be17264aeb8446986bc401d3921f33 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sat, 13 Sep 2025 11:34:49 -0400 Subject: Added anti collectable traps --- apworld/__init__.py | 17 ++++++++++++++++- apworld/items.py | 2 ++ apworld/options.py | 11 ++++++++++- apworld/static_logic.py | 12 +++++++++++- data/ids.yaml | 26 ++++++++++++++++++++++++++ data/metadata.txtpb | 27 +++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 3 deletions(-) diff --git a/apworld/__init__.py b/apworld/__init__.py index 54f870f..8b2e42e 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py @@ -3,7 +3,7 @@ Archipelago init file for Lingo 2 """ from BaseClasses import ItemClassification, Item, Tutorial from worlds.AutoWorld import WebWorld, World -from .items import Lingo2Item +from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS from .options import Lingo2Options from .player_logic import Lingo2PlayerLogic from .regions import create_regions @@ -62,6 +62,20 @@ class Lingo2World(World): 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())) @@ -69,6 +83,7 @@ class Lingo2World(World): 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) diff --git a/apworld/items.py b/apworld/items.py index 32568a3..28158c3 100644 --- a/apworld/items.py +++ b/apworld/items.py @@ -27,3 +27,5 @@ SYMBOL_ITEMS: dict[data_pb2.PuzzleSymbol, str] = { data_pb2.PuzzleSymbol.LINGO: "Lingo Symbol", data_pb2.PuzzleSymbol.QUESTION: "Question Symbol", } + +ANTI_COLLECTABLE_TRAPS: list[str] = [f"Anti {letter}" for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"] diff --git a/apworld/options.py b/apworld/options.py index 4f0b32a..52d2034 100644 --- a/apworld/options.py +++ b/apworld/options.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle +from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range class ShuffleDoors(DefaultOnToggle): @@ -126,6 +126,14 @@ class VictoryCondition(Choice): option_white_ending = 12 +class TrapPercentage(Range): + """Replaces junk items with traps, at the specified rate.""" + display_name = "Trap Percentage" + range_start = 0 + range_end = 100 + default = 0 + + @dataclass class Lingo2Options(PerGameCommonOptions): shuffle_doors: ShuffleDoors @@ -137,3 +145,4 @@ class Lingo2Options(PerGameCommonOptions): cyan_door_behavior: CyanDoorBehavior daedalus_roof_access: DaedalusRoofAccess victory_condition: VictoryCondition + trap_percentage: TrapPercentage diff --git a/apworld/static_logic.py b/apworld/static_logic.py index 1017ec7..2700601 100644 --- a/apworld/static_logic.py +++ b/apworld/static_logic.py @@ -1,5 +1,5 @@ from .generated import data_pb2 as data_pb2 -from .items import SYMBOL_ITEMS +from .items import SYMBOL_ITEMS, ANTI_COLLECTABLE_TRAPS import pkgutil class Lingo2StaticLogic: @@ -12,11 +12,14 @@ class Lingo2StaticLogic: item_name_groups: dict[str, list[str]] location_name_groups: dict[str, list[str]] + letter_weights: dict[str, int] + def __init__(self): self.item_id_to_name = {} self.location_id_to_name = {} self.item_name_groups = {} self.location_name_groups = {} + self.letter_weights = {} file = pkgutil.get_data(__name__, "generated/data.binpb") self.objects = data_pb2.AllObjects() @@ -68,9 +71,16 @@ class Lingo2StaticLogic: for symbol_name in SYMBOL_ITEMS.values(): self.item_id_to_name[self.objects.special_ids[symbol_name]] = symbol_name + for trap_name in ANTI_COLLECTABLE_TRAPS: + self.item_id_to_name[self.objects.special_ids[trap_name]] = trap_name + self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()} self.location_name_to_id = {name: ap_id for ap_id, name in self.location_id_to_name.items()} + for panel in self.objects.panels: + for letter in panel.answer.upper(): + self.letter_weights[letter] = self.letter_weights.get(letter, 0) + 1 + def get_door_item_name(self, door: data_pb2.Door) -> str: return f"{self.get_map_object_map_name(door)} - {door.name}" diff --git a/data/ids.yaml b/data/ids.yaml index 2eba46a..2358b67 100644 --- a/data/ids.yaml +++ b/data/ids.yaml @@ -3842,6 +3842,32 @@ special: A Job Well Done: 1160 Age Symbol: 2791 Anagram Symbol: 2792 + Anti A: 2814 + Anti B: 2815 + Anti C: 2816 + Anti D: 2817 + Anti E: 2818 + Anti F: 2819 + Anti G: 2820 + Anti H: 2821 + Anti I: 2822 + Anti J: 2823 + Anti K: 2824 + Anti L: 2825 + Anti M: 2826 + Anti N: 2827 + Anti O: 2828 + Anti P: 2829 + Anti Q: 2830 + Anti R: 2831 + Anti S: 2832 + Anti T: 2833 + Anti U: 2834 + Anti V: 2835 + Anti W: 2836 + Anti X: 2837 + Anti Y: 2838 + Anti Z: 2839 Boxes Symbol: 2793 Cross Symbol: 2794 Eval Symbol: 2795 diff --git a/data/metadata.txtpb b/data/metadata.txtpb index 57255e6..8b53601 100644 --- a/data/metadata.txtpb +++ b/data/metadata.txtpb @@ -21,3 +21,30 @@ special_names: "Stars Symbol" special_names: "Sun Symbol" special_names: "Sweet Symbol" special_names: "Zero Symbol" +# Anti collectable traps +special_names: "Anti A" +special_names: "Anti B" +special_names: "Anti C" +special_names: "Anti D" +special_names: "Anti E" +special_names: "Anti F" +special_names: "Anti G" +special_names: "Anti H" +special_names: "Anti I" +special_names: "Anti J" +special_names: "Anti K" +special_names: "Anti L" +special_names: "Anti M" +special_names: "Anti N" +special_names: "Anti O" +special_names: "Anti P" +special_names: "Anti Q" +special_names: "Anti R" +special_names: "Anti S" +special_names: "Anti T" +special_names: "Anti U" +special_names: "Anti V" +special_names: "Anti W" +special_names: "Anti X" +special_names: "Anti Y" +special_names: "Anti Z" -- cgit 1.4.1