Lingo: Add trap weights option (#2837)

This commit is contained in:
Star Rauchenberger 2024-03-22 15:28:41 -05:00 committed by GitHub
parent 11b32f17ab
commit 44988d430d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 28 deletions

View File

@ -6,7 +6,7 @@ from logging import warning
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
@ -91,10 +91,23 @@ class LingoWorld(World):
pool.append(self.create_item("Puzzle Skip"))
if traps:
traps_list = ["Slowness Trap", "Iceland Trap", "Atbash Trap"]
total_weight = sum(self.options.trap_weights.values())
for i in range(0, traps):
pool.append(self.create_item(traps_list[i % len(traps_list)]))
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

View File

@ -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):
"""
@ -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):
"""
@ -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
@ -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,
}

View File

@ -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):
@ -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"
@ -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

View File

@ -2,7 +2,7 @@ from enum import Enum
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, \
@ -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
@ -212,7 +227,7 @@ class LingoPlayerLogic:
# 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.