Skip to content

Commit

Permalink
Lingo: Add trap weights option (ArchipelagoMW#2837)
Browse files Browse the repository at this point in the history
  • Loading branch information
hatkirby authored Mar 22, 2024
1 parent 11b32f1 commit 44988d4
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 29 deletions.
23 changes: 18 additions & 5 deletions worlds/lingo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from BaseClasses import Item, ItemClassification, Tutorial
from worlds.AutoWorld import WebWorld, World
from .datatypes import Room, RoomEntrance
from .items import ALL_ITEM_TABLE, ITEMS_BY_GROUP, LingoItem
from .items import ALL_ITEM_TABLE, ITEMS_BY_GROUP, TRAP_ITEMS, LingoItem
from .locations import ALL_LOCATION_TABLE, LOCATIONS_BY_GROUP
from .options import LingoOptions
from .player_logic import LingoPlayerLogic
Expand Down Expand Up @@ -91,10 +91,23 @@ def create_items(self):
pool.append(self.create_item("Puzzle Skip"))

if traps:
traps_list = ["Slowness Trap", "Iceland Trap", "Atbash Trap"]

for i in range(0, traps):
pool.append(self.create_item(traps_list[i % len(traps_list)]))
total_weight = sum(self.options.trap_weights.values())

if total_weight == 0:
raise Exception("Sum of trap weights must be at least one.")

trap_counts = {name: int(weight * traps / total_weight)
for name, weight in self.options.trap_weights.items()}

trap_difference = traps - sum(trap_counts.values())
if trap_difference > 0:
allowed_traps = [name for name in TRAP_ITEMS if self.options.trap_weights[name] > 0]
for i in range(0, trap_difference):
trap_counts[allowed_traps[i % len(allowed_traps)]] += 1

for name, count in trap_counts.items():
for i in range(0, count):
pool.append(self.create_item(name))

self.multiworld.itempool += pool

Expand Down
24 changes: 3 additions & 21 deletions worlds/lingo/items.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
from typing import Dict, List, NamedTuple, Optional, TYPE_CHECKING

from BaseClasses import Item, ItemClassification
from .options import ShuffleDoors
from .static_logic import DOORS_BY_ROOM, PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, \
get_door_item_id, get_progressive_item_id, get_special_item_id

if TYPE_CHECKING:
from . import LingoWorld


class ItemData(NamedTuple):
"""
Expand All @@ -19,20 +15,6 @@ class ItemData(NamedTuple):
has_doors: bool
painting_ids: List[str]

def should_include(self, world: "LingoWorld") -> bool:
if self.mode == "colors":
return world.options.shuffle_colors > 0
elif self.mode == "doors":
return world.options.shuffle_doors != ShuffleDoors.option_none
elif self.mode == "complex door":
return world.options.shuffle_doors == ShuffleDoors.option_complex
elif self.mode == "door group":
return world.options.shuffle_doors == ShuffleDoors.option_simple
elif self.mode == "special":
return False
else:
return True


class LingoItem(Item):
"""
Expand All @@ -44,6 +26,8 @@ class LingoItem(Item):
ALL_ITEM_TABLE: Dict[str, ItemData] = {}
ITEMS_BY_GROUP: Dict[str, List[str]] = {}

TRAP_ITEMS: List[str] = ["Slowness Trap", "Iceland Trap", "Atbash Trap"]


def load_item_data():
global ALL_ITEM_TABLE, ITEMS_BY_GROUP
Expand Down Expand Up @@ -87,9 +71,7 @@ def load_item_data():
"The Feeling of Being Lost": ItemClassification.filler,
"Wanderlust": ItemClassification.filler,
"Empty White Hallways": ItemClassification.filler,
"Slowness Trap": ItemClassification.trap,
"Iceland Trap": ItemClassification.trap,
"Atbash Trap": ItemClassification.trap,
**{trap_name: ItemClassification.trap for trap_name in TRAP_ITEMS},
"Puzzle Skip": ItemClassification.useful,
}

Expand Down
14 changes: 13 additions & 1 deletion worlds/lingo/options.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from dataclasses import dataclass

from Options import Toggle, Choice, DefaultOnToggle, Range, PerGameCommonOptions, StartInventoryPool
from schema import And, Schema

from Options import Toggle, Choice, DefaultOnToggle, Range, PerGameCommonOptions, StartInventoryPool, OptionDict
from worlds.lingo.items import TRAP_ITEMS


class ShuffleDoors(Choice):
Expand Down Expand Up @@ -107,6 +110,14 @@ class TrapPercentage(Range):
default = 20


class TrapWeights(OptionDict):
"""Specify the distribution of traps that should be placed into the pool.
If you don't want a specific type of trap, set the weight to zero."""
display_name = "Trap Weights"
schema = Schema({trap_name: And(int, lambda n: n >= 0) for trap_name in TRAP_ITEMS})
default = {trap_name: 1 for trap_name in TRAP_ITEMS}


class PuzzleSkipPercentage(Range):
"""Replaces junk items with puzzle skips, at the specified rate."""
display_name = "Puzzle Skip Percentage"
Expand Down Expand Up @@ -134,6 +145,7 @@ class LingoOptions(PerGameCommonOptions):
level_2_requirement: Level2Requirement
early_color_hallways: EarlyColorHallways
trap_percentage: TrapPercentage
trap_weights: TrapWeights
puzzle_skip_percentage: PuzzleSkipPercentage
death_link: DeathLink
start_inventory_from_pool: StartInventoryPool
19 changes: 17 additions & 2 deletions worlds/lingo/player_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING

from .datatypes import Door, RoomAndDoor, RoomAndPanel
from .items import ALL_ITEM_TABLE
from .items import ALL_ITEM_TABLE, ItemData
from .locations import ALL_LOCATION_TABLE, LocationClassification
from .options import LocationChecks, ShuffleDoors, VictoryCondition
from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \
Expand Down Expand Up @@ -58,6 +58,21 @@ def should_split_progression(progression_name: str, world: "LingoWorld") -> Prog
return ProgressiveItemBehavior.PROGRESSIVE


def should_include_item(item: ItemData, world: "LingoWorld") -> bool:
if item.mode == "colors":
return world.options.shuffle_colors > 0
elif item.mode == "doors":
return world.options.shuffle_doors != ShuffleDoors.option_none
elif item.mode == "complex door":
return world.options.shuffle_doors == ShuffleDoors.option_complex
elif item.mode == "door group":
return world.options.shuffle_doors == ShuffleDoors.option_simple
elif item.mode == "special":
return False
else:
return True


class LingoPlayerLogic:
"""
Defines logic after a player's options have been applied
Expand Down Expand Up @@ -212,7 +227,7 @@ def __init__(self, world: "LingoWorld"):

# Instantiate all real items.
for name, item in ALL_ITEM_TABLE.items():
if item.should_include(world):
if should_include_item(item, world):
self.real_items.append(name)

# Calculate the requirements for the fake pilgrimage.
Expand Down

0 comments on commit 44988d4

Please sign in to comment.