Fix Custom Item Pool (again again)

This commit is contained in:
Mike A. Trethewey
2020-02-23 16:21:39 -08:00
parent 55fee9317d
commit baec0e4548
5 changed files with 204 additions and 184 deletions

148
CLI.py
View File

@@ -13,6 +13,8 @@ from Rom import get_sprite_from_name
from Utils import is_bundled, close_console
from Fill import FillError
import classes.constants as CONST
class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
@@ -372,79 +374,79 @@ def get_settings():
"remote_items": False,
"race": False,
"custom": False,
"customitemarray": [
0, # Bow
2, # Progessive Bow
1, # Blue Boomerang
1, # Red Boomerang
1, # Hookshot
1, # Mushroom
1, # Magic Powder
1, # Fire Rod
1, # Ice Rod
1, # Bombos
1, # Ether
1, # Quake
1, # Lamp
1, # Hammer
1, # Shovel
1, # Flute
1, # Bug Net
1, # Book
4, # Bottle
1, # Cane of Somaria
1, # Cane of Byrna
1, # Magic Cape
1, # Magic Mirror
1, # Pegasus Boots
0, # Power Glove
0, # Titan's Mitt
2, # Progressive Glove
1, # Flippers
1, # Moon Pearl
24, # Piece of Heart
10, # Heart Container
1, # Sanctuary Heart
0, # FS
0, # MS
0, # TS
0, # GS
4, # Progressive Sword
0, # Fighters' Shield
0, # Fire Shield
0, # Mirror Shield
3, # Progressive Shield
0, # Blue Mail
0, # Red Mail
2, # Progressive Mail
1, # Half Magic
0, # Quarter Magic
0, # Bombs + 5
0, # Bombs +10
0, # Arrows + 5
0, # Arrows +10
1, # Single Arrow
12, # 10 Arrows
0, # Single Bomb
16, # 3 Bombs
1, # 10 Bombs
2, # 1 Rupee
4, # 5 Rupees
28, # 20 Rupees
7, # 50 Rupees
1, # 100 Rupees
5, # 300 Rupees
0, # Blue Clock
0, # Green Clock
0, # Red Clock
0, # Silver Arrows Upgrade
0, # Generic Keys
0, # Triforce Pieces
0, # Triforce Pieces Goal
0, # Triforce (win game)
0, # Rupoors
10 # Rupoor Cost
],
"customitemarray": {
"bow": 0,
"progressivebow": 2,
"boomerang": 1,
"redmerang": 1,
"hookshot": 1,
"mushroom": 1,
"powder": 1,
"firerod": 1,
"icerod": 1,
"bombos": 1,
"ether": 1,
"quake": 1,
"lamp": 1,
"hammer": 1,
"shovel": 1,
"flute": 1,
"bugnet": 1,
"book": 1,
"bottle": 4,
"somaria": 1,
"byrna": 1,
"cape": 1,
"mirror": 1,
"boots": 1,
"powerglove": 0,
"titansmitt": 0,
"progressiveglove": 2,
"flippers": 1,
"pearl": 1,
"heartpiece": 24,
"heartcontainer": 10,
"sancheart": 1,
"sword1": 0,
"sword2": 0,
"sword3": 0,
"sword4": 0,
"progressivesword": 4,
"shield1": 0,
"shield2": 0,
"shield3": 0,
"progressiveshield": 3,
"mail2": 0,
"mail3": 0,
"progressivemail": 2,
"halfmagic": 1,
"quartermagic": 0,
"bombsplus5": 0,
"bombsplus10": 0,
"arrowsplus5": 0,
"arrowsplus10": 0,
"arrow1": 1,
"arrow10": 12,
"bomb1": 0,
"bomb3": 16,
"bomb10": 1,
"rupee1": 2,
"rupee5": 4,
"rupee20": 28,
"rupee50": 7,
"rupee100": 1,
"rupee300": 5,
"blueclock": 0,
"greenclock": 0,
"redclock": 0,
"silversupgrade": 0,
"generickeys": 0,
"triforcepieces": 0,
"triforcepiecesgoal": 0,
"triforce": 0,
"rupoor": 0,
"rupoorcost": 10
},
"rom": os.path.join(".","Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"),
"sprite": None,
"randomSprite": False,

View File

@@ -9,6 +9,8 @@ from EntranceShuffle import connect_entrance
from Fill import FillError, fill_restrictive
from Items import ItemFactory
import classes.constants as CONST
#This file sets the item pools for various modes. Timed modes and triforce hunt are enforced first, and then extra items are specified per mode to fill in the remaining space.
#Some basic items that various modes require are placed here, including pendants and crystals. Medallion requirements for the two relevant entrances are also decided.
@@ -124,6 +126,57 @@ difficulties = {
),
}
def get_custom_array_key(item):
label_switcher = {
"silverarrow": "silversupgrade",
"blueboomerang": "boomerang",
"redboomerang": "redmerang",
"ocarina": "flute",
"bugcatchingnet": "bugnet",
"bookofmudora": "book",
"pegasusboots": "boots",
"titansmitts": "titansmitt",
"pieceofheart": "heartpiece",
"bossheartcontainer": "heartcontainer",
"sanctuaryheartcontainer": "sancheart",
"mastersword": "sword2",
"temperedsword": "sword3",
"goldensword": "sword4",
"blueshield": "shield1",
"redshield": "shield2",
"mirrorshield": "shield3",
"bluemail": "mail2",
"redmail": "mail3",
"progressivearmor": "progressivemail",
"splus12": "halfmagic",
"splus14": "quartermagic",
"singlearrow": "arrow1",
"singlebomb": "bomb1",
"triforcepiece": "triforcepieces"
}
key = item.lower()
trans = {
" ": "",
'(': "",
'/': "",
')': "",
'+': "",
"magic": "",
"caneof": "",
"upgrade": "splus",
"arrows": "arrow",
"arrowplus": "arrowsplus",
"bombs": "bomb",
"bombplus": "bombsplus",
"rupees": "rupee"
}
for check in trans:
repl = trans[check]
key = key.replace(check,repl)
if key in label_switcher:
key = label_switcher.get(key)
return key
def generate_itempool(world, player):
if (world.difficulty[player] not in ['normal', 'hard', 'expert'] or world.goal[player] not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals']
or world.mode[player] not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']):
@@ -141,7 +194,7 @@ def generate_itempool(world, player):
region = world.get_region('Light World',player)
loc = Location(player, "Murahdahla", parent=region)
loc.access_rule = lambda state: state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) > state.world.treasure_hunt_count[player]
loc.access_rule = lambda state: state.item_count(get_custom_array_key('Triforce Piece'), player) + state.item_count(get_custom_array_key('Power Star'), player) > state.world.treasure_hunt_count[player]
region.locations.append(loc)
world.dynamic_locations.append(loc)
@@ -204,7 +257,7 @@ def generate_itempool(world, player):
# set up item pool
if world.custom:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.customitemarray)
world.rupoor_cost = min(world.customitemarray[69], 9999)
world.rupoor_cost = min(world.customitemarray["rupoorcost"], 9999)
else:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player])
@@ -212,10 +265,10 @@ def generate_itempool(world, player):
amt = world.pool_adjustment[player]
if amt < 0:
for i in range(0, amt):
pool.remove('Rupees (20)')
pool.remove(get_custom_array_key('Rupees (20)'))
elif amt > 0:
for i in range(0, amt):
pool.append('Rupees (20)')
pool.append(get_custom_array_key('Rupees (20)'))
for item in precollected_items:
world.push_precollected(ItemFactory(item, player))
@@ -268,9 +321,9 @@ def generate_itempool(world, player):
# logic has some branches where having 4 hearts is one possible requirement (of several alternatives)
# rather than making all hearts/heart pieces progression items (which slows down generation considerably)
# We mark one random heart container as an advancement item (or 4 heart pieces in expert mode)
if world.difficulty[player] in ['normal', 'hard'] and not (world.custom and world.customitemarray[30] == 0):
if world.difficulty[player] in ['normal', 'hard'] and not (world.custom and world.customitemarray["heartcontainer"] == 0):
[item for item in items if item.name == 'Boss Heart Container'][0].advancement = True
elif world.difficulty[player] in ['expert'] and not (world.custom and world.customitemarray[29] < 4):
elif world.difficulty[player] in ['expert'] and not (world.custom and world.customitemarray["heartpiece"] < 4):
adv_heart_pieces = [item for item in items if item.name == 'Piece of Heart'][0:4]
for hp in adv_heart_pieces:
hp.advancement = True
@@ -558,80 +611,31 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
placed_items[loc] = item
# Correct for insanely oversized item counts and take initial steps to handle undersized pools.
for x in range(0, 66):
if customitemarray[x] > total_items_to_place:
customitemarray[x] = total_items_to_place
if customitemarray[68] > total_items_to_place:
customitemarray[68] = total_items_to_place
itemtotal = 0
for x in range(0, 66):
itemtotal = itemtotal + customitemarray[x]
itemtotal = itemtotal + customitemarray[68]
itemtotal = itemtotal + customitemarray[70]
# Bow to Silver Arrows Upgrade, including Generic Keys & Rupoors
for x in [*range(0, 66 + 1), 68, 69]:
key = CONST.CUSTOMITEMS[x]
if customitemarray[key] > total_items_to_place:
customitemarray[key] = total_items_to_place
pool.extend(['Bow'] * customitemarray[0])
pool.extend(['Silver Arrows']* customitemarray[1])
pool.extend(['Blue Boomerang'] * customitemarray[2])
pool.extend(['Red Boomerang'] * customitemarray[3])
pool.extend(['Hookshot'] * customitemarray[4])
pool.extend(['Mushroom'] * customitemarray[5])
pool.extend(['Magic Powder'] * customitemarray[6])
pool.extend(['Fire Rod'] * customitemarray[7])
pool.extend(['Ice Rod'] * customitemarray[8])
pool.extend(['Bombos'] * customitemarray[9])
pool.extend(['Ether'] * customitemarray[10])
pool.extend(['Quake'] * customitemarray[11])
pool.extend(['Lamp'] * customitemarray[12])
pool.extend(['Hammer'] * customitemarray[13])
pool.extend(['Shovel'] * customitemarray[14])
pool.extend(['Ocarina'] * customitemarray[15])
pool.extend(['Bug Catching Net'] * customitemarray[16])
pool.extend(['Book of Mudora'] * customitemarray[17])
pool.extend(['Cane of Somaria'] * customitemarray[19])
pool.extend(['Cane of Byrna'] * customitemarray[20])
pool.extend(['Cape'] * customitemarray[21])
pool.extend(['Pegasus Boots'] * customitemarray[23])
pool.extend(['Power Glove'] * customitemarray[24])
pool.extend(['Titans Mitts'] * customitemarray[25])
pool.extend(['Progressive Glove'] * customitemarray[26])
pool.extend(['Flippers'] * customitemarray[27])
pool.extend(['Piece of Heart'] * customitemarray[29])
pool.extend(['Boss Heart Container'] * customitemarray[30])
pool.extend(['Sanctuary Heart Container'] * customitemarray[31])
pool.extend(['Master Sword'] * customitemarray[33])
pool.extend(['Tempered Sword'] * customitemarray[34])
pool.extend(['Golden Sword'] * customitemarray[35])
pool.extend(['Blue Shield'] * customitemarray[37])
pool.extend(['Red Shield'] * customitemarray[38])
pool.extend(['Mirror Shield'] * customitemarray[39])
pool.extend(['Progressive Shield'] * customitemarray[40])
pool.extend(['Blue Mail'] * customitemarray[41])
pool.extend(['Red Mail'] * customitemarray[42])
pool.extend(['Progressive Armor'] * customitemarray[43])
pool.extend(['Magic Upgrade (1/2)'] * customitemarray[44])
pool.extend(['Magic Upgrade (1/4)'] * customitemarray[45])
pool.extend(['Bomb Upgrade (+5)'] * customitemarray[46])
pool.extend(['Bomb Upgrade (+10)'] * customitemarray[47])
pool.extend(['Arrow Upgrade (+5)'] * customitemarray[48])
pool.extend(['Arrow Upgrade (+10)'] * customitemarray[49])
pool.extend(['Single Arrow'] * customitemarray[50])
pool.extend(['Arrows (10)'] * customitemarray[51])
pool.extend(['Single Bomb'] * customitemarray[52])
pool.extend(['Bombs (3)'] * customitemarray[53])
pool.extend(['Rupee (1)'] * customitemarray[54])
pool.extend(['Rupees (5)'] * customitemarray[55])
pool.extend(['Rupees (20)'] * customitemarray[56])
pool.extend(['Rupees (50)'] * customitemarray[57])
pool.extend(['Rupees (100)'] * customitemarray[58])
pool.extend(['Rupees (300)'] * customitemarray[59])
pool.extend(['Rupoor'] * customitemarray[60])
pool.extend(['Blue Clock'] * customitemarray[61])
pool.extend(['Green Clock'] * customitemarray[62])
pool.extend(['Red Clock'] * customitemarray[63])
pool.extend(['Progressive Bow'] * customitemarray[64])
pool.extend(['Bombs (10)'] * customitemarray[65])
pool.extend(['Triforce Piece'] * customitemarray[66])
pool.extend(['Triforce'] * customitemarray[68])
# Triforce
if customitemarray["triforce"] > total_items_to_place:
customitemarray["triforce"] = total_items_to_place
itemtotal = 0
# Bow to Silver Arrows Upgrade, including Generic Keys & Rupoors
for x in [*range(0, 66 + 1), 68, 69]:
key = CONST.CUSTOMITEMS[x]
itemtotal = itemtotal + customitemarray[key]
# Triforce
itemtotal = itemtotal + customitemarray["triforce"]
# Generic Keys
itemtotal = itemtotal + customitemarray["generickeys"]
customitems = [
"Bow", "Silver Arrows", "Blue Boomerang", "Red Boomerang", "Hookshot", "Mushroom", "Magic Powder", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", "Lamp", "Hammer", "Shovel", "Ocarina", "Bug Catching Net", "Book of Mudora", "Cane of Somaria", "Cane of Byrna", "Cape", "Pegasus Boots", "Power Glove", "Titans Mitts", "Progressive Glove", "Flippers", "Piece of Heart", "Boss Heart Container", "Sanctuary Heart Container", "Master Sword", "Tempered Sword", "Golden Sword", "Blue Shield", "Red Shield", "Mirror Shield", "Progressive Shield", "Blue Mail", "Red Mail", "Progressive Armor", "Magic Upgrade (1/2)", "Magic Upgrade (1/4)", "Bomb Upgrade (+5)", "Bomb Upgrade (+10)", "Arrow Upgrade (+5)", "Arrow Upgrade (+10)", "Single Arrow", "Arrows (10)", "Single Bomb", "Bombs (3)", "Rupee (1)", "Rupees (5)", "Rupees (20)", "Rupees (50)", "Rupees (100)", "Rupees (300)", "Rupoor", "Blue Clock", "Green Clock", "Red Clock", "Progressive Bow", "Bombs (10)", "Triforce Piece", "Triforce"
]
for customitem in customitems:
pool.extend([customitem] * customitemarray[get_custom_array_key(customitem)])
diff = difficulties[difficulty]
@@ -641,17 +645,17 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
# all bottles, since only one bottle is available
if diff.same_bottle:
thisbottle = random.choice(diff.bottles)
for _ in range(customitemarray[18]):
for _ in range(customitemarray["bottle"]):
if not diff.same_bottle:
thisbottle = random.choice(diff.bottles)
pool.append(thisbottle)
if customitemarray[66] > 0 or customitemarray[67] > 0:
treasure_hunt_count = max(min(customitemarray[67], 99), 1) #To display, count must be between 1 and 99.
if customitemarray["triforcepieces"] > 0 or customitemarray["triforcepiecesgoal"] > 0:
treasure_hunt_count = max(min(customitemarray["triforcepiecesgoal"], 99), 1) #To display, count must be between 1 and 99.
treasure_hunt_icon = 'Triforce Piece'
# Ensure game is always possible to complete here, force sufficient pieces if the player is unwilling.
if (customitemarray[66] < treasure_hunt_count) and (goal == 'triforcehunt') and (customitemarray[68] == 0):
extrapieces = treasure_hunt_count - customitemarray[66]
if (customitemarray["triforcepieces"] < treasure_hunt_count) and (goal == 'triforcehunt') and (customitemarray["triforce"] == 0):
extrapieces = treasure_hunt_count - customitemarray["triforcepieces"]
pool.extend(['Triforce Piece'] * extrapieces)
itemtotal = itemtotal + extrapieces
@@ -670,28 +674,30 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
if retro:
key_location = random.choice(['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest', 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross'])
place_item(key_location, 'Small Key (Universal)')
pool.extend(['Small Key (Universal)'] * max((customitemarray[70] - 1), 0))
pool.extend(['Small Key (Universal)'] * max((customitemarray["generickeys"] - 1), 0))
else:
pool.extend(['Small Key (Universal)'] * customitemarray[70])
pool.extend(['Small Key (Universal)'] * customitemarray["generickeys"])
else:
pool.extend(['Small Key (Universal)'] * customitemarray[70])
pool.extend(['Small Key (Universal)'] * customitemarray["generickeys"])
pool.extend(['Fighter Sword'] * customitemarray[32])
pool.extend(['Progressive Sword'] * customitemarray[36])
pool.extend(['Fighter Sword'] * customitemarray["sword1"])
pool.extend(['Progressive Sword'] * customitemarray["progressivesword"])
if shuffle == 'insanity_legacy':
place_item('Link\'s House', 'Magic Mirror')
place_item('Sanctuary', 'Moon Pearl')
pool.extend(['Magic Mirror'] * max((customitemarray[22] -1 ), 0))
pool.extend(['Moon Pearl'] * max((customitemarray[28] - 1), 0))
pool.extend(['Magic Mirror'] * max((customitemarray["mirror"] -1 ), 0))
pool.extend(['Moon Pearl'] * max((customitemarray["pearl"] - 1), 0))
else:
pool.extend(['Magic Mirror'] * customitemarray[22])
pool.extend(['Moon Pearl'] * customitemarray[28])
pool.extend(['Magic Mirror'] * customitemarray["mirror"])
pool.extend(['Moon Pearl'] * customitemarray["pearl"])
if retro:
itemtotal = itemtotal - 28 # Corrects for small keys not being in item pool in Retro Mode
if itemtotal < total_items_to_place:
pool.extend(['Nothing'] * (total_items_to_place - itemtotal))
nothings = total_items_to_place - itemtotal
print("Placing " + str(nothings) + " Nothings")
pool.extend(['Nothing'] * nothings)
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)

21
classes/constants.py Normal file
View File

@@ -0,0 +1,21 @@
CUSTOMITEMS = [
"bow", "progressivebow", "boomerang", "redmerang", "hookshot",
"mushroom", "powder", "firerod", "icerod", "bombos",
"ether", "quake", "lamp", "hammer", "shovel",
"flute", "bugnet", "book", "bottle", "somaria",
"byrna", "cape", "mirror", "boots", "powerglove",
"titansmitt", "progressiveglove", "flippers", "pearl", "heartpiece",
"heartcontainer", "sancheart", "sword1", "sword2", "sword3",
"sword4", "progressivesword", "shield1", "shield2", "shield3",
"progressiveshield", "mail2", "mail3", "progressivemail", "halfmagic",
"quartermagic", "bombsplus5", "bombsplus10", "arrowsplus5", "arrowsplus10",
"arrow1", "arrow10", "bomb1", "bomb3", "bomb10",
"rupee1", "rupee5", "rupee20", "rupee50", "rupee100",
"rupee300", "blueclock", "greenclock", "redclock", "silversupgrade",
"generickeys", "triforcepieces", "triforcepiecesgoal", "triforce", "rupoor",
"rupoorcost"
]

View File

@@ -6,6 +6,7 @@ import random
from CLI import parse_arguments, get_settings
from Main import main
from Utils import local_path, output_path, open_file
import classes.constants as CONST
import gui.widgets as widgets
@@ -178,21 +179,10 @@ def create_guiargs(parent):
internal = adjustargs[adjustarg]
setattr(guiargs,"adjust." + internal, parent.pages["adjust"].content.widgets[adjustarg].storageVar.get())
customitems = [
"bow", "progressivebow", "boomerang", "redmerang", "hookshot", "mushroom", "powder", "firerod",
"icerod", "bombos", "ether", "quake", "lamp", "hammer", "shovel",
"flute", "bugnet", "book", "bottle", "somaria", "byrna", "cape", "mirror",
"boots", "powerglove", "titansmitt", "progressiveglove", "flippers", "pearl", "heartpiece",
"heartcontainer", "sancheart", "sword1", "sword2", "sword3", "sword4", "progressivesword",
"shield1", "shield2", "shield3", "progressiveshield", "mail2",
"mail3", "progressivemail", "halfmagic", "quartermagic", "bombsplus5", "bombsplus10", "arrowsplus5", "arrowsplus10",
"arrow1", "arrow10", "bomb1", "bomb3", "bomb10", "rupee1", "rupee5", "rupee20",
"rupee50", "rupee100", "rupee300", "blueclock", "greenclock", "redclock", "silversupgrade", "generickeys",
"triforcepieces", "triforcepiecesgoal", "triforce", "rupoor", "rupoorcost"
]
guiargs.customitemarray = []
customitems = CONST.CUSTOMITEMS
guiargs.customitemarray = {}
for customitem in customitems:
guiargs.customitemarray.append(int(parent.pages["custom"].content.customWidgets[customitem].storageVar.get()))
guiargs.customitemarray[customitem] = int(parent.pages["custom"].content.customWidgets[customitem].storageVar.get())
guiargs.sprite = parent.pages["randomizer"].pages["gameoptions"].widgets["sprite"]["spriteObject"]
guiargs.randomSprite = parent.randomSprite.get()

View File

@@ -3,6 +3,8 @@ import gui.widgets as widgets
import json
import os
import classes.constants as CONST
def custom_page(top,parent):
# Custom Item Pool
self = ttk.Frame(parent)
@@ -46,8 +48,7 @@ def custom_page(top,parent):
for key in dictWidgets:
self.customWidgets[key] = dictWidgets[key]
keys = list(self.customWidgets.keys())
for i in range(0, len(keys)):
self.customWidgets[keys[i]].storageVar.set(top.settings["customitemarray"][i])
for key in CONST.CUSTOMITEMS:
self.customWidgets[key].storageVar.set(top.settings["customitemarray"][key])
return self