diff options
| author | Star Rauchenberger <fefferburbia@gmail.com> | 2024-03-22 15:28:41 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-22 21:28:41 +0100 |
| commit | 9c6e33c7869d28b8fa1b3349c9a59a40aa8c1526 (patch) | |
| tree | 2476ec2b334184139bb536337d1d9bd7a7b3591c | |
| parent | f17c4acbe9364178787888a91a6e40f8216363e8 (diff) | |
| download | lingo-apworld-9c6e33c7869d28b8fa1b3349c9a59a40aa8c1526.tar.gz lingo-apworld-9c6e33c7869d28b8fa1b3349c9a59a40aa8c1526.tar.bz2 lingo-apworld-9c6e33c7869d28b8fa1b3349c9a59a40aa8c1526.zip | |
Lingo: Add trap weights option (#2837)
| -rw-r--r-- | __init__.py | 23 | ||||
| -rw-r--r-- | items.py | 24 | ||||
| -rw-r--r-- | options.py | 14 | ||||
| -rw-r--r-- | player_logic.py | 19 |
4 files changed, 51 insertions, 29 deletions
| diff --git a/__init__.py b/__init__.py index c92e530..b749418 100644 --- a/__init__.py +++ b/__init__.py | |||
| @@ -6,7 +6,7 @@ from logging import warning | |||
| 6 | from BaseClasses import Item, ItemClassification, Tutorial | 6 | from BaseClasses import Item, ItemClassification, Tutorial |
| 7 | from worlds.AutoWorld import WebWorld, World | 7 | from worlds.AutoWorld import WebWorld, World |
| 8 | from .datatypes import Room, RoomEntrance | 8 | from .datatypes import Room, RoomEntrance |
| 9 | from .items import ALL_ITEM_TABLE, ITEMS_BY_GROUP, LingoItem | 9 | from .items import ALL_ITEM_TABLE, ITEMS_BY_GROUP, TRAP_ITEMS, LingoItem |
| 10 | from .locations import ALL_LOCATION_TABLE, LOCATIONS_BY_GROUP | 10 | from .locations import ALL_LOCATION_TABLE, LOCATIONS_BY_GROUP |
| 11 | from .options import LingoOptions | 11 | from .options import LingoOptions |
| 12 | from .player_logic import LingoPlayerLogic | 12 | from .player_logic import LingoPlayerLogic |
| @@ -91,10 +91,23 @@ class LingoWorld(World): | |||
| 91 | pool.append(self.create_item("Puzzle Skip")) | 91 | pool.append(self.create_item("Puzzle Skip")) |
| 92 | 92 | ||
| 93 | if traps: | 93 | if traps: |
| 94 | traps_list = ["Slowness Trap", "Iceland Trap", "Atbash Trap"] | 94 | total_weight = sum(self.options.trap_weights.values()) |
| 95 | 95 | ||
| 96 | for i in range(0, traps): | 96 | if total_weight == 0: |
| 97 | pool.append(self.create_item(traps_list[i % len(traps_list)])) | 97 | raise Exception("Sum of trap weights must be at least one.") |
| 98 | |||
| 99 | trap_counts = {name: int(weight * traps / total_weight) | ||
| 100 | for name, weight in self.options.trap_weights.items()} | ||
| 101 | |||
| 102 | trap_difference = traps - sum(trap_counts.values()) | ||
| 103 | if trap_difference > 0: | ||
| 104 | allowed_traps = [name for name in TRAP_ITEMS if self.options.trap_weights[name] > 0] | ||
| 105 | for i in range(0, trap_difference): | ||
| 106 | trap_counts[allowed_traps[i % len(allowed_traps)]] += 1 | ||
| 107 | |||
| 108 | for name, count in trap_counts.items(): | ||
| 109 | for i in range(0, count): | ||
| 110 | pool.append(self.create_item(name)) | ||
| 98 | 111 | ||
| 99 | self.multiworld.itempool += pool | 112 | self.multiworld.itempool += pool |
| 100 | 113 | ||
| diff --git a/items.py b/items.py index b9c4eb7..7c7928c 100644 --- a/items.py +++ b/items.py | |||
| @@ -1,13 +1,9 @@ | |||
| 1 | from typing import Dict, List, NamedTuple, Optional, TYPE_CHECKING | 1 | from typing import Dict, List, NamedTuple, Optional, TYPE_CHECKING |
| 2 | 2 | ||
| 3 | from BaseClasses import Item, ItemClassification | 3 | from BaseClasses import Item, ItemClassification |
| 4 | from .options import ShuffleDoors | ||
| 5 | from .static_logic import DOORS_BY_ROOM, PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, \ | 4 | from .static_logic import DOORS_BY_ROOM, PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, \ |
| 6 | get_door_item_id, get_progressive_item_id, get_special_item_id | 5 | get_door_item_id, get_progressive_item_id, get_special_item_id |
| 7 | 6 | ||
| 8 | if TYPE_CHECKING: | ||
| 9 | from . import LingoWorld | ||
| 10 | |||
| 11 | 7 | ||
| 12 | class ItemData(NamedTuple): | 8 | class ItemData(NamedTuple): |
| 13 | """ | 9 | """ |
| @@ -19,20 +15,6 @@ class ItemData(NamedTuple): | |||
| 19 | has_doors: bool | 15 | has_doors: bool |
| 20 | painting_ids: List[str] | 16 | painting_ids: List[str] |
| 21 | 17 | ||
| 22 | def should_include(self, world: "LingoWorld") -> bool: | ||
| 23 | if self.mode == "colors": | ||
| 24 | return world.options.shuffle_colors > 0 | ||
| 25 | elif self.mode == "doors": | ||
| 26 | return world.options.shuffle_doors != ShuffleDoors.option_none | ||
| 27 | elif self.mode == "complex door": | ||
| 28 | return world.options.shuffle_doors == ShuffleDoors.option_complex | ||
| 29 | elif self.mode == "door group": | ||
| 30 | return world.options.shuffle_doors == ShuffleDoors.option_simple | ||
| 31 | elif self.mode == "special": | ||
| 32 | return False | ||
| 33 | else: | ||
| 34 | return True | ||
| 35 | |||
| 36 | 18 | ||
| 37 | class LingoItem(Item): | 19 | class LingoItem(Item): |
| 38 | """ | 20 | """ |
| @@ -44,6 +26,8 @@ class LingoItem(Item): | |||
| 44 | ALL_ITEM_TABLE: Dict[str, ItemData] = {} | 26 | ALL_ITEM_TABLE: Dict[str, ItemData] = {} |
| 45 | ITEMS_BY_GROUP: Dict[str, List[str]] = {} | 27 | ITEMS_BY_GROUP: Dict[str, List[str]] = {} |
| 46 | 28 | ||
| 29 | TRAP_ITEMS: List[str] = ["Slowness Trap", "Iceland Trap", "Atbash Trap"] | ||
| 30 | |||
| 47 | 31 | ||
| 48 | def load_item_data(): | 32 | def load_item_data(): |
| 49 | global ALL_ITEM_TABLE, ITEMS_BY_GROUP | 33 | global ALL_ITEM_TABLE, ITEMS_BY_GROUP |
| @@ -87,9 +71,7 @@ def load_item_data(): | |||
| 87 | "The Feeling of Being Lost": ItemClassification.filler, | 71 | "The Feeling of Being Lost": ItemClassification.filler, |
| 88 | "Wanderlust": ItemClassification.filler, | 72 | "Wanderlust": ItemClassification.filler, |
| 89 | "Empty White Hallways": ItemClassification.filler, | 73 | "Empty White Hallways": ItemClassification.filler, |
| 90 | "Slowness Trap": ItemClassification.trap, | 74 | **{trap_name: ItemClassification.trap for trap_name in TRAP_ITEMS}, |
| 91 | "Iceland Trap": ItemClassification.trap, | ||
| 92 | "Atbash Trap": ItemClassification.trap, | ||
| 93 | "Puzzle Skip": ItemClassification.useful, | 75 | "Puzzle Skip": ItemClassification.useful, |
| 94 | } | 76 | } |
| 95 | 77 | ||
| diff --git a/options.py b/options.py index ed14264..293992a 100644 --- a/options.py +++ b/options.py | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | from dataclasses import dataclass | 1 | from dataclasses import dataclass |
| 2 | 2 | ||
| 3 | from Options import Toggle, Choice, DefaultOnToggle, Range, PerGameCommonOptions, StartInventoryPool | 3 | from schema import And, Schema |
| 4 | |||
| 5 | from Options import Toggle, Choice, DefaultOnToggle, Range, PerGameCommonOptions, StartInventoryPool, OptionDict | ||
| 6 | from worlds.lingo.items import TRAP_ITEMS | ||
| 4 | 7 | ||
| 5 | 8 | ||
| 6 | class ShuffleDoors(Choice): | 9 | class ShuffleDoors(Choice): |
| @@ -107,6 +110,14 @@ class TrapPercentage(Range): | |||
| 107 | default = 20 | 110 | default = 20 |
| 108 | 111 | ||
| 109 | 112 | ||
| 113 | class TrapWeights(OptionDict): | ||
| 114 | """Specify the distribution of traps that should be placed into the pool. | ||
| 115 | If you don't want a specific type of trap, set the weight to zero.""" | ||
| 116 | display_name = "Trap Weights" | ||
| 117 | schema = Schema({trap_name: And(int, lambda n: n >= 0) for trap_name in TRAP_ITEMS}) | ||
| 118 | default = {trap_name: 1 for trap_name in TRAP_ITEMS} | ||
| 119 | |||
| 120 | |||
| 110 | class PuzzleSkipPercentage(Range): | 121 | class PuzzleSkipPercentage(Range): |
| 111 | """Replaces junk items with puzzle skips, at the specified rate.""" | 122 | """Replaces junk items with puzzle skips, at the specified rate.""" |
| 112 | display_name = "Puzzle Skip Percentage" | 123 | display_name = "Puzzle Skip Percentage" |
| @@ -134,6 +145,7 @@ class LingoOptions(PerGameCommonOptions): | |||
| 134 | level_2_requirement: Level2Requirement | 145 | level_2_requirement: Level2Requirement |
| 135 | early_color_hallways: EarlyColorHallways | 146 | early_color_hallways: EarlyColorHallways |
| 136 | trap_percentage: TrapPercentage | 147 | trap_percentage: TrapPercentage |
| 148 | trap_weights: TrapWeights | ||
| 137 | puzzle_skip_percentage: PuzzleSkipPercentage | 149 | puzzle_skip_percentage: PuzzleSkipPercentage |
| 138 | death_link: DeathLink | 150 | death_link: DeathLink |
| 139 | start_inventory_from_pool: StartInventoryPool | 151 | start_inventory_from_pool: StartInventoryPool |
| diff --git a/player_logic.py b/player_logic.py index b3cefa5..966f5a1 100644 --- a/player_logic.py +++ b/player_logic.py | |||
| @@ -2,7 +2,7 @@ from enum import Enum | |||
| 2 | from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING | 2 | from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING |
| 3 | 3 | ||
| 4 | from .datatypes import Door, RoomAndDoor, RoomAndPanel | 4 | from .datatypes import Door, RoomAndDoor, RoomAndPanel |
| 5 | from .items import ALL_ITEM_TABLE | 5 | from .items import ALL_ITEM_TABLE, ItemData |
| 6 | from .locations import ALL_LOCATION_TABLE, LocationClassification | 6 | from .locations import ALL_LOCATION_TABLE, LocationClassification |
| 7 | from .options import LocationChecks, ShuffleDoors, VictoryCondition | 7 | from .options import LocationChecks, ShuffleDoors, VictoryCondition |
| 8 | from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \ | 8 | from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \ |
| @@ -58,6 +58,21 @@ def should_split_progression(progression_name: str, world: "LingoWorld") -> Prog | |||
| 58 | return ProgressiveItemBehavior.PROGRESSIVE | 58 | return ProgressiveItemBehavior.PROGRESSIVE |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | def should_include_item(item: ItemData, world: "LingoWorld") -> bool: | ||
| 62 | if item.mode == "colors": | ||
| 63 | return world.options.shuffle_colors > 0 | ||
| 64 | elif item.mode == "doors": | ||
| 65 | return world.options.shuffle_doors != ShuffleDoors.option_none | ||
| 66 | elif item.mode == "complex door": | ||
| 67 | return world.options.shuffle_doors == ShuffleDoors.option_complex | ||
| 68 | elif item.mode == "door group": | ||
| 69 | return world.options.shuffle_doors == ShuffleDoors.option_simple | ||
| 70 | elif item.mode == "special": | ||
| 71 | return False | ||
| 72 | else: | ||
| 73 | return True | ||
| 74 | |||
| 75 | |||
| 61 | class LingoPlayerLogic: | 76 | class LingoPlayerLogic: |
| 62 | """ | 77 | """ |
| 63 | Defines logic after a player's options have been applied | 78 | Defines logic after a player's options have been applied |
| @@ -212,7 +227,7 @@ class LingoPlayerLogic: | |||
| 212 | 227 | ||
| 213 | # Instantiate all real items. | 228 | # Instantiate all real items. |
| 214 | for name, item in ALL_ITEM_TABLE.items(): | 229 | for name, item in ALL_ITEM_TABLE.items(): |
| 215 | if item.should_include(world): | 230 | if should_include_item(item, world): |
| 216 | self.real_items.append(name) | 231 | self.real_items.append(name) |
| 217 | 232 | ||
| 218 | # Calculate the requirements for the fake pilgrimage. | 233 | # Calculate the requirements for the fake pilgrimage. |
