Various Item pool fixes
* Pedestal goal always left a spare item in the pool, unless vanilla swords was also selected * extra items for the pool can now be given dynamically based on items still needed. * easy item pool + swordless gets 4 bows, not 2 (weird combo, but ok) * add some item pool unittests * add easy item pool to CLI and GUI
This commit is contained in:
parent
8759ab83bc
commit
01ace95c32
|
@ -91,9 +91,10 @@ def parse_arguments(argv, no_defaults=False):
|
|||
type=lambda value: min(max(int(value), 1), 90),
|
||||
help='''Set Triforce Pieces required to win a Triforce Hunt''')
|
||||
parser.add_argument('--difficulty', default=defval('normal'), const='normal', nargs='?',
|
||||
choices=['normal', 'hard', 'expert'],
|
||||
choices=['easy', 'normal', 'hard', 'expert'],
|
||||
help='''\
|
||||
Select game difficulty. Affects available itempool. (default: %(default)s)
|
||||
Easy: An easier setting with some equipment duplicated and increased health.
|
||||
Normal: Normal difficulty.
|
||||
Hard: A harder setting with less equipment and reduced health.
|
||||
Expert: A harder yet setting with minimum equipment and health.
|
||||
|
|
2
Gui.py
2
Gui.py
|
@ -272,7 +272,7 @@ def guiMain(args=None):
|
|||
difficultyFrame = Frame(drowDownFrame)
|
||||
difficultyVar = StringVar()
|
||||
difficultyVar.set('normal')
|
||||
difficultyOptionMenu = OptionMenu(difficultyFrame, difficultyVar, 'normal', 'hard', 'expert')
|
||||
difficultyOptionMenu = OptionMenu(difficultyFrame, difficultyVar, 'easy', 'normal', 'hard', 'expert')
|
||||
difficultyOptionMenu.pack(side=RIGHT)
|
||||
difficultyLabel = Label(difficultyFrame, text='Difficulty: item pool')
|
||||
difficultyLabel.pack(side=LEFT)
|
||||
|
|
56
ItemList.py
56
ItemList.py
|
@ -23,12 +23,12 @@ normalbottles = ['Bottle', 'Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bott
|
|||
hardbottles = ['Bottle', 'Bottle (Red Potion)', 'Bottle (Green Potion)', 'Bottle (Blue Potion)', 'Bottle (Bee)',
|
||||
'Bottle (Good Bee)']
|
||||
|
||||
easybaseitems = (['Sanctuary Heart Container', "Lamp"] + ['Rupees (300)'] * 4 + ['Magic Upgrade (1/2)'] * 2 +
|
||||
['Boss Heart Container'] * 10 + ['Piece of Heart'] * 12)
|
||||
easyextra = ['Piece of Heart'] * 12 + ['Rupees (300)']
|
||||
easyfirst15extra = ['Rupees (100)'] + ['Arrows (10)'] * 7 + ['Bombs (3)'] * 7
|
||||
easysecond10extra = ['Bombs (3)'] * 7 + ['Rupee (1)', 'Rupees (50)', 'Bombs (10)']
|
||||
easythird5extra = ['Rupees (50)'] * 2 + ['Bombs (3)'] * 2 + ['Arrows (10)']
|
||||
easybaseitems = (['Sanctuary Heart Container', "Lamp"] + ['Rupees (300)'] * 5 + ['Magic Upgrade (1/2)'] * 2 +
|
||||
['Boss Heart Container'] * 10 + ['Piece of Heart'] * 24)
|
||||
easyfirst15extra = ['Piece of Heart'] * 12 + ['Rupees (300)'] * 3
|
||||
easysecond15extra = ['Rupees (100)'] + ['Arrows (10)'] * 7 + ['Bombs (3)'] * 7
|
||||
easythird10extra = ['Bombs (3)'] * 7 + ['Rupee (1)', 'Rupees (50)', 'Bombs (10)']
|
||||
easyfourth5extra = ['Rupees (50)'] * 2 + ['Bombs (3)'] * 2 + ['Arrows (10)']
|
||||
easyfinal25extra = ['Rupees (50)'] * 4 + ['Rupees (20)'] * 14 + ['Rupee (1)'] + ['Arrows (10)'] * 4 + ['Rupees (5)'] * 2
|
||||
|
||||
normalbaseitems = (['Magic Upgrade (1/2)', 'Single Arrow', 'Sanctuary Heart Container', 'Arrows (10)', 'Bombs (10)'] +
|
||||
|
@ -66,18 +66,17 @@ difficulties = {
|
|||
progressivebow=["Progressive Bow"] * 2,
|
||||
basicbow=['Bow', 'Silver Bow'] * 2,
|
||||
timedohko=['Green Clock'] * 25,
|
||||
timedother=['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 5,
|
||||
# +5 more Red Clocks if there is room
|
||||
timedother=['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
triforcehunt=['Triforce Piece'] * 30,
|
||||
retro=['Small Key (Universal)'] * 27,
|
||||
extras=[easyextra, easyfirst15extra, easysecond10extra, easythird5extra, easyfinal25extra],
|
||||
retro=['Small Key (Universal)'] * 28,
|
||||
extras=[easyfirst15extra, easysecond15extra, easythird10extra, easyfourth5extra, easyfinal25extra],
|
||||
progressive_sword_limit=8,
|
||||
progressive_shield_limit=6,
|
||||
progressive_armor_limit=2,
|
||||
progressive_armor_limit=4,
|
||||
progressive_bow_limit=4,
|
||||
progressive_bottle_limit=8,
|
||||
boss_heart_container_limit=10,
|
||||
heart_piece_limit=24,
|
||||
heart_piece_limit=36,
|
||||
),
|
||||
'normal': Difficulty(
|
||||
baseitems=normalbaseitems,
|
||||
|
@ -157,13 +156,14 @@ difficulties = {
|
|||
progressive_shield_limit=1,
|
||||
progressive_armor_limit=0,
|
||||
progressive_bow_limit=1,
|
||||
progressive_bottle_limit = 4,
|
||||
boss_heart_container_limit = 2,
|
||||
heart_piece_limit = 8,
|
||||
progressive_bottle_limit=4,
|
||||
boss_heart_container_limit=2,
|
||||
heart_piece_limit=8,
|
||||
),
|
||||
}
|
||||
|
||||
def generate_itempool(world, player):
|
||||
|
||||
def generate_itempool(world, player: int):
|
||||
if world.difficulty[player] not in difficulties:
|
||||
raise NotImplementedError(f"Diffulty {world.difficulty[player]}")
|
||||
if world.goal[player] not in {'ganon', 'pedestal', 'dungeons', 'triforcehunt', 'localtriforcehunt',
|
||||
|
@ -465,14 +465,14 @@ def get_pool_core(world, player: int):
|
|||
if logic in {'owglitches', 'nologic'} and world.glitch_boots[player]:
|
||||
precollected_items.append('Pegasus Boots')
|
||||
pool.remove('Pegasus Boots')
|
||||
pool.extend(['Rupees (20)'])
|
||||
pool.append('Rupees (20)')
|
||||
|
||||
if want_progressives():
|
||||
pool.extend(progressivegloves)
|
||||
else:
|
||||
pool.extend(basicgloves)
|
||||
|
||||
# insanity shuffle doesn't have fake LW/DW logic so for now guaranteed Mirror and Moon Pearl at the start
|
||||
# insanity legacy shuffle doesn't have fake LW/DW logic so for now guaranteed Mirror and Moon Pearl at the start
|
||||
if shuffle == 'insanity_legacy':
|
||||
place_item('Link\'s House', 'Magic Mirror')
|
||||
place_item('Sanctuary', 'Moon Pearl')
|
||||
|
@ -511,7 +511,10 @@ def get_pool_core(world, player: int):
|
|||
elif swords != 'swordless':
|
||||
pool.extend(diff.basicbow)
|
||||
else:
|
||||
pool.extend(['Bow', 'Silver Bow'])
|
||||
swordless_bows = ['Bow', 'Silver Bow']
|
||||
if difficulty == "easy":
|
||||
swordless_bows *= 2
|
||||
pool.extend(swordless_bows)
|
||||
|
||||
if swords == 'swordless':
|
||||
pool.extend(diff.swordless)
|
||||
|
@ -557,17 +560,22 @@ def get_pool_core(world, player: int):
|
|||
treasure_hunt_icon = 'Triforce Piece'
|
||||
|
||||
for extra in diff.extras:
|
||||
if extraitems > 0:
|
||||
if extraitems >= len(extra):
|
||||
pool.extend(extra)
|
||||
extraitems -= len(extra)
|
||||
elif extraitems > 0:
|
||||
pool.extend(world.random.sample(extra, extraitems))
|
||||
break
|
||||
|
||||
if goal == 'pedestal' and swords != 'vanilla':
|
||||
place_item('Master Sword Pedestal', 'Triforce')
|
||||
pool.remove("Rupees (20)")
|
||||
|
||||
if retro:
|
||||
pool = [item.replace('Single Arrow','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrows (10)','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+5)','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+10)','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Single Arrow', 'Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrows (10)', 'Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+5)', 'Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Arrow Upgrade (+10)', 'Rupees (5)') for item in pool]
|
||||
pool.extend(diff.retro)
|
||||
if mode == 'standard':
|
||||
key_location = world.random.choice(
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
from ItemList import difficulties
|
||||
from test.TestBase import TestBase
|
||||
|
||||
base_items = 43
|
||||
extra_counts = (15, 15, 10, 5, 25)
|
||||
|
||||
|
||||
class TestDifficulty(TestBase):
|
||||
pass
|
||||
|
||||
|
||||
def build_difficulty_test(difficulty):
|
||||
# binds difficulty to definition local scope
|
||||
def build_for(function):
|
||||
def wrapped(self, *args):
|
||||
return function(self, difficulty, *args)
|
||||
|
||||
return wrapped
|
||||
|
||||
return build_for
|
||||
|
||||
|
||||
def build_dynamic_tests():
|
||||
for name, difficulty in difficulties.items():
|
||||
|
||||
@build_difficulty_test(difficulty)
|
||||
def test_dyn_difficulty(self, difficulty):
|
||||
base = len(difficulty.baseitems)
|
||||
self.assertEqual(base, base_items)
|
||||
|
||||
setattr(TestDifficulty, f"testCountBase{name}", test_dyn_difficulty)
|
||||
|
||||
@build_difficulty_test(difficulty)
|
||||
def test_dyn_difficulty(self, difficulty):
|
||||
self.assertEqual(len(extra_counts), len(difficulty.extras))
|
||||
|
||||
setattr(TestDifficulty, f"testCountExtra{name}", test_dyn_difficulty)
|
||||
|
||||
@build_difficulty_test(difficulty)
|
||||
def test_dyn_difficulty(self, difficulty):
|
||||
for i, extras in enumerate(extra_counts):
|
||||
self.assertEqual(extras, len(difficulty.extras[i]))
|
||||
|
||||
setattr(TestDifficulty, f"testCountExtras{name}", test_dyn_difficulty)
|
||||
|
||||
|
||||
build_dynamic_tests()
|
Loading…
Reference in New Issue