Forfeit multiworld option fix for shops and pots
GT junk fill reworked for pottery lottery
This commit is contained in:
42
Fill.py
42
Fill.py
@@ -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):
|
||||||
|
|||||||
@@ -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':
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user