Forfeit multiworld option fix for shops and pots

GT junk fill reworked for pottery lottery
This commit is contained in:
aerinon
2022-03-25 14:54:28 -06:00
parent 901cdff47e
commit 031ec9983f
3 changed files with 42 additions and 9 deletions

42
Fill.py
View File

@@ -2,6 +2,7 @@ import RaceRandom as random
import collections import collections
import itertools import itertools
import logging import logging
import math
from BaseClasses import CollectionState, FillError, LocationType from BaseClasses import CollectionState, FillError, LocationType
from Items import ItemFactory from Items import ItemFactory
@@ -380,12 +381,21 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
# fill in gtower locations with trash first # fill in gtower locations with trash first
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
if not gftower_trash or not world.ganonstower_vanilla[player] or world.doorShuffle[player] == 'crossed' or world.logic[player] in ['owglitches', 'nologic']: if (not gftower_trash or not world.ganonstower_vanilla[player]
or world.logic[player] in ['owglitches', 'nologic']):
continue continue
max_trash = 8 if world.algorithm == 'dungeon_only' else 15 gt_count, total_count = calc_trash_locations(world, player)
gftower_trash_count = (random.randint(15, 50) if world.goal[player] == 'triforcehunt' else random.randint(0, max_trash)) scale_factor = .75 * (world.crystals_needed_for_gt[player] / 7)
if world.algorithm == 'dungeon_only':
reserved_space = sum(1 for i in progitempool+prioitempool if i.player == player)
max_trash = max(0, min(gt_count, total_count - reserved_space))
else:
max_trash = gt_count
scaled_trash = math.floor(max_trash * scale_factor)
gftower_trash_count = (random.randint(scaled_trash, max_trash) if world.goal[player] == 'triforcehunt' else random.randint(0, scaled_trash))
gtower_locations = [location for location in fill_locations if 'Ganons Tower' in location.name and location.player == player] gtower_locations = [location for location in fill_locations if location.parent_region.dungeon
and location.parent_region.dungeon.name == 'Ganons Tower' and location.player == player]
random.shuffle(gtower_locations) random.shuffle(gtower_locations)
trashcnt = 0 trashcnt = 0
while gtower_locations and restitempool and trashcnt < gftower_trash_count: while gtower_locations and restitempool and trashcnt < gftower_trash_count:
@@ -449,19 +459,41 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
ensure_good_pots(world) ensure_good_pots(world)
def calc_trash_locations(world, player):
total_count, gt_count = 0, 0
for loc in world.get_locations():
if (loc.player == player and loc.item is None
and (loc.type not in {LocationType.Pot, LocationType.Drop, LocationType.Normal} or not loc.forced_item)
and (loc.type != LocationType.Shop or world.shopsanity[player])
and loc.parent_region.dungeon):
total_count += 1
if loc.parent_region.dungeon.name == 'Ganons Tower':
gt_count += 1
return gt_count, total_count
def ensure_good_pots(world, write_skips=False): def ensure_good_pots(world, write_skips=False):
for loc in world.get_locations(): for loc in world.get_locations():
# convert Arrows 5 and Nothing when necessary # convert Arrows 5 and Nothing when necessary
if (loc.item.name in {'Arrows (5)', 'Nothing'} if (loc.item.name in {'Arrows (5)', 'Nothing'}
and (loc.type != LocationType.Pot or loc.item.player != loc.player)): and (loc.type != LocationType.Pot or loc.item.player != loc.player)):
loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player) loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player)
# can be placed here by multiworld balancing or shop balancing
# change it to something normal for the player it got swapped to
elif (loc.item.name in {'Chicken', 'Big Magic'}
and (loc.type != LocationType.Pot or loc.item.player != loc.player)):
if loc.type == LocationType.Pot:
loc.item.player = loc.player
else:
loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.player)
# don't write out all pots to spoiler # don't write out all pots to spoiler
if write_skips: if write_skips:
if loc.type == LocationType.Pot and loc.item.name in valid_pot_items: if loc.type == LocationType.Pot and loc.item.name in valid_pot_items:
loc.skip = True loc.skip = True
invalid_location_replacement = {'Arrows (5)': 'Arrows (10)', 'Nothing': 'Rupees (5)'} invalid_location_replacement = {'Arrows (5)': 'Arrows (10)', 'Nothing': 'Rupees (5)',
'Chicken': 'Rupees (5)', 'Big Magic': 'Small Magic'}
def fast_fill_helper(world, item_pool, fill_locations): def fast_fill_helper(world, item_pool, fill_locations):

View File

@@ -159,8 +159,7 @@ def send_new_items(ctx : Context):
client.send_index = len(items) client.send_index = len(items)
def forfeit_player(ctx : Context, team, slot): def forfeit_player(ctx : Context, team, slot):
all_locations = {values[0] for values in Regions.location_table.values() if type(values[0]) is int} all_locations = set(ctx.lookup_id_to_name.keys())
all_locations.update({values[1] for values in Regions.key_drop_data.values()})
notify_all(ctx, "%s (Team #%d) has forfeited" % (ctx.player_names[(team, slot)], team + 1)) notify_all(ctx, "%s (Team #%d) has forfeited" % (ctx.player_names[(team, slot)], team + 1))
register_location_checks(ctx, team, slot, all_locations) register_location_checks(ctx, team, slot, all_locations)
@@ -347,8 +346,8 @@ async def console(ctx : Context):
def init_lookups(ctx): def init_lookups(ctx):
ctx.lookup_id_to_name = {x: y for x, y in Regions.lookup_id_to_name.items()} ctx.lookup_id_to_name = {x: y for x, y in Regions.lookup_id_to_name.items()}
ctx.lookup_name_to_id = {x: y for x, y in Regions.lookup_name_to_id.items()} ctx.lookup_name_to_id = {x: y for x, y in Regions.lookup_name_to_id.items()}
for location, datum in PotShuffle.key_drop_data.items(): for location, datum in PotShuffle.key_drop_data.items():
type = datum[0] type = datum[0]
if type == 'Drop': if type == 'Drop':

View File

@@ -148,6 +148,8 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o
#### Volatile #### Volatile
* 1.0.1.12 * 1.0.1.12
* Fix for Multiworld forfeits, shops and pot items now included
* Reworked GT Trash Fill. Base rate is 0-75% of locations fill with 7 crystals entrance requirements. Triforce hunt is 75%-100% of locations. The 75% number will decrease based on the crystal entrance requirement. Dungeon_only algorithm caps it based on how many items need to be placed in dungeons. Cross dungeon shuffle will now work with the trash fill.
* Inverted bug * Inverted bug
* Fix for hammerdashing pots, if sprite limit is reached, items won't spawn, error beep won't play either because of other SFX * Fix for hammerdashing pots, if sprite limit is reached, items won't spawn, error beep won't play either because of other SFX
* Killing enemies freeze + hammer results in the droppable item instead of the freeze prize * Killing enemies freeze + hammer results in the droppable item instead of the freeze prize