Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lingo: Add trap weights option #2837

Merged
merged 6 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
hatkirby marked this conversation as resolved.
Show resolved Hide resolved

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
Loading