LttP, beemizer: support fine-tuned trap replacements (#113)

* update beemizer logic to separate replacement chance and single vs trap chance

* convert beemizer options to new style
This commit is contained in:
Adam Ziegler 2021-11-03 05:34:11 +00:00 committed by GitHub
parent cb8da2e757
commit 583819c4ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 172 additions and 97 deletions

View File

@ -103,7 +103,8 @@ class MultiWorld():
set_player_attr('boss_shuffle', 'none') set_player_attr('boss_shuffle', 'none')
set_player_attr('enemy_health', 'default') set_player_attr('enemy_health', 'default')
set_player_attr('enemy_damage', 'default') set_player_attr('enemy_damage', 'default')
set_player_attr('beemizer', 0) set_player_attr('beemizer_total_chance', 0)
set_player_attr('beemizer_trap_chance', 0)
set_player_attr('escape_assist', []) set_player_attr('escape_assist', [])
set_player_attr('open_pyramid', False) set_player_attr('open_pyramid', False)
set_player_attr('treasure_hunt_icon', 'Triforce Piece') set_player_attr('treasure_hunt_icon', 'Triforce Piece')
@ -1248,7 +1249,6 @@ class Spoiler():
outfile.write('Boss shuffle: %s\n' % self.world.boss_shuffle[player]) outfile.write('Boss shuffle: %s\n' % self.world.boss_shuffle[player])
outfile.write('Enemy health: %s\n' % self.world.enemy_health[player]) outfile.write('Enemy health: %s\n' % self.world.enemy_health[player])
outfile.write('Enemy damage: %s\n' % self.world.enemy_damage[player]) outfile.write('Enemy damage: %s\n' % self.world.enemy_damage[player])
outfile.write('Beemizer: %s\n' % self.world.beemizer[player])
outfile.write('Prize shuffle %s\n' % outfile.write('Prize shuffle %s\n' %
self.world.shuffle_prizes[player]) self.world.shuffle_prizes[player])
if self.entrances: if self.entrances:

View File

@ -634,8 +634,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
ret.enemy_health = get_choice_legacy('enemy_health', weights) ret.enemy_health = get_choice_legacy('enemy_health', weights)
ret.beemizer = int(get_choice_legacy('beemizer', weights, 0))
ret.timer = {'none': False, ret.timer = {'none': False,
None: False, None: False,
False: False, False: False,

View File

@ -59,7 +59,8 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
world.boss_shuffle = args.shufflebosses.copy() world.boss_shuffle = args.shufflebosses.copy()
world.enemy_health = args.enemy_health.copy() world.enemy_health = args.enemy_health.copy()
world.enemy_damage = args.enemy_damage.copy() world.enemy_damage = args.enemy_damage.copy()
world.beemizer = args.beemizer.copy() world.beemizer_total_chance = args.beemizer_total_chance.copy()
world.beemizer_trap_chance = args.beemizer_trap_chance.copy()
world.timer = args.timer.copy() world.timer = args.timer.copy()
world.countdown_start_time = args.countdown_start_time.copy() world.countdown_start_time = args.countdown_start_time.copy()
world.red_clock_time = args.red_clock_time.copy() world.red_clock_time = args.red_clock_time.copy()

View File

@ -1164,41 +1164,79 @@
} }
} }
}, },
"beemizer": { "beemizer_total_chance": {
"keyString": "beemizer", "keyString": "beemizer_total_chance",
"friendlyName": "Beemizer", "friendlyName": "Beemizer - Total Chance",
"description": "Remove non-health items from the global item pool and replace them with single bees and bee traps.", "description": "Chance to replace junk-fill items in the global item pool with single bees and bee traps.",
"inputType": "range", "inputType": "range",
"subOptions": { "subOptions": {
"0": { "0": {
"keyString": "beemizer.0", "keyString": "beemizer_total_chance.0",
"friendlyName": "Level 0", "friendlyName": "Level 0",
"description": "No bee traps are placed.", "description": "No bee traps are placed.",
"defaultValue": 50 "defaultValue": 50
}, },
"1": { "25": {
"keyString": "beemizer.1", "keyString": "beemizer_total_chance.25",
"friendlyName": "Level 1", "friendlyName": "Level 1",
"description": "25% of rupees, bombs and arrows are replaced with bees, of which 60% are traps and 40% single bees", "description": "25% chance for each junk-fill item (rupees, bombs and arrows) to be replaced with bees.",
"defaultValue": 1 "defaultValue": 0
}, },
"2": { "50": {
"keyString": "beemizer.2", "keyString": "beemizer_total_chance.50",
"friendlyName": "Level 2", "friendlyName": "Level 2",
"description": "50% of rupees, bombs and arrows are replaced with bees, of which 70% are traps and 30% single bees", "description": "50% chance for each junk-fill item (rupees, bombs and arrows) to be replaced with bees.",
"defaultValue": 2 "defaultValue": 0
}, },
"3": { "75": {
"keyString": "beemizer.3", "keyString": "beemizer_total_chance.75",
"friendlyName": "Level 3", "friendlyName": "Level 3",
"description": "75% of rupees, bombs and arrows are replaced with bees, of which 80% are traps and 20% single bees", "description": "75% chance for each junk-fill item (rupees, bombs and arrows) to be replaced with bees.",
"defaultValue": 3 "defaultValue": 0
}, },
"4": { "100": {
"keyString": "beemizer.4", "keyString": "beemizer_total_chance.100",
"friendlyName": "Level 4", "friendlyName": "Level 4",
"description": "100% of rupees, bombs and arrows are replaced with bees, of which 90% are traps and 10% single bees", "description": "All junk-fill items (rupees, bombs and arrows) are replaced with bees.",
"defaultValue": 4 "defaultValue": 0
}
}
},
"beemizer_trap_chance": {
"keyString": "beemizer_trap_chance",
"friendlyName": "Beemizer - Trap Chance",
"description": "Chance that replaced junk-fill items are bee traps.",
"inputType": "range",
"subOptions": {
"60": {
"keyString": "beemizer_trap_chance.60",
"friendlyName": "Level 0",
"description": "60% chance for each beemizer replacement to be a trap (40% chance of a single bee).",
"defaultValue": 50
},
"70": {
"keyString": "beemizer_trap_chance.70",
"friendlyName": "Level 1",
"description": "70% chance for each beemizer replacement to be a trap (30% chance of a single bee).",
"defaultValue": 0
},
"80": {
"keyString": "beemizer_trap_chance.80",
"friendlyName": "Level 2",
"description": "80% chance for each beemizer replacement to be a trap (20% chance of a single bee).",
"defaultValue": 0
},
"90": {
"keyString": "beemizer_trap_chance.90",
"friendlyName": "Level 3",
"description": "90% chance for each beemizer replacement to be a trap (10% chance of a single bee).",
"defaultValue": 0
},
"100": {
"keyString": "beemizer_trap_chance.100",
"friendlyName": "Level 4",
"description": "All beemizer replacements are traps (no single bees).",
"defaultValue": 0
} }
} }
}, },

View File

@ -226,12 +226,19 @@ pot_shuffle:
'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile 'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile
'off': 50 # Default pot item locations 'off': 50 # Default pot item locations
### End of Enemizer Section ### ### End of Enemizer Section ###
beemizer: # Remove items from the global item pool and replace them with single bees and bee traps # can add weights for any whole number between 0 and 100
0: 50 # No bee traps are placed beemizer_total_chance: # Remove items from the global item pool and replace them with single bees (fill bottles) and bee traps
1: 0 # 25% of rupees, bombs and arrows are replaced with bees, of which 60% are traps and 40% single bees 0: 50 # No junk fill items are replaced (Beemizer is off)
2: 0 # 50% of rupees, bombs and arrows are replaced with bees, of which 70% are traps and 30% single bees 25: 0 # 25% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees
3: 0 # 75% of rupees, bombs and arrows are replaced with bees, of which 80% are traps and 20% single bees 50: 0 # 50% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees
4: 0 # 100% of rupees, bombs and arrows are replaced with bees, of which 90% are traps and 10% single bees 75: 0 # 75% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees
100: 0 # All junk fill items (rupees, bombs and arrows) are replaced with bees
beemizer_trap_chance:
60: 50 # 60% chance for each beemizer replacement to be a trap, 40% chance to be a single bee
70: 0 # 70% chance for each beemizer replacement to be a trap, 30% chance to be a single bee
80: 0 # 80% chance for each beemizer replacement to be a trap, 20% chance to be a single bee
90: 0 # 90% chance for each beemizer replacement to be a trap, 10% chance to be a single bee
100: 0 # All beemizer replacements are traps
### Shop Settings ### ### Shop Settings ###
shop_shuffle_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl) shop_shuffle_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl)
0: 50 0: 50

View File

@ -481,13 +481,20 @@ A Link to the Past:
'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile 'on': 0 # Keys, items, and buttons hidden under pots in dungeons are shuffled with other pots in their supertile
'off': 50 # Default pot item locations 'off': 50 # Default pot item locations
### End of Enemizer Section ### ### End of Enemizer Section ###
beemizer: # Remove items from the global item pool and replace them with single bees (fill bottles) and bee traps ### Beemizer ###
0: 50 # No bee traps are placed # can add weights for any whole number between 0 and 100
1: 0 # 25% of rupees, bombs and arrows are replaced with bees, of which 60% are traps and 40% single bees beemizer_total_chance: # Remove items from the global item pool and replace them with single bees (fill bottles) and bee traps
2: 0 # 50% of rupees, bombs and arrows are replaced with bees, of which 70% are traps and 30% single bees 0: 50 # No junk fill items are replaced (Beemizer is off)
3: 0 # 75% of rupees, bombs and arrows are replaced with bees, of which 80% are traps and 20% single bees 25: 0 # 25% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees
4: 0 # 100% of rupees, bombs and arrows are replaced with bees, of which 90% are traps and 10% single bees 50: 0 # 50% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees
5: 0 # 100% of rupees, bombs and arrows are replaced with bees, of which 100% are traps and 0% single bees 75: 0 # 75% chance for each junk fill item (rupees, bombs and arrows) to be replaced with bees
100: 0 # All junk fill items (rupees, bombs and arrows) are replaced with bees
beemizer_trap_chance:
60: 50 # 60% chance for each beemizer replacement to be a trap, 40% chance to be a single bee
70: 0 # 70% chance for each beemizer replacement to be a trap, 30% chance to be a single bee
80: 0 # 80% chance for each beemizer replacement to be a trap, 20% chance to be a single bee
90: 0 # 90% chance for each beemizer replacement to be a trap, 10% chance to be a single bee
100: 0 # All beemizer replacements are traps
### Shop Settings ### ### Shop Settings ###
shop_item_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl) shop_item_slots: # Maximum amount of shop slots to be filled with regular item pool items (such as Moon Pearl)
0: 50 0: 50

View File

@ -221,7 +221,8 @@ def parse_arguments(argv, no_defaults=False):
parser.add_argument('--enemy_health', default=defval('default'), parser.add_argument('--enemy_health', default=defval('default'),
choices=['default', 'easy', 'normal', 'hard', 'expert']) choices=['default', 'easy', 'normal', 'hard', 'expert'])
parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos']) parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos'])
parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4)) parser.add_argument('--beemizer_total_chance', default=defval(0), type=lambda value: min(max(int(value), 0), 100))
parser.add_argument('--beemizer_trap_chance', default=defval(0), type=lambda value: min(max(int(value), 0), 100))
parser.add_argument('--shop_shuffle', default='', help='''\ parser.add_argument('--shop_shuffle', default='', help='''\
combine letters for options: combine letters for options:
g: generate default inventories for light and dark world shops, and unique shops g: generate default inventories for light and dark world shops, and unique shops
@ -273,7 +274,7 @@ def parse_arguments(argv, no_defaults=False):
for name in ['logic', 'mode', 'goal', 'difficulty', 'item_functionality', for name in ['logic', 'mode', 'goal', 'difficulty', 'item_functionality',
'shuffle', 'open_pyramid', 'timer', 'shuffle', 'open_pyramid', 'timer',
'countdown_start_time', 'red_clock_time', 'blue_clock_time', 'green_clock_time', 'countdown_start_time', 'red_clock_time', 'blue_clock_time', 'green_clock_time',
'beemizer', 'beemizer_total_chance', 'beemizer_trap_chance',
'shufflebosses', 'enemy_health', 'enemy_damage', 'shufflebosses', 'enemy_health', 'enemy_damage',
'sprite', 'sprite',
"triforce_pieces_available", "triforce_pieces_available",

View File

@ -1,19 +1,20 @@
import typing import typing
def GetBeemizerItem(world, player, item): def GetBeemizerItem(world, player, item):
item_name = item if isinstance(item, str) else item.name item_name = item if isinstance(item, str) else item.name
if world.beemizer[player] and item_name in trap_replaceable:
if world.random.random() < world.beemizer[player] * 0.25: if item_name not in trap_replaceable:
if world.random.random() < (0.5 + world.beemizer[player] * 0.1):
return "Bee Trap" if isinstance(item, str) else world.create_item("Bee Trap", player)
else:
return "Bee" if isinstance(item, str) else world.create_item("Bee", player)
else:
return item
else:
return item return item
# first roll - replaceable item should be replaced, within beemizer_total_chance
if not world.beemizer_total_chance[player] or world.random.random() > (world.beemizer_total_chance[player] / 100):
return item
# second roll - bee replacement should be trap, within beemizer_trap_chance
if not world.beemizer_trap_chance[player] or world.random.random() > (world.beemizer_trap_chance[player] / 100):
return "Bee" if isinstance(item, str) else world.create_item("Bee", player)
else:
return "Bee Trap" if isinstance(item, str) else world.create_item("Bee Trap", player)
# should be replaced with direct world.create_item(item) call in the future # should be replaced with direct world.create_item(item) call in the future
def ItemFactory(items, player: int): def ItemFactory(items, player: int):

View File

@ -261,6 +261,26 @@ class TriforceHud(Choice):
option_hide_both = 3 option_hide_both = 3
class BeemizerRange(Range):
value: int
range_start = 0
range_end = 100
class BeemizerTotalChance(BeemizerRange):
"""Percentage chance for each junk-fill item (rupees, bombs, arrows) to be
replaced with either a bee swarm trap or a single bottle-filling bee."""
default = 0
displayname = "Beemizer Total Chance"
class BeemizerTrapChance(BeemizerRange):
"""Percentage chance for each replaced junk-fill item to be a bee swarm
trap; all other replaced items are single bottle-filling bees."""
default = 60
displayname = "Beemizer Trap Chance"
alttp_options: typing.Dict[str, type(Option)] = { alttp_options: typing.Dict[str, type(Option)] = {
"crystals_needed_for_gt": CrystalsTower, "crystals_needed_for_gt": CrystalsTower,
"crystals_needed_for_ganon": CrystalsGanon, "crystals_needed_for_ganon": CrystalsGanon,
@ -293,6 +313,8 @@ alttp_options: typing.Dict[str, type(Option)] = {
"reduceflashing": ReduceFlashing, "reduceflashing": ReduceFlashing,
"triforcehud": TriforceHud, "triforcehud": TriforceHud,
"glitch_boots": DefaultOnToggle, "glitch_boots": DefaultOnToggle,
"beemizer_total_chance": BeemizerTotalChance,
"beemizer_trap_chance": BeemizerTrapChance,
"death_link": DeathLink "death_link": DeathLink
} }