diff options
| -rw-r--r-- | apworld/__init__.py | 17 | ||||
| -rw-r--r-- | apworld/items.py | 2 | ||||
| -rw-r--r-- | apworld/options.py | 11 | ||||
| -rw-r--r-- | apworld/static_logic.py | 12 | ||||
| -rw-r--r-- | data/ids.yaml | 26 | ||||
| -rw-r--r-- | 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 | |||
| 3 | """ | 3 | """ |
| 4 | from BaseClasses import ItemClassification, Item, Tutorial | 4 | from BaseClasses import ItemClassification, Item, Tutorial |
| 5 | from worlds.AutoWorld import WebWorld, World | 5 | from worlds.AutoWorld import WebWorld, World |
| 6 | from .items import Lingo2Item | 6 | from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS |
| 7 | from .options import Lingo2Options | 7 | from .options import Lingo2Options |
| 8 | from .player_logic import Lingo2PlayerLogic | 8 | from .player_logic import Lingo2PlayerLogic |
| 9 | from .regions import create_regions | 9 | from .regions import create_regions |
| @@ -62,6 +62,20 @@ class Lingo2World(World): | |||
| 62 | total_locations = sum(len(locs) for locs in self.player_logic.locations_by_room.values()) | 62 | total_locations = sum(len(locs) for locs in self.player_logic.locations_by_room.values()) |
| 63 | 63 | ||
| 64 | item_difference = total_locations - len(pool) | 64 | item_difference = total_locations - len(pool) |
| 65 | |||
| 66 | if self.options.trap_percentage > 0: | ||
| 67 | num_traps = int(item_difference * self.options.trap_percentage / 100) | ||
| 68 | item_difference = item_difference - num_traps | ||
| 69 | |||
| 70 | trap_names = [] | ||
| 71 | trap_weights = [] | ||
| 72 | for letter_name, weight in self.static_logic.letter_weights.items(): | ||
| 73 | trap_names.append(f"Anti {letter_name}") | ||
| 74 | trap_weights.append(weight) | ||
| 75 | |||
| 76 | bad_letters = self.random.choices(trap_names, weights=trap_weights, k=num_traps) | ||
| 77 | pool += [self.create_item(trap_name) for trap_name in bad_letters] | ||
| 78 | |||
| 65 | for i in range(0, item_difference): | 79 | for i in range(0, item_difference): |
| 66 | pool.append(self.create_item(self.get_filler_item_name())) | 80 | pool.append(self.create_item(self.get_filler_item_name())) |
| 67 | 81 | ||
| @@ -69,6 +83,7 @@ class Lingo2World(World): | |||
| 69 | 83 | ||
| 70 | def create_item(self, name: str) -> Item: | 84 | def create_item(self, name: str) -> Item: |
| 71 | return Lingo2Item(name, ItemClassification.filler if name == self.get_filler_item_name() else | 85 | return Lingo2Item(name, ItemClassification.filler if name == self.get_filler_item_name() else |
| 86 | ItemClassification.trap if name in ANTI_COLLECTABLE_TRAPS else | ||
| 72 | ItemClassification.progression, | 87 | ItemClassification.progression, |
| 73 | self.item_name_to_id.get(name), self.player) | 88 | self.item_name_to_id.get(name), self.player) |
| 74 | 89 | ||
| 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] = { | |||
| 27 | data_pb2.PuzzleSymbol.LINGO: "Lingo Symbol", | 27 | data_pb2.PuzzleSymbol.LINGO: "Lingo Symbol", |
| 28 | data_pb2.PuzzleSymbol.QUESTION: "Question Symbol", | 28 | data_pb2.PuzzleSymbol.QUESTION: "Question Symbol", |
| 29 | } | 29 | } |
| 30 | |||
| 31 | 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 @@ | |||
| 1 | from dataclasses import dataclass | 1 | from dataclasses import dataclass |
| 2 | 2 | ||
| 3 | from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle | 3 | from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | class ShuffleDoors(DefaultOnToggle): | 6 | class ShuffleDoors(DefaultOnToggle): |
| @@ -126,6 +126,14 @@ class VictoryCondition(Choice): | |||
| 126 | option_white_ending = 12 | 126 | option_white_ending = 12 |
| 127 | 127 | ||
| 128 | 128 | ||
| 129 | class TrapPercentage(Range): | ||
| 130 | """Replaces junk items with traps, at the specified rate.""" | ||
| 131 | display_name = "Trap Percentage" | ||
| 132 | range_start = 0 | ||
| 133 | range_end = 100 | ||
| 134 | default = 0 | ||
| 135 | |||
| 136 | |||
| 129 | @dataclass | 137 | @dataclass |
| 130 | class Lingo2Options(PerGameCommonOptions): | 138 | class Lingo2Options(PerGameCommonOptions): |
| 131 | shuffle_doors: ShuffleDoors | 139 | shuffle_doors: ShuffleDoors |
| @@ -137,3 +145,4 @@ class Lingo2Options(PerGameCommonOptions): | |||
| 137 | cyan_door_behavior: CyanDoorBehavior | 145 | cyan_door_behavior: CyanDoorBehavior |
| 138 | daedalus_roof_access: DaedalusRoofAccess | 146 | daedalus_roof_access: DaedalusRoofAccess |
| 139 | victory_condition: VictoryCondition | 147 | victory_condition: VictoryCondition |
| 148 | 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 @@ | |||
| 1 | from .generated import data_pb2 as data_pb2 | 1 | from .generated import data_pb2 as data_pb2 |
| 2 | from .items import SYMBOL_ITEMS | 2 | from .items import SYMBOL_ITEMS, ANTI_COLLECTABLE_TRAPS |
| 3 | import pkgutil | 3 | import pkgutil |
| 4 | 4 | ||
| 5 | class Lingo2StaticLogic: | 5 | class Lingo2StaticLogic: |
| @@ -12,11 +12,14 @@ class Lingo2StaticLogic: | |||
| 12 | item_name_groups: dict[str, list[str]] | 12 | item_name_groups: dict[str, list[str]] |
| 13 | location_name_groups: dict[str, list[str]] | 13 | location_name_groups: dict[str, list[str]] |
| 14 | 14 | ||
| 15 | letter_weights: dict[str, int] | ||
| 16 | |||
| 15 | def __init__(self): | 17 | def __init__(self): |
| 16 | self.item_id_to_name = {} | 18 | self.item_id_to_name = {} |
| 17 | self.location_id_to_name = {} | 19 | self.location_id_to_name = {} |
| 18 | self.item_name_groups = {} | 20 | self.item_name_groups = {} |
| 19 | self.location_name_groups = {} | 21 | self.location_name_groups = {} |
| 22 | self.letter_weights = {} | ||
| 20 | 23 | ||
| 21 | file = pkgutil.get_data(__name__, "generated/data.binpb") | 24 | file = pkgutil.get_data(__name__, "generated/data.binpb") |
| 22 | self.objects = data_pb2.AllObjects() | 25 | self.objects = data_pb2.AllObjects() |
| @@ -68,9 +71,16 @@ class Lingo2StaticLogic: | |||
| 68 | for symbol_name in SYMBOL_ITEMS.values(): | 71 | for symbol_name in SYMBOL_ITEMS.values(): |
| 69 | self.item_id_to_name[self.objects.special_ids[symbol_name]] = symbol_name | 72 | self.item_id_to_name[self.objects.special_ids[symbol_name]] = symbol_name |
| 70 | 73 | ||
| 74 | for trap_name in ANTI_COLLECTABLE_TRAPS: | ||
| 75 | self.item_id_to_name[self.objects.special_ids[trap_name]] = trap_name | ||
| 76 | |||
| 71 | self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()} | 77 | self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()} |
| 72 | self.location_name_to_id = {name: ap_id for ap_id, name in self.location_id_to_name.items()} | 78 | self.location_name_to_id = {name: ap_id for ap_id, name in self.location_id_to_name.items()} |
| 73 | 79 | ||
| 80 | for panel in self.objects.panels: | ||
| 81 | for letter in panel.answer.upper(): | ||
| 82 | self.letter_weights[letter] = self.letter_weights.get(letter, 0) + 1 | ||
| 83 | |||
| 74 | def get_door_item_name(self, door: data_pb2.Door) -> str: | 84 | def get_door_item_name(self, door: data_pb2.Door) -> str: |
| 75 | return f"{self.get_map_object_map_name(door)} - {door.name}" | 85 | return f"{self.get_map_object_map_name(door)} - {door.name}" |
| 76 | 86 | ||
| 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: | |||
| 3842 | A Job Well Done: 1160 | 3842 | A Job Well Done: 1160 |
| 3843 | Age Symbol: 2791 | 3843 | Age Symbol: 2791 |
| 3844 | Anagram Symbol: 2792 | 3844 | Anagram Symbol: 2792 |
| 3845 | Anti A: 2814 | ||
| 3846 | Anti B: 2815 | ||
| 3847 | Anti C: 2816 | ||
| 3848 | Anti D: 2817 | ||
| 3849 | Anti E: 2818 | ||
| 3850 | Anti F: 2819 | ||
| 3851 | Anti G: 2820 | ||
| 3852 | Anti H: 2821 | ||
| 3853 | Anti I: 2822 | ||
| 3854 | Anti J: 2823 | ||
| 3855 | Anti K: 2824 | ||
| 3856 | Anti L: 2825 | ||
| 3857 | Anti M: 2826 | ||
| 3858 | Anti N: 2827 | ||
| 3859 | Anti O: 2828 | ||
| 3860 | Anti P: 2829 | ||
| 3861 | Anti Q: 2830 | ||
| 3862 | Anti R: 2831 | ||
| 3863 | Anti S: 2832 | ||
| 3864 | Anti T: 2833 | ||
| 3865 | Anti U: 2834 | ||
| 3866 | Anti V: 2835 | ||
| 3867 | Anti W: 2836 | ||
| 3868 | Anti X: 2837 | ||
| 3869 | Anti Y: 2838 | ||
| 3870 | Anti Z: 2839 | ||
| 3845 | Boxes Symbol: 2793 | 3871 | Boxes Symbol: 2793 |
| 3846 | Cross Symbol: 2794 | 3872 | Cross Symbol: 2794 |
| 3847 | Eval Symbol: 2795 | 3873 | 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" | |||
| 21 | special_names: "Sun Symbol" | 21 | special_names: "Sun Symbol" |
| 22 | special_names: "Sweet Symbol" | 22 | special_names: "Sweet Symbol" |
| 23 | special_names: "Zero Symbol" | 23 | special_names: "Zero Symbol" |
| 24 | # Anti collectable traps | ||
| 25 | special_names: "Anti A" | ||
| 26 | special_names: "Anti B" | ||
| 27 | special_names: "Anti C" | ||
| 28 | special_names: "Anti D" | ||
| 29 | special_names: "Anti E" | ||
| 30 | special_names: "Anti F" | ||
| 31 | special_names: "Anti G" | ||
| 32 | special_names: "Anti H" | ||
| 33 | special_names: "Anti I" | ||
| 34 | special_names: "Anti J" | ||
| 35 | special_names: "Anti K" | ||
| 36 | special_names: "Anti L" | ||
| 37 | special_names: "Anti M" | ||
| 38 | special_names: "Anti N" | ||
| 39 | special_names: "Anti O" | ||
| 40 | special_names: "Anti P" | ||
| 41 | special_names: "Anti Q" | ||
| 42 | special_names: "Anti R" | ||
| 43 | special_names: "Anti S" | ||
| 44 | special_names: "Anti T" | ||
| 45 | special_names: "Anti U" | ||
| 46 | special_names: "Anti V" | ||
| 47 | special_names: "Anti W" | ||
| 48 | special_names: "Anti X" | ||
| 49 | special_names: "Anti Y" | ||
| 50 | special_names: "Anti Z" | ||
