Witness: Changes in response to Beta run 1 (#494)
Co-authored-by: metzner <unconfigured@null.spigotmc.org>
This commit is contained in:
parent
1e592b4681
commit
9ab7c8d9e5
|
@ -1,6 +1,6 @@
|
|||
from typing import Dict
|
||||
from BaseClasses import MultiWorld
|
||||
from Options import Toggle, DefaultOnToggle, Option
|
||||
from Options import Toggle, DefaultOnToggle, Option, Range
|
||||
|
||||
|
||||
# class HardMode(Toggle):
|
||||
|
@ -30,8 +30,8 @@ class ShuffleVaultBoxes(Toggle):
|
|||
|
||||
|
||||
class ShuffleUncommonLocations(Toggle):
|
||||
"""Adds the following checks to the pool:
|
||||
Mountaintop River Shape, Tutorial Patio Floor, Theater Videos"""
|
||||
"""Adds some optional puzzles that are somewhat difficult or out of the way.
|
||||
Examples: Mountaintop River Shape, Tutorial Patio Floor, Theater Videos"""
|
||||
display_name = "Shuffle Uncommon Locations"
|
||||
|
||||
|
||||
|
@ -46,6 +46,14 @@ class ChallengeVictoryCondition(Toggle):
|
|||
display_name = "Victory on beating the Challenge"
|
||||
|
||||
|
||||
class TrapPercentage(Range):
|
||||
"""Replaces junk items with traps, at the specified rate."""
|
||||
display_name = "Trap Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 20
|
||||
|
||||
|
||||
the_witness_options: Dict[str, Option] = {
|
||||
# "hard_mode": HardMode,
|
||||
# "unlock_symbols": UnlockSymbols,
|
||||
|
@ -54,7 +62,8 @@ the_witness_options: Dict[str, Option] = {
|
|||
"shuffle_vault_boxes": ShuffleVaultBoxes,
|
||||
"shuffle_uncommon": ShuffleUncommonLocations,
|
||||
"shuffle_hard": ShuffleHardLocations,
|
||||
"challenge_victory": ChallengeVictoryCondition
|
||||
"challenge_victory": ChallengeVictoryCondition,
|
||||
"trap_percentage": TrapPercentage
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -370,7 +370,7 @@ Jungle (Jungle) - Main Island - True:
|
|||
|
||||
Outside Jungle River (River) - Main Island - True - Jungle - 0x337FA:
|
||||
0x17CAA (Rhombic Avoid to Monastery Garden) - True - Environment
|
||||
0x15ADD (Rhombic Avoid Vault) - True - Environment
|
||||
0x15ADD (Vault) - True - Environment & Black/White Squares & Dots
|
||||
0x03702 (Vault Box) - 0x15ADD - True
|
||||
|
||||
Outside Bunker (Bunker) - Main Island - True - Inside Bunker - 0x0A079:
|
||||
|
|
|
@ -12,6 +12,7 @@ from .items import WitnessItem, StaticWitnessItems, WitnessPlayerItems
|
|||
from .rules import set_rules
|
||||
from .regions import WitnessRegions
|
||||
from .Options import is_option_enabled, the_witness_options
|
||||
from .utils import best_junk_to_add_based_on_weights
|
||||
|
||||
|
||||
class WitnessWebWorld(WebWorld):
|
||||
|
@ -50,6 +51,8 @@ class WitnessWorld(World):
|
|||
self.items = WitnessPlayerItems(self.locat, self.world, self.player, self.player_logic)
|
||||
self.regio = WitnessRegions(self.locat)
|
||||
|
||||
self.junk_items_created = {key: 0 for key in self.items.JUNK_WEIGHTS.keys()}
|
||||
|
||||
def generate_basic(self):
|
||||
# Generate item pool
|
||||
pool = []
|
||||
|
@ -69,13 +72,10 @@ class WitnessWorld(World):
|
|||
pool.remove(items_by_name[random_good_item])
|
||||
|
||||
# Put in junk items to fill the rest
|
||||
junk_pool = self.items.JUNK_WEIGHTS.copy()
|
||||
junk_pool = self.world.random.choices(
|
||||
list(junk_pool.keys()), weights=list(junk_pool.values()),
|
||||
k=len(self.locat.CHECK_LOCATION_TABLE) - len(pool) - len(self.locat.EVENT_LOCATION_TABLE) - 1
|
||||
)
|
||||
junk_size = len(self.locat.CHECK_LOCATION_TABLE) - len(pool) - len(self.locat.EVENT_LOCATION_TABLE) - 1
|
||||
|
||||
pool += [self.create_item(junk) for junk in junk_pool]
|
||||
for i in range(0, junk_size):
|
||||
pool.append(self.create_item(self.get_filler_item_name()))
|
||||
|
||||
# Tie Event Items to Event Locations (e.g. Laser Activations)
|
||||
for event_location in self.locat.EVENT_LOCATION_TABLE:
|
||||
|
@ -118,10 +118,12 @@ class WitnessWorld(World):
|
|||
new_item.trap = item.trap
|
||||
return new_item
|
||||
|
||||
def get_filler_item_name(self) -> str: # Used ny itemlinks
|
||||
junk_pool = self.items.JUNK_WEIGHTS.copy()
|
||||
def get_filler_item_name(self) -> str: # Used by itemlinks
|
||||
item = best_junk_to_add_based_on_weights(self.items.JUNK_WEIGHTS, self.junk_items_created)
|
||||
|
||||
return self.world.random.choices(list(junk_pool.keys()), weights=list(junk_pool.values()))[0]
|
||||
self.junk_items_created[item] += 1
|
||||
|
||||
return item
|
||||
|
||||
|
||||
class WitnessLocation(Location):
|
||||
|
|
|
@ -6,7 +6,8 @@ from typing import Dict, NamedTuple, Optional
|
|||
|
||||
from BaseClasses import Item, MultiWorld
|
||||
from . import StaticWitnessLogic, WitnessPlayerLocations, WitnessPlayerLogic
|
||||
from .Options import is_option_enabled
|
||||
from .Options import get_option_value, is_option_enabled
|
||||
from fractions import Fraction
|
||||
|
||||
|
||||
class ItemData(NamedTuple):
|
||||
|
@ -33,12 +34,19 @@ class StaticWitnessItems:
|
|||
|
||||
ALL_ITEM_TABLE: Dict[str, ItemData] = {}
|
||||
|
||||
JUNK_WEIGHTS = {
|
||||
"Speed Boost": 1,
|
||||
"Slowness": 0.8,
|
||||
"Power Surge": 0.2,
|
||||
# These should always add up to 1!!!
|
||||
BONUS_WEIGHTS = {
|
||||
"Speed Boost": Fraction(1, 1),
|
||||
}
|
||||
|
||||
# These should always add up to 1!!!
|
||||
TRAP_WEIGHTS = {
|
||||
"Slowness": Fraction(8, 10),
|
||||
"Power Surge": Fraction(2, 10),
|
||||
}
|
||||
|
||||
ALL_JUNK_ITEMS = set(BONUS_WEIGHTS.keys()) | set(TRAP_WEIGHTS.keys())
|
||||
|
||||
def __init__(self):
|
||||
item_tab = dict()
|
||||
|
||||
|
@ -91,8 +99,28 @@ class WitnessPlayerItems:
|
|||
self.EVENT_ITEM_TABLE[location] = ItemData(None, True, True)
|
||||
self.ITEM_TABLE[location] = ItemData(None, True, True)
|
||||
|
||||
trap_percentage = get_option_value(world, player, "trap_percentage")
|
||||
|
||||
self.JUNK_WEIGHTS = dict()
|
||||
|
||||
if trap_percentage != 0:
|
||||
# I'm sure there must be some super "pythonic" way of doing this :D
|
||||
|
||||
for trap_name, trap_weight in StaticWitnessItems.TRAP_WEIGHTS.items():
|
||||
self.JUNK_WEIGHTS[trap_name] = (trap_weight * trap_percentage) / 100
|
||||
|
||||
if trap_percentage != 100:
|
||||
for bonus_name, bonus_weight in StaticWitnessItems.BONUS_WEIGHTS.items():
|
||||
self.JUNK_WEIGHTS[bonus_name] = (bonus_weight * (100 - trap_percentage)) / 100
|
||||
|
||||
self.JUNK_WEIGHTS = {
|
||||
key: value for (key, value)
|
||||
in StaticWitnessItems.JUNK_WEIGHTS.items()
|
||||
in self.JUNK_WEIGHTS.items()
|
||||
if key in self.ITEM_TABLE.keys()
|
||||
}
|
||||
|
||||
# JUNK_WEIGHTS will add up to 1 if the boosts weights and the trap weights each add up to 1 respectively.
|
||||
|
||||
for junk_item in StaticWitnessItems.ALL_JUNK_ITEMS:
|
||||
if junk_item not in self.JUNK_WEIGHTS.keys():
|
||||
del self.ITEM_TABLE[junk_item]
|
||||
|
|
|
@ -1,5 +1,45 @@
|
|||
import os
|
||||
from Utils import cache_argsless
|
||||
from itertools import accumulate
|
||||
from typing import *
|
||||
from fractions import Fraction
|
||||
|
||||
|
||||
def best_junk_to_add_based_on_weights(weights: Dict[Any, Fraction], created_junk: Dict[Any, int]):
|
||||
min_error = ("", 2)
|
||||
|
||||
for junk_name, instances in created_junk.items():
|
||||
new_dist = created_junk.copy()
|
||||
new_dist[junk_name] += 1
|
||||
new_dist_length = sum(new_dist.values())
|
||||
new_dist = {key: Fraction(value/1)/new_dist_length for key, value in new_dist.items()}
|
||||
|
||||
errors = {key: abs(new_dist[key] - weights[key]) for key in created_junk.keys()}
|
||||
|
||||
new_min_error = max(errors.values())
|
||||
|
||||
if min_error[1] > new_min_error:
|
||||
min_error = (junk_name, new_min_error)
|
||||
|
||||
return min_error[0]
|
||||
|
||||
|
||||
def weighted_list(weights: Dict[Any, Fraction], length):
|
||||
"""
|
||||
Example:
|
||||
weights = {A: 0.3, B: 0.3, C: 0.4}
|
||||
length = 10
|
||||
|
||||
returns: [A, A, A, B, B, B, C, C, C, C]
|
||||
|
||||
Makes sure to match length *exactly*, might approximate as a result
|
||||
"""
|
||||
vals = accumulate(map(lambda x: x * length, weights.values()), lambda x, y: x + y)
|
||||
output_list = []
|
||||
for k, v in zip(weights.keys(), vals):
|
||||
while len(output_list) < v:
|
||||
output_list.append(k)
|
||||
return output_list
|
||||
|
||||
|
||||
def define_new_region(region_string):
|
||||
|
@ -55,4 +95,4 @@ def get_disable_unrandomized_list():
|
|||
path = os.path.join(os.path.dirname(__file__), adjustment_file)
|
||||
|
||||
with open(path) as f:
|
||||
return [line.strip() for line in f.readlines()]
|
||||
return [line.strip() for line in f.readlines()]
|
||||
|
|
Loading…
Reference in New Issue