Skip to content

Commit 44988d4

Browse files
authored
Lingo: Add trap weights option (#2837)
1 parent 11b32f1 commit 44988d4

File tree

4 files changed

+51
-29
lines changed

4 files changed

+51
-29
lines changed

worlds/lingo/__init__.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from BaseClasses import Item, ItemClassification, Tutorial
77
from worlds.AutoWorld import WebWorld, World
88
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
1010
from .locations import ALL_LOCATION_TABLE, LOCATIONS_BY_GROUP
1111
from .options import LingoOptions
1212
from .player_logic import LingoPlayerLogic
@@ -91,10 +91,23 @@ def create_items(self):
9191
pool.append(self.create_item("Puzzle Skip"))
9292

9393
if traps:
94-
traps_list = ["Slowness Trap", "Iceland Trap", "Atbash Trap"]
95-
96-
for i in range(0, traps):
97-
pool.append(self.create_item(traps_list[i % len(traps_list)]))
94+
total_weight = sum(self.options.trap_weights.values())
95+
96+
if total_weight == 0:
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))
98111

99112
self.multiworld.itempool += pool
100113

worlds/lingo/items.py

+3-21
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
from typing import Dict, List, NamedTuple, Optional, TYPE_CHECKING
22

33
from BaseClasses import Item, ItemClassification
4-
from .options import ShuffleDoors
54
from .static_logic import DOORS_BY_ROOM, PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, \
65
get_door_item_id, get_progressive_item_id, get_special_item_id
76

8-
if TYPE_CHECKING:
9-
from . import LingoWorld
10-
117

128
class ItemData(NamedTuple):
139
"""
@@ -19,20 +15,6 @@ class ItemData(NamedTuple):
1915
has_doors: bool
2016
painting_ids: List[str]
2117

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-
3618

3719
class LingoItem(Item):
3820
"""
@@ -44,6 +26,8 @@ class LingoItem(Item):
4426
ALL_ITEM_TABLE: Dict[str, ItemData] = {}
4527
ITEMS_BY_GROUP: Dict[str, List[str]] = {}
4628

29+
TRAP_ITEMS: List[str] = ["Slowness Trap", "Iceland Trap", "Atbash Trap"]
30+
4731

4832
def load_item_data():
4933
global ALL_ITEM_TABLE, ITEMS_BY_GROUP
@@ -87,9 +71,7 @@ def load_item_data():
8771
"The Feeling of Being Lost": ItemClassification.filler,
8872
"Wanderlust": ItemClassification.filler,
8973
"Empty White Hallways": ItemClassification.filler,
90-
"Slowness Trap": ItemClassification.trap,
91-
"Iceland Trap": ItemClassification.trap,
92-
"Atbash Trap": ItemClassification.trap,
74+
**{trap_name: ItemClassification.trap for trap_name in TRAP_ITEMS},
9375
"Puzzle Skip": ItemClassification.useful,
9476
}
9577

worlds/lingo/options.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from dataclasses import dataclass
22

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
47

58

69
class ShuffleDoors(Choice):
@@ -107,6 +110,14 @@ class TrapPercentage(Range):
107110
default = 20
108111

109112

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+
110121
class PuzzleSkipPercentage(Range):
111122
"""Replaces junk items with puzzle skips, at the specified rate."""
112123
display_name = "Puzzle Skip Percentage"
@@ -134,6 +145,7 @@ class LingoOptions(PerGameCommonOptions):
134145
level_2_requirement: Level2Requirement
135146
early_color_hallways: EarlyColorHallways
136147
trap_percentage: TrapPercentage
148+
trap_weights: TrapWeights
137149
puzzle_skip_percentage: PuzzleSkipPercentage
138150
death_link: DeathLink
139151
start_inventory_from_pool: StartInventoryPool

worlds/lingo/player_logic.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING
33

44
from .datatypes import Door, RoomAndDoor, RoomAndPanel
5-
from .items import ALL_ITEM_TABLE
5+
from .items import ALL_ITEM_TABLE, ItemData
66
from .locations import ALL_LOCATION_TABLE, LocationClassification
77
from .options import LocationChecks, ShuffleDoors, VictoryCondition
88
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
5858
return ProgressiveItemBehavior.PROGRESSIVE
5959

6060

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+
6176
class LingoPlayerLogic:
6277
"""
6378
Defines logic after a player's options have been applied
@@ -212,7 +227,7 @@ def __init__(self, world: "LingoWorld"):
212227

213228
# Instantiate all real items.
214229
for name, item in ALL_ITEM_TABLE.items():
215-
if item.should_include(world):
230+
if should_include_item(item, world):
216231
self.real_items.append(name)
217232

218233
# Calculate the requirements for the fake pilgrimage.

0 commit comments

Comments
 (0)