Bomblogic added
This commit is contained in:
@@ -114,6 +114,7 @@ class World(object):
|
||||
set_player_attr('compassshuffle', False)
|
||||
set_player_attr('keyshuffle', False)
|
||||
set_player_attr('bigkeyshuffle', False)
|
||||
set_player_attr('bomblogic', False)
|
||||
set_player_attr('difficulty_requirements', None)
|
||||
set_player_attr('boss_shuffle', 'none')
|
||||
set_player_attr('enemy_shuffle', 'none')
|
||||
@@ -686,8 +687,7 @@ class CollectionState(object):
|
||||
|
||||
# In the future, this can be used to check if the player starts without bombs
|
||||
def can_use_bombs(self, player):
|
||||
StartingBombs = True
|
||||
return StartingBombs or self.has('Bomb Upgrade (+10)', player)
|
||||
return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player))
|
||||
|
||||
def can_hit_crystal(self, player):
|
||||
return (self.can_use_bombs(player)
|
||||
@@ -2013,6 +2013,7 @@ class Spoiler(object):
|
||||
'logic': self.world.logic,
|
||||
'mode': self.world.mode,
|
||||
'retro': self.world.retro,
|
||||
'bomblogic': self.world.bomblogic,
|
||||
'weapons': self.world.swords,
|
||||
'goal': self.world.goal,
|
||||
'shuffle': self.world.shuffle,
|
||||
@@ -2111,6 +2112,7 @@ class Spoiler(object):
|
||||
outfile.write('Experimental: %s\n' % ('Yes' if self.metadata['experimental'][player] else 'No'))
|
||||
outfile.write('Key Drops shuffled: %s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No'))
|
||||
outfile.write(f"Shopsanity: {'Yes' if self.metadata['shopsanity'][player] else 'No'}\n")
|
||||
outfile.write('Bomblogic: %s\n' % ('Yes' if self.metadata['bomblogic'][player] else 'No'))
|
||||
if self.doors:
|
||||
outfile.write('\n\nDoors:\n\n')
|
||||
outfile.write('\n'.join(
|
||||
|
||||
2
CLI.py
2
CLI.py
@@ -96,6 +96,7 @@ def parse_cli(argv, no_defaults=False):
|
||||
for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality',
|
||||
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
||||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
||||
'bomblogic',
|
||||
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max',
|
||||
'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'pseudoboots',
|
||||
'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
|
||||
@@ -126,6 +127,7 @@ def parse_settings():
|
||||
settings = {
|
||||
"lang": "en",
|
||||
"retro": False,
|
||||
"bomblogic": False,
|
||||
"mode": "open",
|
||||
"logic": "noglitches",
|
||||
"goal": "ganon",
|
||||
|
||||
25
ItemList.py
25
ItemList.py
@@ -37,7 +37,7 @@ Difficulty = namedtuple('Difficulty',
|
||||
['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield',
|
||||
'basicshield', 'progressivearmor', 'basicarmor', 'swordless',
|
||||
'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother',
|
||||
'retro',
|
||||
'retro', 'bomblogic',
|
||||
'extras', 'progressive_sword_limit', 'progressive_shield_limit',
|
||||
'progressive_armor_limit', 'progressive_bottle_limit',
|
||||
'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit'])
|
||||
@@ -61,6 +61,7 @@ difficulties = {
|
||||
timedohko = ['Green Clock'] * 25,
|
||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
retro = ['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10,
|
||||
bomblogic = ['Bomb Upgrade (+10)'] * 2,
|
||||
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
|
||||
progressive_sword_limit = 4,
|
||||
progressive_shield_limit = 3,
|
||||
@@ -86,6 +87,7 @@ difficulties = {
|
||||
timedohko = ['Green Clock'] * 25,
|
||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15,
|
||||
bomblogic = ['Bomb Upgrade (+10)'] * 2,
|
||||
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
|
||||
progressive_sword_limit = 3,
|
||||
progressive_shield_limit = 2,
|
||||
@@ -111,6 +113,7 @@ difficulties = {
|
||||
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
|
||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15,
|
||||
bomblogic = ['Bomb Upgrade (+10)'] * 2,
|
||||
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
|
||||
progressive_sword_limit = 2,
|
||||
progressive_shield_limit = 1,
|
||||
@@ -251,10 +254,10 @@ 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)
|
||||
(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.bomblogic[player], world.customitemarray)
|
||||
world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999)
|
||||
else:
|
||||
(pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player], world.logic[player])
|
||||
(pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.bomblogic[player], world.doorShuffle[player], world.logic[player])
|
||||
|
||||
if player in world.pool_adjustment.keys():
|
||||
amt = world.pool_adjustment[player]
|
||||
@@ -284,7 +287,7 @@ def generate_itempool(world, player):
|
||||
if item in ['Hammer', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']:
|
||||
if item not in possible_weapons:
|
||||
possible_weapons.append(item)
|
||||
if item in ['Bombs (10)']:
|
||||
if not world.bomblogic[player] and item in ['Bombs (10)']:
|
||||
if item not in possible_weapons and world.doorShuffle[player] != 'crossed':
|
||||
possible_weapons.append(item)
|
||||
starting_weapon = random.choice(possible_weapons)
|
||||
@@ -709,7 +712,7 @@ rupee_chart = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)'
|
||||
'Rupees (100)': 100, 'Rupees (300)': 300}
|
||||
|
||||
|
||||
def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, door_shuffle, logic):
|
||||
def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, bomblogic, door_shuffle, logic):
|
||||
pool = []
|
||||
placed_items = {}
|
||||
precollected_items = []
|
||||
@@ -756,6 +759,11 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer,
|
||||
diff = difficulties[difficulty]
|
||||
pool.extend(diff.baseitems)
|
||||
|
||||
if bomblogic:
|
||||
pool = [item.replace('Bomb Upgrade (+5)','Rupees (5)') for item in pool]
|
||||
pool = [item.replace('Bomb Upgrade (+10)','Rupees (5)') for item in pool]
|
||||
pool.extend(diff.bomblogic)
|
||||
|
||||
# expert+ difficulties produce the same contents for
|
||||
# all bottles, since only one bottle is available
|
||||
if diff.same_bottle:
|
||||
@@ -850,7 +858,7 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer,
|
||||
pool.extend(['Small Key (Universal)'])
|
||||
return (pool, placed_items, precollected_items, clock_mode, lamps_needed_for_dark_rooms)
|
||||
|
||||
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray):
|
||||
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bomblogic, customitemarray):
|
||||
if isinstance(customitemarray,dict) and 1 in customitemarray:
|
||||
customitemarray = customitemarray[1]
|
||||
pool = []
|
||||
@@ -966,8 +974,9 @@ def test():
|
||||
for shuffle in ['full', 'insanity_legacy']:
|
||||
for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']:
|
||||
for retro in [True, False]:
|
||||
for bomblogic in [True, False]:
|
||||
for door_shuffle in ['basic', 'crossed', 'vanilla']:
|
||||
out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, door_shuffle, logic)
|
||||
out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, bomblogic, door_shuffle, logic)
|
||||
count = len(out[0]) + len(out[1])
|
||||
|
||||
correct_count = total_items_to_place
|
||||
@@ -977,7 +986,7 @@ def test():
|
||||
if retro:
|
||||
correct_count += 28
|
||||
try:
|
||||
assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro))
|
||||
assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bomblogic))
|
||||
except AssertionError as e:
|
||||
print(e)
|
||||
|
||||
|
||||
2
Items.py
2
Items.py
@@ -81,7 +81,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
|
||||
'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'),
|
||||
'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'),
|
||||
'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'),
|
||||
'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'),
|
||||
'Bomb Upgrade (+10)': (True, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'),
|
||||
'Bomb Upgrade (+5)': (False, False, None, 0x51, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'),
|
||||
'Blue Mail': (False, True, None, 0x22, 50, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'),
|
||||
'Red Mail': (False, True, None, 0x23, 100, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'),
|
||||
|
||||
2
Main.py
2
Main.py
@@ -69,6 +69,7 @@ def main(args, seed=None, fish=None):
|
||||
world.compassshuffle = args.compassshuffle.copy()
|
||||
world.keyshuffle = args.keyshuffle.copy()
|
||||
world.bigkeyshuffle = args.bigkeyshuffle.copy()
|
||||
world.bomblogic = args.bomblogic.copy()
|
||||
world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)}
|
||||
world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)}
|
||||
world.crystals_ganon_orig = args.crystals_ganon.copy()
|
||||
@@ -372,6 +373,7 @@ def copy_world(world):
|
||||
ret.compassshuffle = world.compassshuffle.copy()
|
||||
ret.keyshuffle = world.keyshuffle.copy()
|
||||
ret.bigkeyshuffle = world.bigkeyshuffle.copy()
|
||||
ret.bomblogic = world.bomblogic.copy()
|
||||
ret.crystals_needed_for_ganon = world.crystals_needed_for_ganon.copy()
|
||||
ret.crystals_needed_for_gt = world.crystals_needed_for_gt.copy()
|
||||
ret.crystals_ganon_orig = world.crystals_ganon_orig.copy()
|
||||
|
||||
@@ -176,6 +176,8 @@ def roll_settings(weights):
|
||||
ret.retro = True
|
||||
ret.retro = get_choice('retro') == 'on' # this overrides world_state if used
|
||||
|
||||
ret.bomblogic = get_choice('bomblogic') == 'on'
|
||||
|
||||
ret.hints = get_choice('hints') == 'on'
|
||||
|
||||
ret.swords = {'randomized': 'random',
|
||||
|
||||
7
Rom.py
7
Rom.py
@@ -1032,7 +1032,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_bytes(0x184000, [
|
||||
# original_item, limit, replacement_item, filler
|
||||
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
|
||||
0x51, 0x06, 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade
|
||||
0x51, 0x00 if world.bomblogic[player] else 0x06, 0x31 if world.bomblogic[player] else 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade. If bomblogic -> turns into Bombs (10)
|
||||
0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade
|
||||
0x58, 0x01, 0x36 if world.retro[player] else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode)
|
||||
0x3E, difficulty.boss_heart_container_limit, 0x47, 0xff, # boss heart -> green 20
|
||||
@@ -1169,6 +1169,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
equip[0x36C] = 0x18
|
||||
equip[0x36D] = 0x18
|
||||
equip[0x379] = 0x68
|
||||
if world.bomblogic[player]:
|
||||
starting_max_bombs = 0
|
||||
else:
|
||||
starting_max_bombs = 10
|
||||
starting_max_arrows = 30
|
||||
|
||||
@@ -1461,7 +1464,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_bytes(0x180188, [0, 0, 10]) # Zelda respawn refills (magic, bombs, arrows)
|
||||
rom.write_bytes(0x18018B, [0, 0, 10]) # Mantle respawn refills (magic, bombs, arrows)
|
||||
bow_max, bow_small = 70, 10
|
||||
elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']:
|
||||
elif uncle_location.item is not None and uncle_location.item.name in ['Bomb Upgrade (+10)' if world.bomblogic[player] else 'Bombs (10)']:
|
||||
rom.write_byte(0x18004E, 2) # Escape Fill (bombs)
|
||||
rom.write_bytes(0x180185, [0, 50, 0]) # Uncle respawn refills (magic, bombs, arrows)
|
||||
rom.write_bytes(0x180188, [0, 3, 0]) # Zelda respawn refills (magic, bombs, arrows)
|
||||
|
||||
2
Rules.py
2
Rules.py
@@ -1160,7 +1160,7 @@ def standard_rules(world, player):
|
||||
|
||||
def bomb_escape_rule():
|
||||
loc = world.get_location("Link's Uncle", player)
|
||||
return loc.item and loc.item.name == 'Bombs (10)'
|
||||
return loc.item and loc.item.name in ['Bomb Upgrade (+10)' if world.bomblogic[player] else 'Bombs (10)']
|
||||
|
||||
def standard_escape_rule(state):
|
||||
return state.can_kill_most_things(player) or bomb_escape_rule()
|
||||
|
||||
@@ -220,6 +220,10 @@
|
||||
"type": "bool",
|
||||
"help": "suppress"
|
||||
},
|
||||
"bomblogic": {
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
},
|
||||
"retro": {
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
|
||||
@@ -263,6 +263,7 @@
|
||||
"and a few other little things make this more like Zelda-1. (default: %(default)s)"
|
||||
],
|
||||
"pseudoboots": [ " Players starts with pseudo boots that allow dashing but no item checks (default: %(default)s"],
|
||||
"bomblogic": ["Start with 0 bomb capacity. Two capacity upgrades (+10) are added to the pool (default: %(default)s)" ],
|
||||
"startinventory": [ "Specifies a list of items that will be in your starting inventory (separated by commas). (default: %(default)s)" ],
|
||||
"usestartinventory": [ "Toggle usage of Starting Inventory." ],
|
||||
"custom": [ "Not supported." ],
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
"randomizer.item.hints": "Include Helpful Hints",
|
||||
"randomizer.item.retro": "Retro mode (universal keys)",
|
||||
"randomizer.item.pseudoboots": "Start with Pseudo Boots",
|
||||
"randomizer.item.bomblogic": "Bomblogic",
|
||||
|
||||
"randomizer.item.worldstate": "World State",
|
||||
"randomizer.item.worldstate.standard": "Standard",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"checkboxes": {
|
||||
"retro": { "type": "checkbox" },
|
||||
"bomblogic": { "type": "checkbox" },
|
||||
"shopsanity": { "type": "checkbox" },
|
||||
"hints": {
|
||||
"type": "checkbox"
|
||||
|
||||
@@ -57,6 +57,7 @@ SETTINGSTOPROCESS = {
|
||||
"item": {
|
||||
"hints": "hints",
|
||||
"retro": "retro",
|
||||
"bomblogic": "bomblogic",
|
||||
"shopsanity": "shopsanity",
|
||||
"pseudoboots": "pseudoboots",
|
||||
"worldstate": "mode",
|
||||
|
||||
Reference in New Issue
Block a user