From 2ef49294b1262fc75d07b48a7d39c6ab75040f13 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 13:06:14 -0500 Subject: [PATCH 01/28] RAC: Starting item fixes - Remove the setting to prevent it appearing in player's yaml files --- worlds/RAC1/Options.py | 5 +++-- worlds/RAC1/__init__.py | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 05a35cb35a86..91fa96022bb3 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -125,6 +125,7 @@ class ShuffleInfobots(ItemOptions): vanilla: Infobots are unshuffled. random_same: Infobots are shuffled to other Infobot locations. random_item: Infobots are shuffled anywhere, useful items are found at Infobot locations. + WARNING! Using random_same, or random_item with no other pool selected, is likely to fail on solo worlds. unrestricted: Infobots are shuffled anywhere, anything can be found at Infobot locations. """ display_name = "Shuffle Infobots" @@ -147,7 +148,7 @@ class GoldenWeaponProgression(Toggle): @dataclass class RacOptions(PerGameCommonOptions): # death_link: DeathLink - starting_item: StartingItem + # starting_item: StartingItem shuffle_weapons: ShuffleWeapons shuffle_gadgets: ShuffleGadgets shuffle_packs: ShufflePacks @@ -164,7 +165,7 @@ def get_options_as_dict(options: RacOptions) -> dict[str, Any]: return { # "death_link", "start_inventory_from_pool": dict(), - "starting_item": options.starting_item.option_vanilla, + # "starting_item": options.starting_item.option_vanilla, "shuffle_weapons": options.shuffle_weapons.value, "shuffle_gadgets": options.shuffle_gadgets.value, "shuffle_packs": options.shuffle_packs.value, diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index a4bb6fe75c97..d773ca3a9c1c 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -123,21 +123,21 @@ def generate_early(self) -> None: create_regions(self) # TODO: Item Pools: get_pre_fill_items() - if (self.options.shuffle_weapons == ShuffleWeapons.option_vanilla or - self.options.starting_item == StartingItem.option_vanilla): - starting_item = self.create_item(Items.BOMB_GLOVE.name) - else: - starting_item = [] - match self.options.starting_item: - case StartingItem.option_random_same: - starting_item = list(Items.WEAPONS) - case StartingItem.option_random_item: - starting_item = [item for item in Items.ALL if item.name != "Gold Bolt"] - case StartingItem.option_unrestricted: - starting_item = list(Items.ALL) - self.random.shuffle(starting_item) - self.multiworld.push_precollected(self.create_item(starting_item[0].name)) - starting_item = self.create_item(starting_item[0].name) + # if (self.options.shuffle_weapons == ShuffleWeapons.option_vanilla or + # self.options.starting_item == StartingItem.option_vanilla): + starting_item = self.create_item(Items.BOMB_GLOVE.name) + # else: + # starting_item = [] + # match self.options.starting_item: + # case StartingItem.option_random_same: + # starting_item = list(Items.WEAPONS) + # case StartingItem.option_random_item: + # starting_item = [item for item in Items.ALL if item.name != "Gold Bolt"] + # case StartingItem.option_unrestricted: + # starting_item = list(Items.ALL) + # self.random.shuffle(starting_item) + # self.multiworld.push_precollected(self.create_item(starting_item[0].name)) + # starting_item = self.create_item(starting_item[0].name) starting_planet = self.create_item(Items.NOVALIS_INFOBOT.name) self.starting_items = [starting_item, starting_planet] From 635384c70badbf5781015850a807a2d5c0a0a53d Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 14:14:38 -0500 Subject: [PATCH 02/28] RAC: Progressive items defines --- worlds/RAC1/data/Items.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 433212e71ffb..69ec94aaa888 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -63,6 +63,23 @@ class ItemData(Item): GOLDEN_MORPH_O_RAY = ItemData(71, "Golden Morph-o-ray", "GoldenWeapons") GOLDEN_DECOY_GLOVE = ItemData(75, "Golden Decoy glove", "GoldenWeapons") +PROGRESSIVE_PACK = ItemData(80, "Progressive Pack", "Packs") +PROGRESSIVE_HELMET = ItemData(81, "Progressive Helmet", "Helmets") +PROGRESSIVE_SUCK = ItemData(82, "Progressive Suck Cannon", "ProgressiveWeapons") +PROGRESSIVE_BOMB = ItemData(83, "Progressive Bomb glove", "ProgressiveWeapons") +PROGRESSIVE_DEVASTATOR = ItemData(84, "Progressive Devastator", "ProgressiveWeapons") +PROGRESSIVE_BLASTER = ItemData(85, "Progressive Blaster", "ProgressiveWeapons") +PROGRESSIVE_PYROCITOR = ItemData(86, "Progressive Pyrocitor", "ProgressiveWeapons") +PROGRESSIVE_MINE = ItemData(87, "Progressive Mine glove", "ProgressiveWeapons") +PROGRESSIVE_TESLA = ItemData(88, "Progressive Tesla claw", "ProgressiveWeapons") +PROGRESSIVE_DOOM = ItemData(89, "Progressive Glove of doom", "ProgressiveWeapons") +PROGRESSIVE_MORPH = ItemData(90, "Progressive Morph-o-ray", "ProgressiveWeapons") +PROGRESSIVE_DECOY = ItemData(91, "Progressive Decoy glove", "ProgressiveWeapons") +PROGRESSIVE_BOOTS = ItemData(92, "Progressive Boots", "Boots") +PROGRESSIVE_HOVERBOARD = ItemData(93, "Progressive Hoverboard", "ExtraItems") +PROGRESSIVE_TRADE = ItemData(94, "Progressive Raritanium", "ExtraItems") +PROGRESSIVE_NANOTECH = ItemData(95, "Progressive Nanotech", "ExtraItems") + NOVALIS_INFOBOT = ItemData(101, "Novalis", "Infobots") ARIDIA_INFOBOT = ItemData(102, "Aridia", "Infobots") KERWAN_INFOBOT = ItemData(103, "Kerwan", "Infobots") From 87ef3fbe4e273aada5e95d4384747d5a4acc9df8 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 14:18:54 -0500 Subject: [PATCH 03/28] RAC: Progressive items Pools --- worlds/RAC1/data/Items.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 69ec94aaa888..4aefc548345f 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -156,6 +156,16 @@ class CollectableData(ItemData): RYNO, DRONE_DEVICE, DECOY_GLOVE, + PROGRESSIVE_SUCK, + PROGRESSIVE_BOMB, + PROGRESSIVE_DEVASTATOR, + PROGRESSIVE_BLASTER, + PROGRESSIVE_PYROCITOR, + PROGRESSIVE_MINE, + PROGRESSIVE_TESLA, + PROGRESSIVE_DOOM, + PROGRESSIVE_MORPH, + PROGRESSIVE_DECOY, ] GOLDEN_WEAPONS: Sequence[ItemData] = [ @@ -184,17 +194,20 @@ class CollectableData(ItemData): HELI_PACK, THRUSTER_PACK, HYDRO_PACK, + PROGRESSIVE_PACK, ] HELMETS: Sequence[ItemData] = [ SONIC_SUMMONER, O2_MASK, PILOTS_HELMET, + PROGRESSIVE_HELMET, ] BOOTS: Sequence[ItemData] = [ MAGNEBOOTS, GRINDBOOTS, + PROGRESSIVE_BOOTS, ] EXTRA_ITEMS: Sequence[ItemData] = [ @@ -207,6 +220,9 @@ class CollectableData(ItemData): CODEBOT, PREMIUM_NANOTECH, ULTRA_NANOTECH, + PROGRESSIVE_HOVERBOARD, + PROGRESSIVE_TRADE, + PROGRESSIVE_NANOTECH, ] COLLECTABLES: Sequence[CollectableData] = [ From 0717f37e39147bc497852adcca2f6b3658363898 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 14:30:48 -0500 Subject: [PATCH 04/28] RAC: Progressive items Classification and counts --- worlds/RAC1/ItemPool.py | 6 ++++++ worlds/RAC1/data/Items.py | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/worlds/RAC1/ItemPool.py b/worlds/RAC1/ItemPool.py index 6dc89a84232c..efa1b2137291 100644 --- a/worlds/RAC1/ItemPool.py +++ b/worlds/RAC1/ItemPool.py @@ -10,13 +10,16 @@ def get_classification(item: ItemData) -> ItemClassification: Items.HELI_PACK, Items.THRUSTER_PACK, Items.HYDRO_PACK, + Items.PROGRESSIVE_PACK, Items.SWINGSHOT, Items.MAGNEBOOTS, Items.GRINDBOOTS, + Items.PROGRESSIVE_BOOTS, Items.HYDRODISPLACER, Items.TAUNTER, Items.O2_MASK, Items.PILOTS_HELMET, + Items.PROGRESSIVE_HELMET, Items.TRESPASSER, Items.HOLOGUISE, Items.CODEBOT, @@ -34,6 +37,9 @@ def get_classification(item: ItemData) -> ItemClassification: Items.PERSUADER, Items.PREMIUM_NANOTECH, Items.ULTRA_NANOTECH, + Items.PROGRESSIVE_HOVERBOARD, + Items.PROGRESSIVE_TRADE, + Items.PROGRESSIVE_NANOTECH, ]: return ItemClassification.useful if item in Items.WEAPONS: diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 4aefc548345f..0ca1ffa94da2 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -156,16 +156,16 @@ class CollectableData(ItemData): RYNO, DRONE_DEVICE, DECOY_GLOVE, - PROGRESSIVE_SUCK, - PROGRESSIVE_BOMB, - PROGRESSIVE_DEVASTATOR, - PROGRESSIVE_BLASTER, - PROGRESSIVE_PYROCITOR, - PROGRESSIVE_MINE, - PROGRESSIVE_TESLA, - PROGRESSIVE_DOOM, - PROGRESSIVE_MORPH, - PROGRESSIVE_DECOY, + *[PROGRESSIVE_SUCK] * 2, + *[PROGRESSIVE_BOMB] * 2, + *[PROGRESSIVE_DEVASTATOR] * 2, + *[PROGRESSIVE_BLASTER] * 2, + *[PROGRESSIVE_PYROCITOR] * 2, + *[PROGRESSIVE_MINE] * 2, + *[PROGRESSIVE_TESLA] * 2, + *[PROGRESSIVE_DOOM] * 2, + *[PROGRESSIVE_MORPH] * 2, + *[PROGRESSIVE_DECOY] * 2, ] GOLDEN_WEAPONS: Sequence[ItemData] = [ @@ -194,20 +194,20 @@ class CollectableData(ItemData): HELI_PACK, THRUSTER_PACK, HYDRO_PACK, - PROGRESSIVE_PACK, + *[PROGRESSIVE_PACK] * 3, ] HELMETS: Sequence[ItemData] = [ SONIC_SUMMONER, O2_MASK, PILOTS_HELMET, - PROGRESSIVE_HELMET, + *[PROGRESSIVE_HELMET] * 3, ] BOOTS: Sequence[ItemData] = [ MAGNEBOOTS, GRINDBOOTS, - PROGRESSIVE_BOOTS, + *[PROGRESSIVE_BOOTS] * 2, ] EXTRA_ITEMS: Sequence[ItemData] = [ @@ -220,9 +220,9 @@ class CollectableData(ItemData): CODEBOT, PREMIUM_NANOTECH, ULTRA_NANOTECH, - PROGRESSIVE_HOVERBOARD, - PROGRESSIVE_TRADE, - PROGRESSIVE_NANOTECH, + *[PROGRESSIVE_HOVERBOARD] * 2, + *[PROGRESSIVE_TRADE] * 2, + *[PROGRESSIVE_NANOTECH] * 2, ] COLLECTABLES: Sequence[CollectableData] = [ From ca222d4792cc41e1578779049b2c6d5ca8c4b732 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 22:13:08 -0500 Subject: [PATCH 05/28] RAC: Add Progressive Options --- worlds/RAC1/Options.py | 162 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 5 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 91fa96022bb3..fe89c4a9c82b 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -45,6 +45,18 @@ class ShuffleWeapons(ItemOptions): pool = "Weapons" +class ShuffleGoldenWeapons(ItemOptions): + """Randomize Golden Weapon locations + vanilla: Golden Weapons are unshuffled. + random_same: Golden Weapons are shuffled to other Weapon locations. + random_item: Golden Weapons are shuffled anywhere, useful items are found at Golden Weapon locations. + unrestricted: Golden Weapons are shuffled anywhere, anything can be found at Golden Weapon locations. + """ + display_name = "Shuffle Golden Weapons" + default = 3 + pool = "Weapons" + + # TODO: Early Weapon option, off, shuffled amount (user states amount), list (user lists items) class EarlyWeapon(TextChoice): """ @@ -138,11 +150,137 @@ class EnableBoltMultiplier(Toggle): display_name = "Enable Bolt Multiplier" -class GoldenWeaponProgression(Toggle): - """If enabled, make golden weapons and their standard variants progressive items. - This means that there are two copies of the regular item in the pool, when you collect one for the first time - then it is the standard version, but collecting the second one will give you the golden version.""" +class ProgressiveOptions(Choice): + """Template + vanilla: These items are not progressive, each item is independent of other items. + progressive: These items are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: These items are progressive, the order of upgrading is reversed. + progressive_random: These items are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 + + +class GoldenWeaponProgression(ProgressiveOptions): + """Progressive Weapons + If enabled, make golden weapons and their standard variants progressive items. + vanilla: Golden Weapons and Weapons are not progressive, Golden Weapons do nothing until their base item is + found. + normal: Golden Weapons and Weapons are not progressive, each item is independent of other items. + progressive: Golden Weapons and Weapons are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Golden Weapons and Weapons are progressive, the order of upgrading is reversed. + progressive_random: Golden Weapons and Weapons are progressive, the order of upgrading is random.""" display_name = "Golden Weapon Progression" + value: int + option_vanilla = 0 + option_normal = 1 + option_progressive = 2 + option_progressive_reversed = 3 + option_progressive_random = 4 + alias_true = 0 + alias_false = 1 + default = 1 + + +class PackProgression(ProgressiveOptions): + """Progressive Packs + vanilla: Packs are not progressive, each item is independent of other items. + progressive: Packs are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Packs are progressive, the order of upgrading is reversed. + progressive_random: Packs are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 + + +class HelmetProgression(ProgressiveOptions): + """Progressive Helmets + vanilla: Helmets are not progressive, each item is independent of other items. + progressive: Helmets are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Helmets are progressive, the order of upgrading is reversed. + progressive_random: Helmets are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 + + +class BootsProgression(ProgressiveOptions): + """Progressive Boots + vanilla: Grind and Magneboots are not progressive, each item is independent of other items. + progressive: Grind and Magneboots are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Grind and Magneboots are progressive, the order of upgrading is reversed. + progressive_random: Grind and Magneboots are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 + + +class HoverboardProgression(ProgressiveOptions): + """Progressive Hoverboard + vanilla: Hoverboard and Zoomerator are not progressive, each item is independent of other items. + progressive: Hoverboard and Zoomerator are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Hoverboard and Zoomerator are progressive, the order of upgrading is reversed. + progressive_random: Hoverboard and Zoomerator are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 + + +class RaritaniumProgression(ProgressiveOptions): + """Progressive Raritanium + vanilla: Raritanium and Persuader are not progressive, each item is independent of other items. + progressive: Raritanium and Persuader are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Raritanium and Persuader are progressive, the order of upgrading is reversed. + progressive_random: Raritanium and Persuader are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 + + +class NanotechProgression(ProgressiveOptions): + """Progressive Nanotech + vanilla: Nanotech is not progressive, each item is independent of other items. + progressive: Nanotech are progressive, collecting multiple of an item will upgrade it. + progressive_reversed: Nanotech are progressive, the order of upgrading is reversed. + progressive_random: Nanotech are progressive, the order of upgrading is random. + """ + value: int + option_vanilla = 0 + option_progressive = 1 + option_progressive_reversed = 2 + option_progressive_random = 3 + alias_true = 1 + alias_false = 0 @dataclass @@ -150,6 +288,7 @@ class RacOptions(PerGameCommonOptions): # death_link: DeathLink # starting_item: StartingItem shuffle_weapons: ShuffleWeapons + shuffle_golden_weapons: ShuffleGoldenWeapons shuffle_gadgets: ShuffleGadgets shuffle_packs: ShufflePacks shuffle_helmets: ShuffleHelmets @@ -158,7 +297,13 @@ class RacOptions(PerGameCommonOptions): shuffle_gold_bolts: ShuffleGoldBolts shuffle_infobots: ShuffleInfobots # enable_bolt_multiplier: EnableBoltMultiplier - # extend_weapon_progression: GoldenWeaponProgression + progressive_weapons: GoldenWeaponProgression + progressive_packs: PackProgression + progressive_helmets: HelmetProgression + progressive_boots: BootsProgression + progressive_hoverboard: HoverboardProgression + progressive_raritanium: RaritaniumProgression + progressive_nanotech: NanotechProgression def get_options_as_dict(options: RacOptions) -> dict[str, Any]: @@ -174,4 +319,11 @@ def get_options_as_dict(options: RacOptions) -> dict[str, Any]: "shuffle_extra_items": options.shuffle_extra_items.value, "shuffle_gold_bolts": options.shuffle_gold_bolts.value, "shuffle_infobots": options.shuffle_infobots.value, + "progressive_weapons": options.progressive_weapons.value, + "progressive_packs": options.progressive_packs.value, + "progressive_helmets": options.progressive_helmets.value, + "progressive_boots": options.progressive_boots.value, + "progressive_hoverboard": options.progressive_hoverboard.value, + "progressive_raritanium": options.progressive_raritanium.value, + "progressive_nanotech": options.progressive_nanotech.value, } From 5301b59e38bbabdba7a1fccda10ac9e8e09ea2cb Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 22:14:55 -0500 Subject: [PATCH 06/28] RAC: Progressive Pool Cleanup --- worlds/RAC1/ItemPool.py | 41 ++++------- worlds/RAC1/__init__.py | 1 + worlds/RAC1/data/Items.py | 145 +++++++++++++++++++++++++++----------- 3 files changed, 118 insertions(+), 69 deletions(-) diff --git a/worlds/RAC1/ItemPool.py b/worlds/RAC1/ItemPool.py index efa1b2137291..caa484ca2e92 100644 --- a/worlds/RAC1/ItemPool.py +++ b/worlds/RAC1/ItemPool.py @@ -4,47 +4,36 @@ def get_classification(item: ItemData) -> ItemClassification: - if item in Items.PLANETS: + if (item in Items.PLANETS + or item in Items.ALL_PACKS + or item in Items.GADGETS + or item in Items.ALL_BOOTS): return ItemClassification.progression if item in [ - Items.HELI_PACK, - Items.THRUSTER_PACK, - Items.HYDRO_PACK, - Items.PROGRESSIVE_PACK, - Items.SWINGSHOT, - Items.MAGNEBOOTS, - Items.GRINDBOOTS, - Items.PROGRESSIVE_BOOTS, - Items.HYDRODISPLACER, Items.TAUNTER, Items.O2_MASK, Items.PILOTS_HELMET, Items.PROGRESSIVE_HELMET, - Items.TRESPASSER, - Items.HOLOGUISE, Items.CODEBOT, Items.RARITANIUM, Items.HOVERBOARD, Items.ZOOMERATOR, + Items.PROGRESSIVE_HOVERBOARD, Items.BOMB_GLOVE, + Items.PROGRESSIVE_BOMB, + Items.BLASTER, + Items.MINE_GLOVE, + Items.PROGRESSIVE_MINE, Items.DEVASTATOR, + Items.PROGRESSIVE_DEVASTATOR, Items.VISIBOMB, - Items.METAL_DETECTOR, - ]: - return ItemClassification.progression - if item in [ - Items.BOLT_GRABBER, - Items.PERSUADER, - Items.PREMIUM_NANOTECH, - Items.ULTRA_NANOTECH, - Items.PROGRESSIVE_HOVERBOARD, + Items.RYNO, Items.PROGRESSIVE_TRADE, - Items.PROGRESSIVE_NANOTECH, ]: - return ItemClassification.useful - if item in Items.WEAPONS: - return ItemClassification.useful - if item in Items.GOLDEN_WEAPONS: + return ItemClassification.progression + if (item == Items.SONIC_SUMMONER + or item in Items.ALL_WEAPONS + or item in Items.ALL_EXTRA_ITEMS): return ItemClassification.useful return ItemClassification.filler diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index d773ca3a9c1c..85f638ba4bc8 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -84,6 +84,7 @@ def generate_early(self) -> None: self.options.shuffle_boots, self.options.shuffle_weapons, self.options.shuffle_extra_items, + self.options.shuffle_golden_weapons, ] disabled_pools = [] restricted_pools = [] diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 0ca1ffa94da2..fd4e3d1fa904 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -65,17 +65,17 @@ class ItemData(Item): PROGRESSIVE_PACK = ItemData(80, "Progressive Pack", "Packs") PROGRESSIVE_HELMET = ItemData(81, "Progressive Helmet", "Helmets") -PROGRESSIVE_SUCK = ItemData(82, "Progressive Suck Cannon", "ProgressiveWeapons") -PROGRESSIVE_BOMB = ItemData(83, "Progressive Bomb glove", "ProgressiveWeapons") -PROGRESSIVE_DEVASTATOR = ItemData(84, "Progressive Devastator", "ProgressiveWeapons") -PROGRESSIVE_BLASTER = ItemData(85, "Progressive Blaster", "ProgressiveWeapons") -PROGRESSIVE_PYROCITOR = ItemData(86, "Progressive Pyrocitor", "ProgressiveWeapons") -PROGRESSIVE_MINE = ItemData(87, "Progressive Mine glove", "ProgressiveWeapons") -PROGRESSIVE_TESLA = ItemData(88, "Progressive Tesla claw", "ProgressiveWeapons") -PROGRESSIVE_DOOM = ItemData(89, "Progressive Glove of doom", "ProgressiveWeapons") -PROGRESSIVE_MORPH = ItemData(90, "Progressive Morph-o-ray", "ProgressiveWeapons") -PROGRESSIVE_DECOY = ItemData(91, "Progressive Decoy glove", "ProgressiveWeapons") -PROGRESSIVE_BOOTS = ItemData(92, "Progressive Boots", "Boots") +PROGRESSIVE_SUCK = ItemData(82, "Progressive Suck Cannon", "Weapons") +PROGRESSIVE_BOMB = ItemData(83, "Progressive Bomb glove", "Weapons") +PROGRESSIVE_DEVASTATOR = ItemData(84, "Progressive Devastator", "Weapons") +PROGRESSIVE_BLASTER = ItemData(85, "Progressive Blaster", "Weapons") +PROGRESSIVE_PYROCITOR = ItemData(86, "Progressive Pyrocitor", "Weapons") +PROGRESSIVE_MINE = ItemData(87, "Progressive Mine glove", "Weapons") +PROGRESSIVE_TESLA = ItemData(88, "Progressive Tesla claw", "Weapons") +PROGRESSIVE_DOOM = ItemData(89, "Progressive Glove of doom", "Weapons") +PROGRESSIVE_MORPH = ItemData(90, "Progressive Morph-o-ray", "Weapons") +PROGRESSIVE_DECOY = ItemData(91, "Progressive Decoy glove", "Weapons") +PROGRESSIVE_BOOT = ItemData(92, "Progressive Boots", "Boots") PROGRESSIVE_HOVERBOARD = ItemData(93, "Progressive Hoverboard", "ExtraItems") PROGRESSIVE_TRADE = ItemData(94, "Progressive Raritanium", "ExtraItems") PROGRESSIVE_NANOTECH = ItemData(95, "Progressive Nanotech", "ExtraItems") @@ -141,31 +141,37 @@ class CollectableData(ItemData): WEAPONS: Sequence[ItemData] = [ + TAUNTER, + VISIBOMB, + WALLOPER, + DRONE_DEVICE, +] + +NON_PROGRESSIVE_WEAPONS: Sequence[ItemData] = [ SUCK_CANNON, BOMB_GLOVE, DEVASTATOR, - VISIBOMB, - TAUNTER, BLASTER, PYROCITOR, MINE_GLOVE, - WALLOPER, TESLA_CLAW, GLOVE_OF_DOOM, MORPH_O_RAY, RYNO, - DRONE_DEVICE, DECOY_GLOVE, - *[PROGRESSIVE_SUCK] * 2, - *[PROGRESSIVE_BOMB] * 2, - *[PROGRESSIVE_DEVASTATOR] * 2, - *[PROGRESSIVE_BLASTER] * 2, - *[PROGRESSIVE_PYROCITOR] * 2, - *[PROGRESSIVE_MINE] * 2, - *[PROGRESSIVE_TESLA] * 2, - *[PROGRESSIVE_DOOM] * 2, - *[PROGRESSIVE_MORPH] * 2, - *[PROGRESSIVE_DECOY] * 2, +] + +PROGRESSIVE_WEAPONS: Sequence[ItemData] = [ + PROGRESSIVE_SUCK, + PROGRESSIVE_BOMB, + PROGRESSIVE_DEVASTATOR, + PROGRESSIVE_BLASTER, + PROGRESSIVE_PYROCITOR, + PROGRESSIVE_MINE, + PROGRESSIVE_TESLA, + PROGRESSIVE_DOOM, + PROGRESSIVE_MORPH, + PROGRESSIVE_DECOY, ] GOLDEN_WEAPONS: Sequence[ItemData] = [ @@ -181,6 +187,19 @@ class CollectableData(ItemData): GOLDEN_DECOY_GLOVE, ] +PROGRESSIVE_GOLDEN_WEAPONS: Sequence[ItemData] = [ + GOLDEN_SUCK_CANNON, + GOLDEN_BOMB_GLOVE, + GOLDEN_DEVASTATOR, + GOLDEN_BLASTER, + GOLDEN_PYROCITOR, + GOLDEN_MINE_GLOVE, + GOLDEN_TESLA_CLAW, + GOLDEN_GLOVE_OF_DOOM, + GOLDEN_MORPH_O_RAY, + GOLDEN_DECOY_GLOVE, +] + GADGETS: Sequence[ItemData] = [ HYDRODISPLACER, TRESPASSER, @@ -194,6 +213,9 @@ class CollectableData(ItemData): HELI_PACK, THRUSTER_PACK, HYDRO_PACK, +] + +PROGRESSIVE_PACKS: Sequence[ItemData] = [ *[PROGRESSIVE_PACK] * 3, ] @@ -201,32 +223,56 @@ class CollectableData(ItemData): SONIC_SUMMONER, O2_MASK, PILOTS_HELMET, +] + +PROGRESSIVE_HELMETS: Sequence[ItemData] = [ *[PROGRESSIVE_HELMET] * 3, ] BOOTS: Sequence[ItemData] = [ MAGNEBOOTS, GRINDBOOTS, - *[PROGRESSIVE_BOOTS] * 2, +] + +PROGRESSIVE_BOOTS: Sequence[ItemData] = [ + *[PROGRESSIVE_BOOT] * 2, ] EXTRA_ITEMS: Sequence[ItemData] = [ - HOVERBOARD, MAP_O_MATIC, BOLT_GRABBER, - PERSUADER, + CODEBOT, +] + +NON_PROGRESSIVE_HOVERBOARDS: Sequence[ItemData] = [ + HOVERBOARD, ZOOMERATOR, +] + +PROGRESSIVE_HOVERBOARDS: Sequence[ItemData] = [ + *[PROGRESSIVE_HOVERBOARD] * 2, +] + +NON_PROGRESSIVE_TRADES: Sequence[ItemData] = [ + PERSUADER, RARITANIUM, - CODEBOT, +] + +PROGRESSIVE_TRADES: Sequence[ItemData] = [ + *[PROGRESSIVE_TRADE] * 2, +] + +NON_PROGRESSIVE_NANOTECHS: Sequence[ItemData] = [ PREMIUM_NANOTECH, ULTRA_NANOTECH, - *[PROGRESSIVE_HOVERBOARD] * 2, - *[PROGRESSIVE_TRADE] * 2, +] + +PROGRESSIVE_NANOTECHS: Sequence[ItemData] = [ *[PROGRESSIVE_NANOTECH] * 2, ] -COLLECTABLES: Sequence[CollectableData] = [ - GOLD_BOLT, +GOLD_BOLTS: Sequence[CollectableData] = [ + *[GOLD_BOLT] * 40, ] PLANETS: Sequence[ItemData] = [ @@ -283,7 +329,21 @@ class CollectableData(ItemData): GOING_COMMANDO, ] -ALL: Sequence[ItemData] = [*WEAPONS, *GADGETS, *PACKS, *HELMETS, *BOOTS, *EXTRA_ITEMS, *[GOLD_BOLT] * 40, *PLANETS, ] +ALL: Sequence[ItemData] = [*WEAPONS, *NON_PROGRESSIVE_WEAPONS, *PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, + *PROGRESSIVE_GOLDEN_WEAPONS, *GADGETS, *PACKS, *PROGRESSIVE_PACKS, *HELMETS, + *PROGRESSIVE_HELMETS, *BOOTS, *PROGRESSIVE_BOOTS, *EXTRA_ITEMS, + *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, + *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS, *GOLD_BOLTS, + *PLANETS, *SKILLPOINTS] + +ALL_WEAPONS: Sequence[ItemData] = [*WEAPONS, *NON_PROGRESSIVE_WEAPONS, *PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, + *PROGRESSIVE_GOLDEN_WEAPONS] +ALL_PACKS: Sequence[ItemData] = [*PACKS, *PROGRESSIVE_PACKS] +ALL_HELMETS: Sequence[ItemData] = [*HELMETS, *PROGRESSIVE_HELMETS] +ALL_BOOTS: Sequence[ItemData] = [*BOOTS, *PROGRESSIVE_BOOTS] +ALL_EXTRA_ITEMS: Sequence[ItemData] = [*EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, + *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, + *PROGRESSIVE_NANOTECHS] def from_id(item_id: int) -> ItemData: @@ -298,21 +358,20 @@ def from_name(item_name: str) -> ItemData: matching = [item for item in ALL if item.name == item_name] if len(matching) == 0: raise ValueError(f"No item data for '{item_name}'") - if item_name != GOLD_BOLT.name: - assert len(matching) < 2, f"Multiple item data with name '{item_name}'. Please report." + # if item_name != GOLD_BOLT.name: + # assert len(matching) < 2, f"Multiple item data with name '{item_name}'. Please report." return matching[0] def get_item_groups() -> dict[str, set[str]]: groups: dict[str, set[str]] = { - "Weapons": {w.name for w in WEAPONS}, - "GoldenWeapons": {gw.name for gw in GOLDEN_WEAPONS}, + "Weapons": {w.name for w in ALL_WEAPONS}, "Gadgets": {g.name for g in GADGETS}, - "Packs": {p.name for p in PACKS}, - "Helmets": {h.name for h in HELMETS}, - "Boots": {b.name for b in BOOTS}, - "ExtraItems": {e.name for e in EXTRA_ITEMS}, - "GoldBolts": {c.name for c in COLLECTABLES}, + "Packs": {p.name for p in ALL_PACKS}, + "Helmets": {h.name for h in ALL_HELMETS}, + "Boots": {b.name for b in ALL_BOOTS}, + "ExtraItems": {e.name for e in ALL_EXTRA_ITEMS}, + "GoldBolts": {c.name for c in GOLD_BOLTS}, "Infobots": {i.name for i in PLANETS}, "Skillpoints": {s.name for s in SKILLPOINTS}, } From 4a4a6da2547a92a43ed0359f45139a4f2dedec32 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sat, 9 Aug 2025 22:15:58 -0500 Subject: [PATCH 07/28] RAC: Check Progressive Options for Items --- worlds/RAC1/__init__.py | 7 +++--- worlds/RAC1/data/Items.py | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 85f638ba4bc8..0cd9a6fdc4e1 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -267,10 +267,11 @@ def fill_pool(self, pools, scope) -> (list, list): return placed_locations def create_item(self, name: str, override: Optional[ItemClassification] = None) -> "Item": + new_name = Items.check_progressive_item(self.options, name) if override: - return RacItem(name, override, self.item_name_to_id[name], self.player) - item_data = Items.from_name(name) - return RacItem(name, ItemPool.get_classification(item_data), self.item_name_to_id[name], self.player) + return RacItem(new_name, override, self.item_name_to_id[new_name], self.player) + item_data = Items.from_name(new_name) + return RacItem(new_name, ItemPool.get_classification(item_data), self.item_name_to_id[new_name], self.player) def create_event(self, name: str) -> "Item": return RacItem(name, ItemClassification.progression, None, self.player) diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index fd4e3d1fa904..6f7db9055717 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -2,6 +2,7 @@ from typing import Sequence from BaseClasses import Item +from worlds.RAC1 import Options @dataclass @@ -376,3 +377,51 @@ def get_item_groups() -> dict[str, set[str]]: "Skillpoints": {s.name for s in SKILLPOINTS}, } return groups + +def check_progressive_item(options, item) -> str: + new_item = item + match from_name(item).pool: + case SUCK_CANNON.pool | GOLDEN_SUCK_CANNON.pool: + if options.progressive_weapons.value > Options.GoldenWeaponProgression.option_normal: + match item: + case SUCK_CANNON.name: + new_item = PROGRESSIVE_SUCK.name + case BOMB_GLOVE.name: + new_item = PROGRESSIVE_BOMB.name + case DEVASTATOR.name: + new_item = PROGRESSIVE_DEVASTATOR.name + case BLASTER.name: + new_item = PROGRESSIVE_BLASTER.name + case PYROCITOR.name: + new_item = PROGRESSIVE_PYROCITOR.name + case MINE_GLOVE.name: + new_item = PROGRESSIVE_MINE.name + case TESLA_CLAW.name: + new_item = PROGRESSIVE_TESLA.name + case GLOVE_OF_DOOM.name: + new_item = PROGRESSIVE_DOOM.name + case MORPH_O_RAY.name: + new_item = PROGRESSIVE_MORPH.name + case DECOY_GLOVE.name: + new_item = PROGRESSIVE_DECOY.name + case HELI_PACK.pool: + if options.progressive_packs.value: + new_item = PROGRESSIVE_PACK.name + case O2_MASK.pool: + if options.progressive_helmets.value: + new_item = PROGRESSIVE_HELMET.name + case GRINDBOOTS.pool: + if options.progressive_boots.value: + new_item = PROGRESSIVE_BOOT.name + case HOVERBOARD.pool: + match item: + case HOVERBOARD.name | ZOOMERATOR.name: + if options.progressive_hoverboard.value: + new_item = PROGRESSIVE_HOVERBOARD.name + case RARITANIUM.name | PERSUADER.name: + if options.progressive_raritanium.value: + new_item = PROGRESSIVE_TRADE.name + case PREMIUM_NANOTECH.name | ULTRA_NANOTECH.name: + if options.progressive_nanotech.value: + new_item = PROGRESSIVE_NANOTECH.name + return new_item From 2a5680f5d7ddc8bba8786507e622aa177dccecc0 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sun, 17 Aug 2025 06:30:33 -0500 Subject: [PATCH 08/28] RAC: Starting Location Option --- worlds/RAC1/Regions.py | 2 +- worlds/RAC1/__init__.py | 6 +++--- worlds/RAC1/data/Planets.py | 15 +++++++++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/worlds/RAC1/Regions.py b/worlds/RAC1/Regions.py index ef100265dd77..8d40bb3c5683 100644 --- a/worlds/RAC1/Regions.py +++ b/worlds/RAC1/Regions.py @@ -18,7 +18,7 @@ def create_regions(world: 'RacWorld'): menu = Region("Menu", world.player, world.multiworld) world.multiworld.regions.append(menu) - for planet_data in Planets.LOGIC_PLANETS: + for planet_data in Planets.ALL_PLANETS: if planet_data.locations: def generate_planet_access_rule(planet: PlanetData) -> typing.Callable[[CollectionState], bool]: def planet_access_rule(state: CollectionState): diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 733cf50c31c1..5aeda6bd76d3 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -11,7 +11,7 @@ from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, POOL_GOLD_BOLT, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_WEAPON) from .data.Planets import ALL_LOCATIONS, location_groups, PlanetData -from .Options import RacOptions, ShuffleInfobots, ShuffleWeapons, StartingItem +from .Options import RacOptions, ShuffleInfobots, ShuffleWeapons, StartingItem, StartingLocation from .Regions import create_regions rac_logger = logging.getLogger("Ratchet & Clank") @@ -142,10 +142,10 @@ def generate_early(self) -> None: # starting_item = self.create_item(starting_item[0].name) if (self.options.shuffle_infobots == ShuffleInfobots.option_vanilla or - self.options.starting_planet == StartingPlanet.option_vanilla): + self.options.starting_location == StartingLocation.option_false): starting_planet = self.create_item(Items.NOVALIS_INFOBOT.name) else: - starting_planet = list(Planets.LOGIC_PLANETS) + starting_planet = list(Planets.STARTING_PLANETS) self.random.shuffle(starting_planet) self.starting_planet = starting_planet[0].name starting_planet = self.create_item(starting_planet[0].name) diff --git a/worlds/RAC1/data/Planets.py b/worlds/RAC1/data/Planets.py index 9bdebaf8afcb..35fc0c7d9f0c 100644 --- a/worlds/RAC1/data/Planets.py +++ b/worlds/RAC1/data/Planets.py @@ -168,7 +168,7 @@ class PlanetData(NamedTuple): VELDIN_DREK, ]) -LOGIC_PLANETS: Sequence[PlanetData] = [ +ALL_PLANETS: Sequence[PlanetData] = [ NOVALIS, ARIDIA, KERWAN, @@ -189,9 +189,20 @@ class PlanetData(NamedTuple): VELDIN, ] +STARTING_PLANETS: Sequence[PlanetData] = [ + NOVALIS, + ARIDIA, + KERWAN, + BLARG, + BATALIA, + GASPAR, + ORXON, + HOVEN, +] + ALL_LOCATIONS: Sequence[LocationData] = [ location - for locations in [planet.locations for planet in LOGIC_PLANETS] + for locations in [planet.locations for planet in ALL_PLANETS] for location in locations ] From 478310c107421de61cbf78eb765072d6008aca27 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Mon, 18 Aug 2025 14:50:47 -0500 Subject: [PATCH 09/28] RAC: Move all golden weapons to Novalis --- worlds/RAC1/data/Locations.py | 29 ++++++++++++++--------------- worlds/RAC1/data/Planets.py | 10 +++++----- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/worlds/RAC1/data/Locations.py b/worlds/RAC1/data/Locations.py index 33e0c58023d5..8375f2953249 100644 --- a/worlds/RAC1/data/Locations.py +++ b/worlds/RAC1/data/Locations.py @@ -46,14 +46,24 @@ class LocationData: # Golden Weapon Locations NOVALIS_GOLD_WEAPON_1 = LocationData(95, "Novalis", "Novalis: Golden Weapon 1 - 20,000", Items.GOLDEN_BOMB_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_2 = LocationData(96, "Novalis", "Novalis: Golden Weapon 2 - 30,000", +NOVALIS_GOLD_WEAPON_2 = LocationData(100, "Novalis", "Novalis: Golden Weapon 2 - 60,000", + Items.GOLDEN_TESLA_CLAW.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_3 = LocationData(96, "Novalis", "Novalis: Golden Weapon 3 - 30,000", Items.GOLDEN_PYROCITOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_3 = LocationData(97, "Novalis", "Novalis: Golden Weapon 3 - 20,000", +NOVALIS_GOLD_WEAPON_4 = LocationData(101, "Novalis", "Novalis: Golden Weapon 4 - 60,000", + Items.GOLDEN_DEVASTATOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_5 = LocationData(97, "Novalis", "Novalis: Golden Weapon 5 - 20,000", Items.GOLDEN_BLASTER.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_4 = LocationData(98, "Novalis", "Novalis: Golden Weapon 4 - 10,000", +NOVALIS_GOLD_WEAPON_6 = LocationData(102, "Novalis", "Novalis: Golden Weapon 6 - 10,000", + Items.GOLDEN_MINE_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_7 = LocationData(98, "Novalis", "Novalis: Golden Weapon 7 - 10,000", Items.GOLDEN_GLOVE_OF_DOOM.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_5 = LocationData(99, "Novalis", "Novalis: Golden Weapon 5 - 10,000", +NOVALIS_GOLD_WEAPON_8 = LocationData(103, "Novalis", "Novalis: Golden Weapon 8 - 20,000", + Items.GOLDEN_MORPH_O_RAY.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_9 = LocationData(99, "Novalis", "Novalis: Golden Weapon 9 - 10,000", Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_10 = LocationData(104, "Novalis", "Novalis: Golden Weapon 10 - 10,000", + Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) # Skill Point Locations NOVALIS_SKILLPOINT = LocationData( @@ -205,17 +215,6 @@ class LocationData: 69, "Gemlik", "Gemlik: Defeat Captain Quark", Items.OLTANIS_INFOBOT.name, {POOL_INFOBOT}, gemlik_quark_rule) GEMLIK_GOLD_BOLT = LocationData( 70, "Gemlik", "Gemlik: Gold Bolt: Visibomb Hidden Tower", Items.GOLD_BOLT.name, {POOL_GOLD_BOLT}, gemlik_bolt_rule) -# Golden Weapon Locations -GEMLIK_GOLD_WEAPON_1 = LocationData(100, "Gemlik", "Gemlik: Golden Weapon 1 - 60,000", - Items.GOLDEN_TESLA_CLAW.name, {POOL_GOLDEN_WEAPON}, gemlik_gold_weapon_rule) -GEMLIK_GOLD_WEAPON_2 = LocationData(101, "Gemlik", "Gemlik: Golden Weapon 2 - 60,000", - Items.GOLDEN_DEVASTATOR.name, {POOL_GOLDEN_WEAPON}, gemlik_gold_weapon_rule) -GEMLIK_GOLD_WEAPON_3 = LocationData(102, "Gemlik", "Gemlik: Golden Weapon 3 - 10,000", - Items.GOLDEN_MINE_GLOVE.name, {POOL_GOLDEN_WEAPON}, gemlik_gold_weapon_rule) -GEMLIK_GOLD_WEAPON_4 = LocationData(103, "Gemlik", "Gemlik: Golden Weapon 4 - 20,000", - Items.GOLDEN_MORPH_O_RAY.name, {POOL_GOLDEN_WEAPON}, gemlik_gold_weapon_rule) -GEMLIK_GOLD_WEAPON_5 = LocationData(104, "Gemlik", "Gemlik: Golden Weapon 5 - 10,000", - Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, gemlik_gold_weapon_rule) # Oltanis OLTANIS_VENDOR_TESLA_CLAW = LocationData( diff --git a/worlds/RAC1/data/Planets.py b/worlds/RAC1/data/Planets.py index 35fc0c7d9f0c..cca2060e85cf 100644 --- a/worlds/RAC1/data/Planets.py +++ b/worlds/RAC1/data/Planets.py @@ -21,6 +21,11 @@ class PlanetData(NamedTuple): NOVALIS_GOLD_WEAPON_3, NOVALIS_GOLD_WEAPON_4, NOVALIS_GOLD_WEAPON_5, + NOVALIS_GOLD_WEAPON_6, + NOVALIS_GOLD_WEAPON_7, + NOVALIS_GOLD_WEAPON_8, + NOVALIS_GOLD_WEAPON_9, + NOVALIS_GOLD_WEAPON_10, ]) ARIDIA = PlanetData("Aridia", 2, [ @@ -121,11 +126,6 @@ class PlanetData(NamedTuple): GEMLIK = PlanetData("Gemlik", 13, [ GEMLIK_QUARK_FIGHT, GEMLIK_GOLD_BOLT, - GEMLIK_GOLD_WEAPON_1, - GEMLIK_GOLD_WEAPON_2, - GEMLIK_GOLD_WEAPON_3, - GEMLIK_GOLD_WEAPON_4, - GEMLIK_GOLD_WEAPON_5, ]) OLTANIS = PlanetData("Oltanis", 14, [ From fa1a299bd56efc2f30bbf85a9cdd9e02305a8e3a Mon Sep 17 00:00:00 2001 From: Myth197 Date: Mon, 18 Aug 2025 15:44:40 -0500 Subject: [PATCH 10/28] RAC: Add display names and rich text tags to Options --- worlds/RAC1/Options.py | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 0c6af9d97b34..be86d28fbd1f 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -28,6 +28,7 @@ class StartingItem(ItemOptions): random_item: Start with any random equipable item, weapons or gadgets. """ display_name = "Starting Item" + rich_text_doc = True default = 0 pool = "StartItem" @@ -44,6 +45,7 @@ class ShuffleWeapons(ItemOptions): unrestricted: Weapons are shuffled anywhere, anything can be found at Weapon locations. """ display_name = "Shuffle Weapons" + rich_text_doc = True default = 3 pool = "Weapons" @@ -55,6 +57,7 @@ class EarlyWeapon(TextChoice): Set to off if 'Randomize Weapon locations' option is set to 'vanilla or random_same'. """ display_name = "Early Weapon" + rich_text_doc = True class ShuffleGadgets(ItemOptions): @@ -65,6 +68,7 @@ class ShuffleGadgets(ItemOptions): unrestricted: Gadgets are shuffled anywhere, anything can be found at Gadget locations. """ display_name = "Shuffle Gadgets" + rich_text_doc = True default = 3 pool = "Gadgets" @@ -77,6 +81,7 @@ class ShufflePacks(ItemOptions): unrestricted: Packs are shuffled anywhere, anything can be found at Pack locations. """ display_name = "Shuffle Packs" + rich_text_doc = True default = 3 pool = "Packs" @@ -89,6 +94,7 @@ class ShuffleHelmets(ItemOptions): unrestricted: Helmets are shuffled anywhere, anything can be found at Helmet locations. """ display_name = "Shuffle Helmets" + rich_text_doc = True default = 3 pool = "Helmets" @@ -101,6 +107,7 @@ class ShuffleBoots(ItemOptions): unrestricted: Boots are shuffled anywhere, anything can be found at Boot locations. """ display_name = "Shuffle Boots" + rich_text_doc = True default = 3 pool = "Boots" @@ -113,6 +120,7 @@ class ShuffleExtraItems(ItemOptions): unrestricted: Extra Items are shuffled anywhere, anything can be found at Extra Item locations. """ display_name = "Shuffle Extra Items" + rich_text_doc = True default = 3 pool = "ExtraItems" @@ -131,7 +139,8 @@ class ShuffleInfobots(ItemOptions): WARNING! Using random_same, or random_item with no other pool selected, is likely to fail on solo worlds. unrestricted: Infobots are shuffled anywhere, anything can be found at Infobot locations. """ - display_name = "Shuffle Infobots" + display_name = "Shuffle Infobots"# + rich_text_doc = True default = 3 pool = "Infobots" @@ -144,6 +153,7 @@ class ShuffleGoldWeapons(ItemOptions): unrestricted: Gold Weapons are shuffled anywhere, anything can be found at Gold Weapon locations. """ display_name = "Shuffle Gold Weapons" + rich_text_doc = True default = 3 pool = "GoldenWeapons" @@ -169,7 +179,7 @@ class ProgressiveOptions(Choice): class GoldenWeaponProgression(ProgressiveOptions): - """Progressive Weapons + """ If enabled, make golden weapons and their standard variants progressive items. vanilla: Golden Weapons and Weapons are not progressive, Golden Weapons do nothing until their base item is found. @@ -177,7 +187,8 @@ class GoldenWeaponProgression(ProgressiveOptions): progressive: Golden Weapons and Weapons are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Golden Weapons and Weapons are progressive, the order of upgrading is reversed. progressive_random: Golden Weapons and Weapons are progressive, the order of upgrading is random.""" - display_name = "Golden Weapon Progression" + display_name = "Progressive Weapons" + rich_text_doc = True value: int option_vanilla = 0 option_normal = 1 @@ -190,12 +201,14 @@ class GoldenWeaponProgression(ProgressiveOptions): class PackProgression(ProgressiveOptions): - """Progressive Packs + """ vanilla: Packs are not progressive, each item is independent of other items. progressive: Packs are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Packs are progressive, the order of upgrading is reversed. progressive_random: Packs are progressive, the order of upgrading is random. """ + display_name = "Progressive Packs" + rich_text_doc = True value: int option_vanilla = 0 option_progressive = 1 @@ -206,12 +219,14 @@ class PackProgression(ProgressiveOptions): class HelmetProgression(ProgressiveOptions): - """Progressive Helmets + """ vanilla: Helmets are not progressive, each item is independent of other items. progressive: Helmets are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Helmets are progressive, the order of upgrading is reversed. progressive_random: Helmets are progressive, the order of upgrading is random. """ + display_name = "Progressive Helmets" + rich_text_doc = True value: int option_vanilla = 0 option_progressive = 1 @@ -222,12 +237,14 @@ class HelmetProgression(ProgressiveOptions): class BootsProgression(ProgressiveOptions): - """Progressive Boots + """ vanilla: Grind and Magneboots are not progressive, each item is independent of other items. progressive: Grind and Magneboots are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Grind and Magneboots are progressive, the order of upgrading is reversed. progressive_random: Grind and Magneboots are progressive, the order of upgrading is random. """ + display_name = "Progressive Boots" + rich_text_doc = True value: int option_vanilla = 0 option_progressive = 1 @@ -238,12 +255,14 @@ class BootsProgression(ProgressiveOptions): class HoverboardProgression(ProgressiveOptions): - """Progressive Hoverboard + """ vanilla: Hoverboard and Zoomerator are not progressive, each item is independent of other items. progressive: Hoverboard and Zoomerator are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Hoverboard and Zoomerator are progressive, the order of upgrading is reversed. progressive_random: Hoverboard and Zoomerator are progressive, the order of upgrading is random. """ + display_name = "Progressive Hoverboard" + rich_text_doc = True value: int option_vanilla = 0 option_progressive = 1 @@ -254,12 +273,14 @@ class HoverboardProgression(ProgressiveOptions): class RaritaniumProgression(ProgressiveOptions): - """Progressive Raritanium + """ vanilla: Raritanium and Persuader are not progressive, each item is independent of other items. progressive: Raritanium and Persuader are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Raritanium and Persuader are progressive, the order of upgrading is reversed. progressive_random: Raritanium and Persuader are progressive, the order of upgrading is random. """ + display_name = "Progressive Raritanium" + rich_text_doc = True value: int option_vanilla = 0 option_progressive = 1 @@ -270,12 +291,14 @@ class RaritaniumProgression(ProgressiveOptions): class NanotechProgression(ProgressiveOptions): - """Progressive Nanotech + """ vanilla: Nanotech is not progressive, each item is independent of other items. progressive: Nanotech are progressive, collecting multiple of an item will upgrade it. progressive_reversed: Nanotech are progressive, the order of upgrading is reversed. progressive_random: Nanotech are progressive, the order of upgrading is random. """ + display_name = "Progressive Nanotech" + rich_text_doc = True value: int option_vanilla = 0 option_progressive = 1 From c1704e9c9e11971f8b08671942ff36a8f384a698 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Mon, 18 Aug 2025 17:24:57 -0500 Subject: [PATCH 11/28] RAC: Make Weapons and Gold Weapons shuffle together when both enabled --- worlds/RAC1/__init__.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 5aeda6bd76d3..f85f71628118 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -9,7 +9,8 @@ from .data import Items, Locations, Planets from .data.Items import CollectableData, ItemData from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, - POOL_GOLD_BOLT, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_WEAPON) + POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, + POOL_WEAPON) from .data.Planets import ALL_LOCATIONS, location_groups, PlanetData from .Options import RacOptions, ShuffleInfobots, ShuffleWeapons, StartingItem, StartingLocation from .Regions import create_regions @@ -197,6 +198,8 @@ def fill_pool(self, pools, scope) -> (list, list): placed_locations[len(placed_locations) - 1].place_locked_item(item) case 1: for pool in pools: + if pool == POOL_GOLDEN_WEAPON and POOL_WEAPON in pools: + continue base_state = CollectionState(multiworld) item_sweep: Sequence[Item] = [] unplaced_items = [item for item in Items.ALL if item.name not in placed_items] @@ -204,6 +207,8 @@ def fill_pool(self, pools, scope) -> (list, list): item_sweep += [self.create_item(item)] for item in unplaced_items: if item.pool != pool: + if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools and item.pool == POOL_GOLDEN_WEAPON: + continue item_sweep += [self.create_item(item.name)] rac_logger.debug(f"Item Sweep: {item_sweep}") base_state = sweep_from_pool(base_state, item_sweep) @@ -215,6 +220,11 @@ def fill_pool(self, pools, scope) -> (list, list): loc_temp += [self.get_location(loc.name)] item_temp += [self.create_item(loc.vanilla_item)] placed_items += [loc.vanilla_item] + if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools: + if POOL_GOLDEN_WEAPON in loc.pools and loc.vanilla_item is not None: + loc_temp += [self.get_location(loc.name)] + item_temp += [self.create_item(loc.vanilla_item)] + placed_items += [loc.vanilla_item] rac_logger.debug(f"Randomize Locations: {loc_temp}") placed_locations += loc_temp self.random.shuffle(item_temp) @@ -277,6 +287,9 @@ def fill_pool(self, pools, scope) -> (list, list): def create_item(self, name: str, override: Optional[ItemClassification] = None) -> "Item": new_name = Items.check_progressive_item(self.options, name) + if Items.from_name(name).pool == POOL_WEAPON or Items.from_name(name).pool == POOL_GOLDEN_WEAPON: + rac_logger.debug(f"Checking progressive weapon: {name}") + rac_logger.debug(f"Weapon is: {new_name}") if override: return RacItem(new_name, override, self.item_name_to_id[new_name], self.player) item_data = Items.from_name(new_name) From 760c7ff8b2c8afaa8345465105e39f4e8e797677 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Mon, 18 Aug 2025 17:32:40 -0500 Subject: [PATCH 12/28] RAC: Logging changes --- worlds/RAC1/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index f85f71628118..dee780c2250f 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -156,11 +156,11 @@ def generate_early(self) -> None: self.multiworld.push_precollected(starting_planet) rac_logger.debug(f"Starting items: {self.starting_items}") - rac_logger.debug(f"Disabled Items:") + rac_logger.debug(f"___Vanilla Locations___") self.preplaced_locations += self.fill_pool(disabled_pools, 0) - rac_logger.debug(f"Restricted Items:") + rac_logger.debug(f"___Internal Shuffled Pools___") self.preplaced_locations += self.fill_pool(restricted_pools, 1) - rac_logger.debug(f"Useful Items:") + rac_logger.debug(f"___Group Shuffled Pools___") self.preplaced_locations += self.fill_pool(useful_pools, 2) rac_logger.debug(f"Pre-placed Items placed: {[loc.item for loc in self.preplaced_locations]}") rac_logger.debug(f"Pre-filled Locations removed: {self.preplaced_locations}") @@ -186,7 +186,7 @@ def fill_pool(self, pools, scope) -> (list, list): match scope: case 0: for pool in pools: - rac_logger.debug(f"Disabled Pool: {pool}") + rac_logger.debug(f"Disable Pool: {pool}") for loc in ALL_LOCATIONS: if pool in loc.pools and loc.vanilla_item is not None: if self.get_location(loc.name).item is not None: @@ -210,7 +210,7 @@ def fill_pool(self, pools, scope) -> (list, list): if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools and item.pool == POOL_GOLDEN_WEAPON: continue item_sweep += [self.create_item(item.name)] - rac_logger.debug(f"Item Sweep: {item_sweep}") + rac_logger.debug(f"Assumed collected: {item_sweep}") base_state = sweep_from_pool(base_state, item_sweep) rac_logger.debug(f"Restricted Pool: {pool}") loc_temp = [] @@ -249,7 +249,7 @@ def fill_pool(self, pools, scope) -> (list, list): item_sweep = [] base_state = CollectionState(multiworld) for pool in pools: - rac_logger.debug(f"Useful Pool: {pool}") + rac_logger.debug(f"add Pool: {pool}") for loc in ALL_LOCATIONS: if pool in loc.pools and loc.vanilla_item is not None: loc_temp += [self.get_location(loc.name)] From 8b1d3b556a15c448c8e734c725ef0a8ffa7dad75 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Tue, 19 Aug 2025 08:23:39 -0500 Subject: [PATCH 13/28] RAC: Starting Location changes --- worlds/RAC1/Options.py | 14 +++++++++++--- worlds/RAC1/Regions.py | 6 +----- worlds/RAC1/data/Items.py | 21 +++++++++++++++++++++ worlds/RAC1/data/Planets.py | 15 ++------------- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index be86d28fbd1f..2a341fcdd78c 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -21,7 +21,7 @@ class ItemOptions(Choice): alias_false = 0 -class StartingItem(ItemOptions): +class StartingItem(Choice): """Randomize what weapon you start the game with. vanilla: Start with the Bomb Glove. random_same: Start with a random weapon. @@ -29,14 +29,22 @@ class StartingItem(ItemOptions): """ display_name = "Starting Item" rich_text_doc = True + value: int + option_vanilla = 0 + option_random_same = 1 + option_random_item = 2 default = 0 + alias_true = 2 + alias_false = 0 pool = "StartItem" + class StartingLocation(Toggle): """Randomize what Planet you start on""" display_name = "Shuffle Starting Planet" default = 1 + class ShuffleWeapons(ItemOptions): """Randomize Weapon locations vanilla: Weapons are unshuffled. @@ -311,7 +319,7 @@ class NanotechProgression(ProgressiveOptions): @dataclass class RacOptions(PerGameCommonOptions): # death_link: DeathLink - # starting_item: StartingItem + starting_item: StartingItem starting_location: StartingLocation shuffle_weapons: ShuffleWeapons shuffle_gadgets: ShuffleGadgets @@ -335,8 +343,8 @@ class RacOptions(PerGameCommonOptions): def get_options_as_dict(options: RacOptions) -> dict[str, Any]: return { # "death_link", - "start_inventory_from_pool": dict(), # "starting_item": options.starting_item.option_vanilla, + "starting_item": options.starting_item.value, "starting_location": options.starting_location.value, "shuffle_weapons": options.shuffle_weapons.value, "shuffle_gadgets": options.shuffle_gadgets.value, diff --git a/worlds/RAC1/Regions.py b/worlds/RAC1/Regions.py index 8d40bb3c5683..59d4f1010a08 100644 --- a/worlds/RAC1/Regions.py +++ b/worlds/RAC1/Regions.py @@ -18,7 +18,7 @@ def create_regions(world: 'RacWorld'): menu = Region("Menu", world.player, world.multiworld) world.multiworld.regions.append(menu) - for planet_data in Planets.ALL_PLANETS: + for planet_data in Planets.LOGIC_PLANETS: if planet_data.locations: def generate_planet_access_rule(planet: PlanetData) -> typing.Callable[[CollectionState], bool]: def planet_access_rule(state: CollectionState): @@ -47,10 +47,6 @@ def planet_access_rule(state: CollectionState): menu.connect(region, None, generate_planet_access_rule(planet_data)) for location_data in planet_data.locations: - # Don't create the location if there is a "pool" it is in that is not enabled - # if location_data.name in world.disabled_pools: - # continue - def generate_access_rule(loc: LocationData) -> typing.Callable[[CollectionState], bool]: def access_rule(state: CollectionState): if loc.access_rule: diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 3040022d2a82..c78f4502e77f 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -297,6 +297,14 @@ class CollectableData(ItemData): VELDIN_INFOBOT, ] +STARTING_PLANETS: Sequence[ItemData] = [ + NOVALIS_INFOBOT, + KERWAN_INFOBOT, + BLARG_INFOBOT, + BATALIA_INFOBOT, + ORXON_INFOBOT, +] + SKILLPOINTS: Sequence[ItemData] = [ TAKE_AIM, SWING_IT, @@ -346,6 +354,18 @@ class CollectableData(ItemData): *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS] +def get_starting_planets(options) -> Sequence[ItemData]: + planets: Sequence[ItemData] = [] + for item in STARTING_PLANETS: + planets += [item] + if options.shuffle_infobots.value >= Options.ShuffleInfobots.option_unrestricted: + planets += [ARIDIA_INFOBOT] + if options.shuffle_helmets.value >= Options.ShuffleInfobots.option_unrestricted: + planets += [GASPAR_INFOBOT] + if options.shuffle_gold_bolts.value: + planets += [HOVEN_INFOBOT] + return planets + def from_id(item_id: int) -> ItemData: matching = [item for item in ALL if item.item_id == item_id] @@ -378,6 +398,7 @@ def get_item_groups() -> dict[str, set[str]]: } return groups + def check_progressive_item(options, item) -> str: new_item = item match from_name(item).pool: diff --git a/worlds/RAC1/data/Planets.py b/worlds/RAC1/data/Planets.py index cca2060e85cf..273c0df554ae 100644 --- a/worlds/RAC1/data/Planets.py +++ b/worlds/RAC1/data/Planets.py @@ -168,7 +168,7 @@ class PlanetData(NamedTuple): VELDIN_DREK, ]) -ALL_PLANETS: Sequence[PlanetData] = [ +LOGIC_PLANETS: Sequence[PlanetData] = [ NOVALIS, ARIDIA, KERWAN, @@ -189,20 +189,9 @@ class PlanetData(NamedTuple): VELDIN, ] -STARTING_PLANETS: Sequence[PlanetData] = [ - NOVALIS, - ARIDIA, - KERWAN, - BLARG, - BATALIA, - GASPAR, - ORXON, - HOVEN, -] - ALL_LOCATIONS: Sequence[LocationData] = [ location - for locations in [planet.locations for planet in ALL_PLANETS] + for locations in [planet.locations for planet in LOGIC_PLANETS] for location in locations ] From f2d521c9c1df2b1f0230615de5877a1ed4c4806e Mon Sep 17 00:00:00 2001 From: Myth197 Date: Tue, 19 Aug 2025 08:31:21 -0500 Subject: [PATCH 14/28] RAC: Bolt Packs --- worlds/RAC1/ItemPool.py | 3 +- worlds/RAC1/Logic.py | 15 ++++- worlds/RAC1/Options.py | 36 ++++++++++- worlds/RAC1/__init__.py | 106 +++++++++++++++++++------------- worlds/RAC1/data/Items.py | 24 +++++++- worlds/RAC1/data/Locations.py | 13 ++-- worlds/RAC1/test/TestOptions.py | 6 ++ 7 files changed, 147 insertions(+), 56 deletions(-) diff --git a/worlds/RAC1/ItemPool.py b/worlds/RAC1/ItemPool.py index caa484ca2e92..204e417bc89f 100644 --- a/worlds/RAC1/ItemPool.py +++ b/worlds/RAC1/ItemPool.py @@ -7,7 +7,8 @@ def get_classification(item: ItemData) -> ItemClassification: if (item in Items.PLANETS or item in Items.ALL_PACKS or item in Items.GADGETS - or item in Items.ALL_BOOTS): + or item in Items.ALL_BOOTS + or item == Items.GOLD_BOLT): return ItemClassification.progression if item in [ Items.TAUNTER, diff --git a/worlds/RAC1/Logic.py b/worlds/RAC1/Logic.py index 7f44300542f9..31831395754d 100644 --- a/worlds/RAC1/Logic.py +++ b/worlds/RAC1/Logic.py @@ -1,6 +1,11 @@ +import logging + from BaseClasses import CollectionState from .data import Items +rac_logger = logging.getLogger("Ratchet & Clank") +rac_logger.setLevel(logging.DEBUG) + def can_swingshot(state: CollectionState, player: int) -> bool: return state.has(Items.SWINGSHOT.name, player) @@ -100,7 +105,15 @@ def has_long_range_weapon(state: CollectionState, player: int) -> bool: def has_40_gold_bolts(state: CollectionState, player: int) -> bool: - return state.has(Items.GOLD_BOLT.name, player, 40) + factor = state.multiworld.worlds[player].options.pack_size_gold_bolts.value + count, mod = divmod(20, factor) + if mod != 0: + count = count // 1 + if state.count(Items.GOLD_BOLT.name, player) < count: + rac_logger.debug(f"Missing gold bolt packs from world, expected {count} but only had" + f" {state.count(Items.GOLD_BOLT.name, player)}. Can reach " + f"{state.prog_items}") + return state.has(Items.GOLD_BOLT.name, player, count) # Novalis diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 2a341fcdd78c..1eccda18370e 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Any -from Options import (Choice, PerGameCommonOptions, TextChoice, Toggle) +from Options import (Choice, PerGameCommonOptions, Range, TextChoice, Toggle) class ItemOptions(Choice): @@ -139,6 +139,24 @@ class ShuffleGoldBolts(Toggle): default = 1 +class GoldBoltPackSize(Range): + """ + Number of Gold Bolts received each time you collect a pack of Gold Bolts (Gold Bolts Shuffle Off forces this to 1) + """ + display_name = "Gold Bolt Pack Size" + default = 8 + range_start = 1 + range_end = 40 + + +class BoltPackSize(Range): + """Number of Bolts received each time you collect a pack of Bolts.""" + display_name = "Bolt Pack Size" + default = 15000 + range_start = 0 + range_end = 1000000 + + class ShuffleInfobots(ItemOptions): """Randomize Infobot locations vanilla: Infobots are unshuffled. @@ -147,7 +165,7 @@ class ShuffleInfobots(ItemOptions): WARNING! Using random_same, or random_item with no other pool selected, is likely to fail on solo worlds. unrestricted: Infobots are shuffled anywhere, anything can be found at Infobot locations. """ - display_name = "Shuffle Infobots"# + display_name = "Shuffle Infobots" # rich_text_doc = True default = 3 pool = "Infobots" @@ -165,6 +183,13 @@ class ShuffleGoldWeapons(ItemOptions): default = 3 pool = "GoldenWeapons" + +class ShuffleSkillPoints(Toggle): + """Randomize Skillpoint locations""" + display_name = "Shuffle Skillpoints" + default = 1 + + class EnableBoltMultiplier(Toggle): """Enables the bolt multiplier feature without being in New Game+.""" display_name = "Enable Bolt Multiplier" @@ -330,6 +355,9 @@ class RacOptions(PerGameCommonOptions): shuffle_gold_bolts: ShuffleGoldBolts shuffle_infobots: ShuffleInfobots shuffle_gold_weapons: ShuffleGoldWeapons + shuffle_skill_points: ShuffleSkillPoints + pack_size_gold_bolts: GoldBoltPackSize + pack_size_bolts: BoltPackSize # enable_bolt_multiplier: EnableBoltMultiplier progressive_weapons: GoldenWeaponProgression progressive_packs: PackProgression @@ -343,7 +371,6 @@ class RacOptions(PerGameCommonOptions): def get_options_as_dict(options: RacOptions) -> dict[str, Any]: return { # "death_link", - # "starting_item": options.starting_item.option_vanilla, "starting_item": options.starting_item.value, "starting_location": options.starting_location.value, "shuffle_weapons": options.shuffle_weapons.value, @@ -355,6 +382,9 @@ def get_options_as_dict(options: RacOptions) -> dict[str, Any]: "shuffle_gold_bolts": options.shuffle_gold_bolts.value, "shuffle_infobots": options.shuffle_infobots.value, "shuffle_gold_weapons": options.shuffle_gold_weapons.value, + "shuffle_skill_points": options.shuffle_skill_points, + "pack_size_gold_bolts": options.pack_size_gold_bolts.value, + "pack_size_bolts": options.pack_size_bolts.value, "progressive_weapons": options.progressive_weapons.value, "progressive_packs": options.progressive_packs.value, "progressive_helmets": options.progressive_helmets.value, diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index dee780c2250f..126d2b10cf0c 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -58,12 +58,13 @@ class RacWorld(World): location.location_id} item_name_groups = Items.get_item_groups() location_name_groups = location_groups + item_pool: dict[str, list[Item]] = {} starting_planet = Items.NOVALIS_INFOBOT.name starting_items: list[Item] = [] - preplaced_locations: list[Location] = [] + preplaced_items: list[Item] = [] - # def get_filler_item_name(self) -> str: - # return Items.BOLT_PACK.name + def get_filler_item_name(self) -> str: + return Items.BOLT_PACK.name def generate_early(self) -> None: rac_logger.debug(f"_________START EARLY GENERATION____________") @@ -72,9 +73,12 @@ def generate_early(self) -> None: self.player_name) rac_logger.warning("INCOMPLETE WORLD! Slot '%s' may require send_location/send_item for completion!", self.player_name) + self.item_pool: dict[str, list[Item]] = {} + self.starting_planet = Items.NOVALIS_INFOBOT.name self.starting_items = [] - self.preplaced_locations = [] - rac_logger.debug(f"Pre-placed Item List: {[loc.item for loc in self.preplaced_locations]}") + self.preplaced_items = [] + rac_logger.debug(f"Pre-placed Item List: {self.preplaced_items}") + rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") # TODO: Item Pools @@ -97,6 +101,10 @@ def generate_early(self) -> None: enabled_pools += [POOL_GOLD_BOLT] else: disabled_pools += [POOL_GOLD_BOLT] + # if self.options.shuffle_skill_points.value: + # enabled_pools += [POOL_SKILLPOINT] + # else: + # disabled_pools += [POOL_SKILLPOINT] rac_logger.debug(f"Iterating through Options:") for pool_option in shuffle_pools: rac_logger.debug(f"Option: {pool_option}") @@ -141,6 +149,25 @@ def generate_early(self) -> None: # self.random.shuffle(starting_item) # self.multiworld.push_precollected(self.create_item(starting_item[0].name)) # starting_item = self.create_item(starting_item[0].name) + if self.options.shuffle_gold_bolts.value: + pass + else: + self.options.pack_size_gold_bolts.value = 1 + + rac_logger.debug(f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}") + rac_logger.debug(f"___Generate Item Pool___") + option_list = Items.get_pool(self.options) + rac_logger.debug(f"length of option_list: {len(option_list)}") + rac_logger.debug(f"gold bolts in list: {option_list.count(Items.GOLD_BOLT)}") + for item in option_list: + rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") + item_list = self.item_pool.get(item.name) or [] + item_list.append(self.create_item(item.name)) + self.item_pool[item.name] = item_list + # if item.name in self.item_pool.keys(): + # self.item_pool[item.name].append(self.create_item(item.name)) + # else: + # self.item_pool |= {item.name: [self.create_item(item.name)]} if (self.options.shuffle_infobots == ShuffleInfobots.option_vanilla or self.options.starting_location == StartingLocation.option_false): @@ -166,23 +193,25 @@ def generate_early(self) -> None: rac_logger.debug(f"Pre-filled Locations removed: {self.preplaced_locations}") rac_logger.debug(f"_________END EARLY GENERATION____________") - # self.disabled_location_data = set(loc for loc in ALL_LOCATIONS if not loc.pools.issubset(enabled_pools)) - - # for location in ALL_LOCATIONS: - # if not location.pools.issubset(enabled_pools): - # logging.debug(f"disable: {location.name}") - # self.disabled_location_data.append(location) - # output: list[str] = list(loc.name for loc in self.disabled_location_data) - # logging.debug(f"disabled location data: {output}") - def fill_pool(self, pools, scope) -> (list, list): multiworld = self.multiworld - placed_items = [loc.item.name for loc in self.preplaced_locations] - starting_item_list = [item.name for item in self.starting_items] - placed_items += starting_item_list - placed_items += [*[Items.GOLD_BOLT.name] * 40] - unplaced_items: list[ItemData] = [item for item in Items.ALL if item.name not in placed_items] - placed_locations: list[Location] = [] + placed_items = self.preplaced_items + placed_items += self.starting_items + placed_items += self.item_pool[Items.GOLD_BOLT.name] + # for name in self.item_pool: + # if Items.from_name(name).pool == POOL_SKILLPOINT: + # placed_items += self.item_pool[name] + rac_logger.debug(f"placed_items: {placed_items}") + unplaced_items: list[Item] = [] + for name, items in self.item_pool.items(): + rac_logger.debug(f"Checking if {name} is unplaced") + if items: + if name == Items.GOLD_BOLT.name or items[0].name.endswith("Skill Point"): + continue + else: + rac_logger.debug(f"Add to unplaced: {name}") + unplaced_items += items + add_items: list[Item] = [] match scope: case 0: for pool in pools: @@ -306,31 +335,24 @@ def create_items(self) -> None: rac_logger.debug(f"_________START ITEM CREATION__________") items_to_add: list[Item] = [self.create_item(item.name) for item in Items.ALL] - # add gold bolts in whatever slots we have left - # unfilled = [i for i in self.multiworld.get_unfilled_locations(self.player) if not i.is_event] - # rac_logger.debug(self.multiworld.get_filled_locations(self.player)) - # rac_logger.debug(f"{len(items_to_add)} {len(unfilled)}") - # remain = len(unfilled) - len(items_to_add) - # assert remain >= 0, "There are more items than locations. This is not supported." - # rac_logger.debug(f"Not enough items to fill all locations. Adding {remain} filler items to the item pool") - # for _ in range(remain): - # items_to_add.append(self.create_item(Items.GOLD_BOLT.name, ItemClassification.filler)) - - items_to_remove: list[Item] = [loc.item for loc in self.preplaced_locations] - items_to_remove += self.starting_items - rac_logger.debug(f"Preplaced item list before removal: {items_to_remove}") - for item in items_to_remove: - items_to_add.remove(item) - rac_logger.debug(f"{item} removed") - if len(items_to_add) == len(self.multiworld.get_unfilled_locations(self.player)) - 1: - rac_logger.debug(f"Add item pool to multiworld: {items_to_add}") - self.multiworld.itempool.extend(items_to_add) - rac_logger.debug(f"_________END ITEM CREATION__________") - else: + # add bolt packs in whatever slots we have left + unfilled = [i for i in self.multiworld.get_unfilled_locations(self.player) if not i.is_event] + rac_logger.debug(f"Items:{len(items_to_add)}, Locations:{len(unfilled)}") + remain = len(unfilled) - len(items_to_add) + if remain < 0: rac_logger.debug(f"Items unplaced: {items_to_add}") rac_logger.debug(f"Locations unfilled: {self.multiworld.get_unfilled_locations(self.player)}") - raise FillError(f"Item Count: {len(items_to_add)} does not match Location count: " + raise FillError(f"Item Count: {len(items_to_add)} exceeds Location count: " f"{len(self.multiworld.get_unfilled_locations(self.player))}") + elif remain == 0: + pass + else: + rac_logger.debug(f"Not enough items to fill all locations. Adding {remain} filler items to the item pool") + for _ in range(remain): + items_to_add.append(self.create_item(Items.BOLT_PACK.name)) + rac_logger.debug(f"Add item pool to multiworld: {items_to_add}") + self.multiworld.itempool.extend(items_to_add) + rac_logger.debug(f"_________END ITEM CREATION__________") def set_rules(self) -> None: boss_location = self.multiworld.get_location(Locations.VELDIN_DREK.name, self.player) diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index c78f4502e77f..061a8bf24a79 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -138,8 +138,8 @@ class CollectableData(ItemData): # Collectables -GOLD_BOLT = CollectableData(301, "Gold Bolt", "GoldBolts", 40) - +GOLD_BOLT = ItemData(301, "Gold Bolt Pack", "GoldBolts") +BOLT_PACK = ItemData(302, "Bolt Pack", "Filler") WEAPONS: Sequence[ItemData] = [ TAUNTER, @@ -343,8 +343,11 @@ class CollectableData(ItemData): *PROGRESSIVE_HELMETS, *BOOTS, *PROGRESSIVE_BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS, *GOLD_BOLTS, - *PLANETS, *SKILLPOINTS] + *PLANETS, *SKILLPOINTS, BOLT_PACK] +ITEM_POOL: Sequence[ItemData] = [*PLANETS, *WEAPONS, *NON_PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, *GADGETS, *PACKS, + *HELMETS, *BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, + *NON_PROGRESSIVE_NANOTECHS] # *SKILLPOINTS ALL_WEAPONS: Sequence[ItemData] = [*WEAPONS, *NON_PROGRESSIVE_WEAPONS, *PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, *PROGRESSIVE_GOLDEN_WEAPONS] ALL_PACKS: Sequence[ItemData] = [*PACKS, *PROGRESSIVE_PACKS] @@ -353,6 +356,21 @@ class CollectableData(ItemData): ALL_EXTRA_ITEMS: Sequence[ItemData] = [*EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS] +ALL_STARTING: Sequence[ItemData] = [*ALL_WEAPONS, *GADGETS] + + +def get_pool(options) -> Sequence[ItemData]: + pool = [] + for item in ITEM_POOL: + pool += [item] + gb_count = 0 + if pool.count(GOLD_BOLT) > 0: + raise AssertionError("Gold Bolts should not be in the pool before getting added") + while gb_count < 40: + pool += [GOLD_BOLT] + gb_count += options.pack_size_gold_bolts + return pool + def get_starting_planets(options) -> Sequence[ItemData]: planets: Sequence[ItemData] = [] diff --git a/worlds/RAC1/data/Locations.py b/worlds/RAC1/data/Locations.py index 8375f2953249..8c31f8061563 100644 --- a/worlds/RAC1/data/Locations.py +++ b/worlds/RAC1/data/Locations.py @@ -16,7 +16,8 @@ POOL_INFOBOT: str = "Infobots" POOL_SKILLPOINT: str = "Skillpoint" -DEFAULT_LIST = list([POOL_WEAPON, POOL_GADGET, POOL_PACK, POOL_HELMET, POOL_BOOT, POOL_EXTRA_ITEM, POOL_INFOBOT]) +DEFAULT_LIST = list([POOL_WEAPON, POOL_GADGET, POOL_PACK, POOL_HELMET, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GOLD_BOLT, + POOL_INFOBOT]) ALL_POOLS = list([POOL_START_PLANET, POOL_START_ITEM, POOL_WEAPON, POOL_GOLDEN_WEAPON, POOL_GADGET, POOL_PACK, POOL_HELMET, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GOLD_BOLT, POOL_INFOBOT, POOL_SKILLPOINT]) @@ -47,23 +48,23 @@ class LocationData: NOVALIS_GOLD_WEAPON_1 = LocationData(95, "Novalis", "Novalis: Golden Weapon 1 - 20,000", Items.GOLDEN_BOMB_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_2 = LocationData(100, "Novalis", "Novalis: Golden Weapon 2 - 60,000", - Items.GOLDEN_TESLA_CLAW.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_TESLA_CLAW.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_3 = LocationData(96, "Novalis", "Novalis: Golden Weapon 3 - 30,000", Items.GOLDEN_PYROCITOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_4 = LocationData(101, "Novalis", "Novalis: Golden Weapon 4 - 60,000", - Items.GOLDEN_DEVASTATOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_DEVASTATOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_5 = LocationData(97, "Novalis", "Novalis: Golden Weapon 5 - 20,000", Items.GOLDEN_BLASTER.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_6 = LocationData(102, "Novalis", "Novalis: Golden Weapon 6 - 10,000", - Items.GOLDEN_MINE_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_MINE_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_7 = LocationData(98, "Novalis", "Novalis: Golden Weapon 7 - 10,000", Items.GOLDEN_GLOVE_OF_DOOM.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_8 = LocationData(103, "Novalis", "Novalis: Golden Weapon 8 - 20,000", - Items.GOLDEN_MORPH_O_RAY.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_MORPH_O_RAY.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_9 = LocationData(99, "Novalis", "Novalis: Golden Weapon 9 - 10,000", Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_10 = LocationData(104, "Novalis", "Novalis: Golden Weapon 10 - 10,000", - Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) # Skill Point Locations NOVALIS_SKILLPOINT = LocationData( diff --git a/worlds/RAC1/test/TestOptions.py b/worlds/RAC1/test/TestOptions.py index bb640ddcaec1..6665681a6b7f 100644 --- a/worlds/RAC1/test/TestOptions.py +++ b/worlds/RAC1/test/TestOptions.py @@ -67,6 +67,11 @@ class TestVanillaGoldBolts(RACTestBase): options = {"shuffle_gold_bolts": ShuffleGoldBolts.option_false} +class TestRandomGoldBolts(RACTestBase): + """Test Gold Bolts with a random pack size""" + options = {"pack_size_gold_bolts": GoldBoltPackSize.weighted_range("random-low")} + + class TestVanillaInfobots(RACTestBase): """Test Infobots unshuffled to verify beatable""" options = {"shuffle_infobots": ShuffleInfobots.option_vanilla} @@ -81,6 +86,7 @@ class TestUsefuls(RACTestBase): """Test Useful items local shuffle to verify beatable""" options = { "shuffle_weapons": ShuffleWeapons.option_random_item, + "shuffle_gold_weapons": ShuffleGoldWeapons.option_random_item, "shuffle_gadgets": ShuffleGadgets.option_random_item, "shuffle_packs": ShufflePacks.option_random_item, "shuffle_helmets": ShuffleHelmets.option_random_item, From 8f1039de629c505969e5d256650333bfd17df518 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Tue, 19 Aug 2025 08:35:35 -0500 Subject: [PATCH 15/28] RAC: Weapon Fixes --- worlds/RAC1/__init__.py | 58 +++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 126d2b10cf0c..a304e12944aa 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -7,7 +7,7 @@ from worlds.LauncherComponents import Component, components, SuffixIdentifier, Type from . import ItemPool from .data import Items, Locations, Planets -from .data.Items import CollectableData, ItemData +from .data.Items import ALL_WEAPONS, CollectableData, ItemData from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, POOL_WEAPON) @@ -221,24 +221,33 @@ def fill_pool(self, pools, scope) -> (list, list): if self.get_location(loc.name).item is not None: raise FillError(f"Slot {self.player_name} selected vanilla {pool}, but Location:" f" {loc.name} was already filled") - item = self.create_item(loc.vanilla_item) - placed_locations += [self.get_location(loc.name)] + if self.item_pool[loc.vanilla_item]: + item = self.item_pool[loc.vanilla_item].pop(0) + else: + rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be placed at {loc.name}, " + f"filler bolt pack placed instead") + item = self.create_item(Items.BOLT_PACK.name) + self.get_location(loc.name).place_locked_item(item) + add_items += [item] rac_logger.debug(f"vanilla: {loc.name}, item: {item}") - placed_locations[len(placed_locations) - 1].place_locked_item(item) case 1: for pool in pools: if pool == POOL_GOLDEN_WEAPON and POOL_WEAPON in pools: continue base_state = CollectionState(multiworld) - item_sweep: Sequence[Item] = [] - unplaced_items = [item for item in Items.ALL if item.name not in placed_items] - for item in starting_item_list: - item_sweep += [self.create_item(item)] + item_sweep = placed_items + rac_logger.debug(f"unplaced items: {unplaced_items}") for item in unplaced_items: - if item.pool != pool: - if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools and item.pool == POOL_GOLDEN_WEAPON: - continue - item_sweep += [self.create_item(item.name)] + rac_logger.debug(f"check {pool} pool: {item}") + item_pool = Items.from_name(item.name).pool + if item_pool != pool: + if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools and item_pool == POOL_GOLDEN_WEAPON: + rac_logger.debug(f"Gold Weapon skipped: {item}") + else: + rac_logger.debug(f"add to assumed: {item}") + item_sweep += [item] + else: + rac_logger.debug(f"{item} is in pool {pool}") rac_logger.debug(f"Assumed collected: {item_sweep}") base_state = sweep_from_pool(base_state, item_sweep) rac_logger.debug(f"Restricted Pool: {pool}") @@ -247,15 +256,25 @@ def fill_pool(self, pools, scope) -> (list, list): for loc in ALL_LOCATIONS: if pool in loc.pools and loc.vanilla_item is not None: loc_temp += [self.get_location(loc.name)] - item_temp += [self.create_item(loc.vanilla_item)] - placed_items += [loc.vanilla_item] + if self.item_pool[loc.vanilla_item]: + item_temp += [self.item_pool[loc.vanilla_item].pop(0)] + else: + rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be shuffled into pool {pool}" + f", filler bolt pack added instead") + item_temp += [self.create_item(Items.BOLT_PACK.name)] if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools: if POOL_GOLDEN_WEAPON in loc.pools and loc.vanilla_item is not None: loc_temp += [self.get_location(loc.name)] item_temp += [self.create_item(loc.vanilla_item)] placed_items += [loc.vanilla_item] + if self.item_pool[loc.vanilla_item]: + item_temp += [self.item_pool[loc.vanilla_item].pop(0)] + else: + rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be shuffled into pool" + f" {pool}, filler bolt pack added instead") + item_temp += [self.create_item(Items.BOLT_PACK.name)] rac_logger.debug(f"Randomize Locations: {loc_temp}") - placed_locations += loc_temp + add_items += item_temp self.random.shuffle(item_temp) rac_logger.debug(f"Shuffled items: {item_temp}") rac_logger.debug(f"Reachability before Shuffle: {base_state.reachable_regions}") @@ -264,9 +283,10 @@ def fill_pool(self, pools, scope) -> (list, list): if loc in loc_temp] rac_logger.debug(f"Reachable Locations: {reachable}") fill_restrictive(multiworld, base_state, loc_temp, item_temp, single_player_placement=True, - swap=True, name=f"RAC1 Restricted Item Fill: {pool}") - for loc in loc_temp: - placed_locations.remove(loc) + lock=False, swap=True, allow_partial=False, + name=f"RAC1 Restricted Item Fill: {pool}") + # for item in item_temp: + # add_items.remove(item) # if item_temp: # for loc in placed_locations: # rac_logger.debug(f"same group: {loc.name}, item: {loc.item}") @@ -275,7 +295,7 @@ def fill_pool(self, pools, scope) -> (list, list): case 2: loc_temp = [] item_temp = [] - item_sweep = [] + item_sweep = placed_items base_state = CollectionState(multiworld) for pool in pools: rac_logger.debug(f"add Pool: {pool}") From 6d6fdac0654bdd083a953b006e57d60dc7d713d1 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Tue, 19 Aug 2025 08:38:41 -0500 Subject: [PATCH 16/28] RAC: Start Inventory Fixes --- worlds/RAC1/__init__.py | 47 +++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index a304e12944aa..c2967639289d 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -133,22 +133,6 @@ def generate_early(self) -> None: rac_logger.debug(f"Creating Regions") create_regions(self) - # TODO: Item Pools: get_pre_fill_items() - # if (self.options.shuffle_weapons == ShuffleWeapons.option_vanilla or - # self.options.starting_item == StartingItem.option_vanilla): - starting_item = self.create_item(Items.BOMB_GLOVE.name) - # else: - # starting_item = [] - # match self.options.starting_item: - # case StartingItem.option_random_same: - # starting_item = list(Items.WEAPONS) - # case StartingItem.option_random_item: - # starting_item = [item for item in Items.ALL if item.name != "Gold Bolt"] - # case StartingItem.option_unrestricted: - # starting_item = list(Items.ALL) - # self.random.shuffle(starting_item) - # self.multiworld.push_precollected(self.create_item(starting_item[0].name)) - # starting_item = self.create_item(starting_item[0].name) if self.options.shuffle_gold_bolts.value: pass else: @@ -171,12 +155,33 @@ def generate_early(self) -> None: if (self.options.shuffle_infobots == ShuffleInfobots.option_vanilla or self.options.starting_location == StartingLocation.option_false): - starting_planet = self.create_item(Items.NOVALIS_INFOBOT.name) + starting_planet = self.item_pool[Items.NOVALIS_INFOBOT.name].pop(0) else: - starting_planet = list(Planets.STARTING_PLANETS) + starting_planet = [planet for planet in Items.get_starting_planets(self.options)] self.random.shuffle(starting_planet) self.starting_planet = starting_planet[0].name - starting_planet = self.create_item(starting_planet[0].name) + starting_planet = self.item_pool[starting_planet[0].name].pop(0) + rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") + + if (self.options.shuffle_weapons == ShuffleWeapons.option_vanilla or + self.options.starting_item == StartingItem.option_vanilla): + starting_item = self.item_pool[Items.BOMB_GLOVE.name].pop(0) + elif self.options.starting_item == StartingItem.option_random_same: + starting_item = [] + weapon_list = [item.name for item in Items.ALL_WEAPONS] + for name, item in self.item_pool.items(): + if name in weapon_list: + starting_item.extend(item) + self.random.shuffle(starting_item) + starting_item = self.item_pool[starting_item[0].name].pop(0) + else: + starting_item = [] + equip_list = [item.name for item in Items.ALL_STARTING] + for name, item in self.item_pool.items(): + if name in equip_list: + starting_item.extend(item) + self.random.shuffle(starting_item) + starting_item = self.item_pool[starting_item[0].name].pop(0) self.starting_items = [starting_item, starting_planet] self.multiworld.push_precollected(starting_item) @@ -349,7 +354,9 @@ def create_event(self, name: str) -> "Item": def get_pre_fill_items(self) -> list["Item"]: rac_logger.debug(f"fetching preplaced_items") - return [loc.item for loc in self.preplaced_locations] + items = self.starting_items + items += self.preplaced_items + return items def create_items(self) -> None: rac_logger.debug(f"_________START ITEM CREATION__________") From 1c8f91b978ea25c75544a90d11ecb868bd28f5d5 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Tue, 19 Aug 2025 08:39:52 -0500 Subject: [PATCH 17/28] RAC: Shuffle fixes --- worlds/RAC1/__init__.py | 55 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index c2967639289d..682726ec4076 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -1,7 +1,7 @@ import logging -from typing import Any, Mapping, Optional, Sequence +from typing import Any, Mapping, Optional -from BaseClasses import CollectionState, Item, ItemClassification, Location, Tutorial +from BaseClasses import CollectionState, Item, ItemClassification, Tutorial from Fill import fill_restrictive, FillError, sweep_from_pool from worlds.AutoWorld import WebWorld, World from worlds.LauncherComponents import Component, components, SuffixIdentifier, Type @@ -153,6 +153,7 @@ def generate_early(self) -> None: # else: # self.item_pool |= {item.name: [self.create_item(item.name)]} + rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") if (self.options.shuffle_infobots == ShuffleInfobots.option_vanilla or self.options.starting_location == StartingLocation.option_false): starting_planet = self.item_pool[Items.NOVALIS_INFOBOT.name].pop(0) @@ -186,16 +187,26 @@ def generate_early(self) -> None: self.starting_items = [starting_item, starting_planet] self.multiworld.push_precollected(starting_item) self.multiworld.push_precollected(starting_planet) + for name, count in self.options.start_inventory: + if count > len(self.item_pool[name]): + rac_logger.warning(f"Too many copies of {name} in yaml start inventory! Giving only " + f"{len(self.item_pool[name])} of {count} copies") + for i in range(count): + if self.item_pool[name]: + self.starting_items += [self.item_pool[name].pop(0)] + else: + break + rac_logger.debug(f"Starting items: {self.starting_items}") rac_logger.debug(f"___Vanilla Locations___") - self.preplaced_locations += self.fill_pool(disabled_pools, 0) + self.preplaced_items += self.fill_pool(disabled_pools, 0) rac_logger.debug(f"___Internal Shuffled Pools___") - self.preplaced_locations += self.fill_pool(restricted_pools, 1) + self.preplaced_items += self.fill_pool(restricted_pools, 1) rac_logger.debug(f"___Group Shuffled Pools___") - self.preplaced_locations += self.fill_pool(useful_pools, 2) - rac_logger.debug(f"Pre-placed Items placed: {[loc.item for loc in self.preplaced_locations]}") - rac_logger.debug(f"Pre-filled Locations removed: {self.preplaced_locations}") + self.preplaced_items += self.fill_pool(useful_pools, 2) + rac_logger.debug(f"Pre-placed Items placed: {self.preplaced_items}") + rac_logger.debug(f"Pre-filled Locations removed: {[loc.name for loc in self.get_locations() if loc.item]}") rac_logger.debug(f"_________END EARLY GENERATION____________") def fill_pool(self, pools, scope) -> (list, list): @@ -270,8 +281,6 @@ def fill_pool(self, pools, scope) -> (list, list): if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools: if POOL_GOLDEN_WEAPON in loc.pools and loc.vanilla_item is not None: loc_temp += [self.get_location(loc.name)] - item_temp += [self.create_item(loc.vanilla_item)] - placed_items += [loc.vanilla_item] if self.item_pool[loc.vanilla_item]: item_temp += [self.item_pool[loc.vanilla_item].pop(0)] else: @@ -308,26 +317,25 @@ def fill_pool(self, pools, scope) -> (list, list): if pool in loc.pools and loc.vanilla_item is not None: loc_temp += [self.get_location(loc.name)] if loc_temp: - for item in starting_item_list: - item_sweep += [self.create_item(item)] - for item in unplaced_items: - if item.name != Items.GOLD_BOLT.name: - item_temp += [self.create_item(item.name)] base_state = sweep_from_pool(base_state, item_sweep) rac_logger.debug(f"Randomizing Useful Locations: {loc_temp}") - placed_locations += loc_temp - self.random.shuffle(item_temp) + self.random.shuffle(unplaced_items) + for i in range(len(loc_temp)): + item_temp += [self.item_pool[unplaced_items[i].name].pop(0)] rac_logger.debug(f"Shuffled items: {item_temp}") + add_items += item_temp rac_logger.debug(f"Reachability before Shuffle: {base_state.reachable_regions}") reachable = [loc for loc in multiworld.get_reachable_locations(base_state, self.player) if loc in loc_temp] rac_logger.debug(f"Reachable Locations: {reachable}") # TODO: Try using remaining_fill() to prevent deadend seeds fill_restrictive(multiworld, base_state, loc_temp, item_temp, single_player_placement=True, - swap=True, allow_partial=True, allow_excluded=True, - name="RAC1 Useful Item Fill") - for loc in loc_temp: - placed_locations.remove(loc) + lock=False, swap=True, allow_partial=True, name="RAC1 Useful Item Fill") + for item in item_temp: + add_items.remove(item) + item_list = self.item_pool.get(item.name) or [] + item_list.append(self.create_item(item.name)) + self.item_pool[item.name] = item_list # if loc_temp: # for loc in placed_locations: # rac_logger.debug(f"any item: {loc.name}, item: {loc.item}") @@ -337,7 +345,7 @@ def fill_pool(self, pools, scope) -> (list, list): # else: # raise FillError(f"Slot {self.player_name} has locations requiring useful items that are " # f"unfilled, No items left to get placed at Locations: {loc_temp}") - return placed_locations + return add_items def create_item(self, name: str, override: Optional[ItemClassification] = None) -> "Item": new_name = Items.check_progressive_item(self.options, name) @@ -360,7 +368,10 @@ def get_pre_fill_items(self) -> list["Item"]: def create_items(self) -> None: rac_logger.debug(f"_________START ITEM CREATION__________") - items_to_add: list[Item] = [self.create_item(item.name) for item in Items.ALL] + rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") + items_to_add: list[Item] = [] + for items in self.item_pool.values(): + items_to_add.extend(items) # add bolt packs in whatever slots we have left unfilled = [i for i in self.multiworld.get_unfilled_locations(self.player) if not i.is_event] From 8d9e993e5a6d56ac854cefbc152940bf7349b0f7 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Tue, 19 Aug 2025 11:45:07 -0500 Subject: [PATCH 18/28] RAC: Disable Skillpoints --- worlds/RAC1/Options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 1eccda18370e..70c71a074876 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -355,7 +355,7 @@ class RacOptions(PerGameCommonOptions): shuffle_gold_bolts: ShuffleGoldBolts shuffle_infobots: ShuffleInfobots shuffle_gold_weapons: ShuffleGoldWeapons - shuffle_skill_points: ShuffleSkillPoints + # shuffle_skill_points: ShuffleSkillPoints pack_size_gold_bolts: GoldBoltPackSize pack_size_bolts: BoltPackSize # enable_bolt_multiplier: EnableBoltMultiplier @@ -382,7 +382,7 @@ def get_options_as_dict(options: RacOptions) -> dict[str, Any]: "shuffle_gold_bolts": options.shuffle_gold_bolts.value, "shuffle_infobots": options.shuffle_infobots.value, "shuffle_gold_weapons": options.shuffle_gold_weapons.value, - "shuffle_skill_points": options.shuffle_skill_points, + # "shuffle_skill_points": options.shuffle_skill_points.value, "pack_size_gold_bolts": options.pack_size_gold_bolts.value, "pack_size_bolts": options.pack_size_bolts.value, "progressive_weapons": options.progressive_weapons.value, From ff6e29ee2cdd233dd4f8e5793363d296a4339155 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Wed, 20 Aug 2025 16:12:07 -0500 Subject: [PATCH 19/28] RAC: Fix Gold Weapon Numbering --- worlds/RAC1/data/Locations.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/worlds/RAC1/data/Locations.py b/worlds/RAC1/data/Locations.py index 8c31f8061563..542d62d3b148 100644 --- a/worlds/RAC1/data/Locations.py +++ b/worlds/RAC1/data/Locations.py @@ -45,26 +45,26 @@ class LocationData: NOVALIS_UNDERWATER_CAVES_GOLD_BOLT = LocationData(6, "Novalis", "Novalis: Gold Bolt: Amoeboid Caves", Items.GOLD_BOLT.name, {POOL_GOLD_BOLT}, novalis_underwater_caves_rule) # Golden Weapon Locations -NOVALIS_GOLD_WEAPON_1 = LocationData(95, "Novalis", "Novalis: Golden Weapon 1 - 20,000", - Items.GOLDEN_BOMB_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_2 = LocationData(100, "Novalis", "Novalis: Golden Weapon 2 - 60,000", +NOVALIS_GOLD_WEAPON_1 = LocationData(100, "Novalis", "Novalis: Golden Weapon 1 - 60,000", Items.GOLDEN_TESLA_CLAW.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_3 = LocationData(96, "Novalis", "Novalis: Golden Weapon 3 - 30,000", - Items.GOLDEN_PYROCITOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_4 = LocationData(101, "Novalis", "Novalis: Golden Weapon 4 - 60,000", +NOVALIS_GOLD_WEAPON_2 = LocationData(95, "Novalis", "Novalis: Golden Weapon 2 - 20,000", + Items.GOLDEN_BOMB_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_3 = LocationData(101, "Novalis", "Novalis: Golden Weapon 3 - 60,000", Items.GOLDEN_DEVASTATOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_5 = LocationData(97, "Novalis", "Novalis: Golden Weapon 5 - 20,000", - Items.GOLDEN_BLASTER.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_6 = LocationData(102, "Novalis", "Novalis: Golden Weapon 6 - 10,000", +NOVALIS_GOLD_WEAPON_4 = LocationData(96, "Novalis", "Novalis: Golden Weapon 4 - 30,000", + Items.GOLDEN_PYROCITOR.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_5 = LocationData(102, "Novalis", "Novalis: Golden Weapon 5 - 10,000", Items.GOLDEN_MINE_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_7 = LocationData(98, "Novalis", "Novalis: Golden Weapon 7 - 10,000", - Items.GOLDEN_GLOVE_OF_DOOM.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_8 = LocationData(103, "Novalis", "Novalis: Golden Weapon 8 - 20,000", +NOVALIS_GOLD_WEAPON_6 = LocationData(97, "Novalis", "Novalis: Golden Weapon 6 - 20,000", + Items.GOLDEN_BLASTER.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_7 = LocationData(103, "Novalis", "Novalis: Golden Weapon 7 - 20,000", Items.GOLDEN_MORPH_O_RAY.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_9 = LocationData(99, "Novalis", "Novalis: Golden Weapon 9 - 10,000", - Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) -NOVALIS_GOLD_WEAPON_10 = LocationData(104, "Novalis", "Novalis: Golden Weapon 10 - 10,000", +NOVALIS_GOLD_WEAPON_8 = LocationData(98, "Novalis", "Novalis: Golden Weapon 8 - 10,000", + Items.GOLDEN_GLOVE_OF_DOOM.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_9 = LocationData(104, "Novalis", "Novalis: Golden Weapon 9 - 10,000", Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) +NOVALIS_GOLD_WEAPON_10 = LocationData(99, "Novalis", "Novalis: Golden Weapon 10 - 10,000", + Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) # Skill Point Locations NOVALIS_SKILLPOINT = LocationData( From b3c51a32f9f117b4623656d2acecdda1387419f3 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Thu, 21 Aug 2025 21:20:12 -0500 Subject: [PATCH 20/28] RAC: Bolt and Gold Bolt Pack names --- worlds/RAC1/ItemPool.py | 4 ++-- worlds/RAC1/Logic.py | 5 +++-- worlds/RAC1/__init__.py | 7 ++++++- worlds/RAC1/data/Items.py | 18 +++++++++++++++++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/worlds/RAC1/ItemPool.py b/worlds/RAC1/ItemPool.py index 204e417bc89f..d768659a1b9f 100644 --- a/worlds/RAC1/ItemPool.py +++ b/worlds/RAC1/ItemPool.py @@ -7,8 +7,7 @@ def get_classification(item: ItemData) -> ItemClassification: if (item in Items.PLANETS or item in Items.ALL_PACKS or item in Items.GADGETS - or item in Items.ALL_BOOTS - or item == Items.GOLD_BOLT): + or item in Items.ALL_BOOTS): return ItemClassification.progression if item in [ Items.TAUNTER, @@ -30,6 +29,7 @@ def get_classification(item: ItemData) -> ItemClassification: Items.VISIBOMB, Items.RYNO, Items.PROGRESSIVE_TRADE, + Items.GOLD_BOLT, ]: return ItemClassification.progression if (item == Items.SONIC_SUMMONER diff --git a/worlds/RAC1/Logic.py b/worlds/RAC1/Logic.py index 31831395754d..6ebbf297b104 100644 --- a/worlds/RAC1/Logic.py +++ b/worlds/RAC1/Logic.py @@ -105,10 +105,11 @@ def has_long_range_weapon(state: CollectionState, player: int) -> bool: def has_40_gold_bolts(state: CollectionState, player: int) -> bool: - factor = state.multiworld.worlds[player].options.pack_size_gold_bolts.value - count, mod = divmod(20, factor) + count, mod = divmod(20, Items.GOLD_BOLT.quantity) if mod != 0: count = count // 1 + if count < 1: + count = 1 if state.count(Items.GOLD_BOLT.name, player) < count: rac_logger.debug(f"Missing gold bolt packs from world, expected {count} but only had" f" {state.count(Items.GOLD_BOLT.name, player)}. Can reach " diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 682726ec4076..6c76f9e33bb5 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -7,7 +7,7 @@ from worlds.LauncherComponents import Component, components, SuffixIdentifier, Type from . import ItemPool from .data import Items, Locations, Planets -from .data.Items import ALL_WEAPONS, CollectableData, ItemData +from .data.Items import ALL_WEAPONS, CollectableData, ItemData, progression_rules, set_quantity from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, POOL_WEAPON) @@ -137,6 +137,11 @@ def generate_early(self) -> None: pass else: self.options.pack_size_gold_bolts.value = 1 + set_quantity(Items.GOLD_BOLT, self.options.pack_size_gold_bolts.value) + set_quantity(Items.BOLT_PACK, self.options.pack_size_bolts.value) + rac_logger.debug( + f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}, Bolt pack size: " + f"{self.options.pack_size_bolts.value}") rac_logger.debug(f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}") rac_logger.debug(f"___Generate Item Pool___") diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 061a8bf24a79..234ca6ed5b56 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -10,6 +10,7 @@ class ItemData(Item): item_id: int name: str pool: str + quantity: int = 1 HELI_PACK = ItemData(2, "Heli Pack", "Packs") @@ -139,7 +140,7 @@ class CollectableData(ItemData): # Collectables GOLD_BOLT = ItemData(301, "Gold Bolt Pack", "GoldBolts") -BOLT_PACK = ItemData(302, "Bolt Pack", "Filler") +BOLT_PACK = ItemData(302, "Bolt Pack", "Filler", 15000) WEAPONS: Sequence[ItemData] = [ TAUNTER, @@ -464,3 +465,18 @@ def check_progressive_item(options, item) -> str: if options.progressive_nanotech.value: new_item = PROGRESSIVE_NANOTECH.name return new_item + + +def set_quantity(item, count): + item.quantity = count + if count == 1: + item.name = f"{item.quantity} - {item.name}" + elif 1000 <= count < 1000000: + temp0 = count // 1000 + temp1 = count - (temp0 * 1000) + item.name = f"{temp0},{temp1} - {item.name}s" + elif count == 1000000: + item.name = f"1 MILLION - {item.name}s" + else: + item.name = f"{item.quantity} - {item.name}s" + return From 644cd4a10571e7678d6c25412ebe3ce6da63035a Mon Sep 17 00:00:00 2001 From: Myth197 Date: Fri, 22 Aug 2025 01:59:48 -0500 Subject: [PATCH 21/28] RAC: Bolt Multiplier Options --- worlds/RAC1/Options.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 70c71a074876..31b99555bf8a 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -190,9 +190,20 @@ class ShuffleSkillPoints(Toggle): default = 1 -class EnableBoltMultiplier(Toggle): +class EnableBoltMultiplier(Range): """Enables the bolt multiplier feature without being in New Game+.""" - display_name = "Enable Bolt Multiplier" + display_name = "Bolt Multiplier" + default = 5 + range_start = 1 + range_end = 20 + + +class MDBoltMultiplier(Range): + """Bolt Multiplier when using the metal detector""" + display_name = "Metal Detector Bolt Multiplier" + default = 35 + range_start = 1 + range_end = 100 class ProgressiveOptions(Choice): @@ -358,7 +369,8 @@ class RacOptions(PerGameCommonOptions): # shuffle_skill_points: ShuffleSkillPoints pack_size_gold_bolts: GoldBoltPackSize pack_size_bolts: BoltPackSize - # enable_bolt_multiplier: EnableBoltMultiplier + metal_bolt_multiplier: MDBoltMultiplier + enable_bolt_multiplier: EnableBoltMultiplier progressive_weapons: GoldenWeaponProgression progressive_packs: PackProgression progressive_helmets: HelmetProgression @@ -385,6 +397,8 @@ def get_options_as_dict(options: RacOptions) -> dict[str, Any]: # "shuffle_skill_points": options.shuffle_skill_points.value, "pack_size_gold_bolts": options.pack_size_gold_bolts.value, "pack_size_bolts": options.pack_size_bolts.value, + "metal_bolt_multiplier": options.metal_bolt_multiplier.value, + "enable_bolt_multiplier": options.enable_bolt_multiplier.value, "progressive_weapons": options.progressive_weapons.value, "progressive_packs": options.progressive_packs.value, "progressive_helmets": options.progressive_helmets.value, From d3b3ea72ccd7d77b101f9adde4aff19d3903aba4 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Fri, 22 Aug 2025 02:05:12 -0500 Subject: [PATCH 22/28] RAC: Starting Planet - Novalis Fix --- worlds/RAC1/__init__.py | 3 +++ worlds/RAC1/data/Items.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 6c76f9e33bb5..a722dbacf990 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -279,6 +279,9 @@ def fill_pool(self, pools, scope) -> (list, list): loc_temp += [self.get_location(loc.name)] if self.item_pool[loc.vanilla_item]: item_temp += [self.item_pool[loc.vanilla_item].pop(0)] + elif (self.starting_planet != Items.NOVALIS_INFOBOT.name and pool in + Items.NOVALIS_INFOBOT.pool): + item_temp += [self.item_pool[Items.NOVALIS_INFOBOT.name].pop(0)] else: rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be shuffled into pool {pool}" f", filler bolt pack added instead") diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 234ca6ed5b56..ddab7bb66f34 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -379,7 +379,7 @@ def get_starting_planets(options) -> Sequence[ItemData]: planets += [item] if options.shuffle_infobots.value >= Options.ShuffleInfobots.option_unrestricted: planets += [ARIDIA_INFOBOT] - if options.shuffle_helmets.value >= Options.ShuffleInfobots.option_unrestricted: + if options.shuffle_helmets.value >= Options.ShuffleHelmets.option_unrestricted: planets += [GASPAR_INFOBOT] if options.shuffle_gold_bolts.value: planets += [HOVEN_INFOBOT] From 282a7b1c5ab4c4c4eca456a6d06b8c9512a6616e Mon Sep 17 00:00:00 2001 From: Myth197 Date: Fri, 22 Aug 2025 02:07:43 -0500 Subject: [PATCH 23/28] RAC: Vanilla Gold Bolts and Bolt Name Fixes --- worlds/RAC1/__init__.py | 13 +++++++---- worlds/RAC1/data/Items.py | 41 +++++++++++++++++++++++------------ worlds/RAC1/data/Locations.py | 2 +- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index a722dbacf990..0d78a8df961b 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -108,7 +108,7 @@ def generate_early(self) -> None: rac_logger.debug(f"Iterating through Options:") for pool_option in shuffle_pools: rac_logger.debug(f"Option: {pool_option}") - match pool_option.value: # TODO: starting item and planet + match pool_option.value: case Options.ItemOptions.option_vanilla: disabled_pools += [pool_option.pool] case Options.ItemOptions.option_random_same: @@ -137,8 +137,11 @@ def generate_early(self) -> None: pass else: self.options.pack_size_gold_bolts.value = 1 - set_quantity(Items.GOLD_BOLT, self.options.pack_size_gold_bolts.value) - set_quantity(Items.BOLT_PACK, self.options.pack_size_bolts.value) + + self.item_name_to_id[set_quantity(Items.GOLD_BOLT, self.options.pack_size_gold_bolts.value)] = ( + Items.GOLD_BOLT.item_id) + self.item_name_to_id[set_quantity(Items.BOLT_PACK, self.options.pack_size_bolts.value)] = ( + Items.BOLT_PACK.item_id) rac_logger.debug( f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}, Bolt pack size: " f"{self.options.pack_size_bolts.value}") @@ -242,7 +245,9 @@ def fill_pool(self, pools, scope) -> (list, list): if self.get_location(loc.name).item is not None: raise FillError(f"Slot {self.player_name} selected vanilla {pool}, but Location:" f" {loc.name} was already filled") - if self.item_pool[loc.vanilla_item]: + elif pool == Items.GOLD_BOLT.pool: + item = self.item_pool[Items.GOLD_BOLT.name].pop(0) + elif self.item_pool[loc.vanilla_item]: item = self.item_pool[loc.vanilla_item].pop(0) else: rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be placed at {loc.name}, " diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index ddab7bb66f34..4dedc71baec5 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -343,7 +343,7 @@ class CollectableData(ItemData): *PROGRESSIVE_GOLDEN_WEAPONS, *GADGETS, *PACKS, *PROGRESSIVE_PACKS, *HELMETS, *PROGRESSIVE_HELMETS, *BOOTS, *PROGRESSIVE_BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, - *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS, *GOLD_BOLTS, + *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS, GOLD_BOLT, *PLANETS, *SKILLPOINTS, BOLT_PACK] ITEM_POOL: Sequence[ItemData] = [*PLANETS, *WEAPONS, *NON_PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, *GADGETS, *PACKS, @@ -390,7 +390,7 @@ def from_id(item_id: int) -> ItemData: matching = [item for item in ALL if item.item_id == item_id] if len(matching) == 0: raise ValueError(f"No item data for item id '{item_id}'") - assert len(matching) < 2, f"Multiple item data with id '{item_id}'. Please report." + assert len(matching) < 2, f"{len(matching)} item data found with id '{item_id}'. Items are: {matching}" return matching[0] @@ -467,16 +467,29 @@ def check_progressive_item(options, item) -> str: return new_item -def set_quantity(item, count): +def set_quantity(item, count) -> str: item.quantity = count - if count == 1: - item.name = f"{item.quantity} - {item.name}" - elif 1000 <= count < 1000000: - temp0 = count // 1000 - temp1 = count - (temp0 * 1000) - item.name = f"{temp0},{temp1} - {item.name}s" - elif count == 1000000: - item.name = f"1 MILLION - {item.name}s" - else: - item.name = f"{item.quantity} - {item.name}s" - return + match item.item_id: + case BOLT_PACK.item_id: + if count == 1: + item.name = f"A Single Bolt" + elif count == 0: + item.name = f"Nothing" + elif 1000 <= count < 1000000: + temp0 = count // 1000 + temp1 = count - (temp0 * 1000) + item.name = f"{temp0},{temp1} Bolts" + elif count == 1000000: + item.name = f"1 MILLION BOLTS!!!" + else: + item.name = f"{item.quantity} Bolts" + BOLT_PACK.name = item.name + case GOLD_BOLT.item_id: + if count == 1: + item.name = f"A Gold Bolt" + else: + item.name = f"{item.quantity} Gold Bolts" + GOLD_BOLT.name = item.name + case _: + raise Exception(f"Awww heck! {item.name} was tried to be turned into a pack!") + return item.name diff --git a/worlds/RAC1/data/Locations.py b/worlds/RAC1/data/Locations.py index 542d62d3b148..4b046906e183 100644 --- a/worlds/RAC1/data/Locations.py +++ b/worlds/RAC1/data/Locations.py @@ -12,7 +12,7 @@ POOL_HELMET: str = "Helmets" POOL_BOOT: str = "Boots" POOL_EXTRA_ITEM: str = "ExtraItems" -POOL_GOLD_BOLT: str = "GoldBolt" +POOL_GOLD_BOLT: str = "GoldBolts" POOL_INFOBOT: str = "Infobots" POOL_SKILLPOINT: str = "Skillpoint" From 69dfd3dd88548924cb37654df0252ba15eeb75a8 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Fri, 22 Aug 2025 03:25:15 -0500 Subject: [PATCH 24/28] RAC: Progressive Item order --- worlds/RAC1/Logic.py | 43 +++-- worlds/RAC1/__init__.py | 52 ++++-- worlds/RAC1/data/Items.py | 293 +++++++++++++++++++++++++++++++++- worlds/RAC1/data/Locations.py | 4 +- 4 files changed, 345 insertions(+), 47 deletions(-) diff --git a/worlds/RAC1/Logic.py b/worlds/RAC1/Logic.py index 6ebbf297b104..b5e81736f907 100644 --- a/worlds/RAC1/Logic.py +++ b/worlds/RAC1/Logic.py @@ -12,35 +12,32 @@ def can_swingshot(state: CollectionState, player: int) -> bool: def can_improved_jump(state: CollectionState, player: int) -> bool: - return state.has_any([Items.HELI_PACK.name, Items.THRUSTER_PACK.name], player) + return (state.has_any_count(Items.PROG[Items.HELI_PACK.name], player) or + state.has_any_count(Items.PROG[Items.THRUSTER_PACK.name], player)) def can_heli_high_jump(state: CollectionState, player: int) -> bool: # relevant for eudora gold bolt - return state.has(Items.HELI_PACK.name, player) + return state.has_any_count(Items.PROG[Items.HELI_PACK.name], player) def can_glide(state: CollectionState, player: int) -> bool: # gliding is not possible without the heli pack - return state.has(Items.HELI_PACK.name, player) + return state.has_any_count(Items.PROG[Items.HELI_PACK.name], player) def can_ground_pound(state: CollectionState, player: int) -> bool: - return state.has(Items.THRUSTER_PACK.name, player) + return state.has_any_count(Items.PROG[Items.THRUSTER_PACK.name], player) def has_hydro_pack(state: CollectionState, player: int) -> bool: - return state.has(Items.HYDRO_PACK.name, player) + return state.has_any_count(Items.PROG[Items.HYDRO_PACK.name], player) def can_grind(state: CollectionState, player: int) -> bool: - return state.has(Items.GRINDBOOTS.name, player) + return state.has_any_count(Items.PROG[Items.GRINDBOOTS.name], player) def has_magneboots(state: CollectionState, player: int) -> bool: - return state.has(Items.MAGNEBOOTS.name, player) - - -def can_taunt(state: CollectionState, player: int) -> bool: - return state.has(Items.TAUNTER.name, player) + return state.has_any_count(Items.PROG[Items.MAGNEBOOTS.name], player) def has_hydrodisplacer(state: CollectionState, player: int) -> bool: @@ -48,19 +45,19 @@ def has_hydrodisplacer(state: CollectionState, player: int) -> bool: def has_raritanium(state: CollectionState, player: int) -> bool: - return state.has(Items.RARITANIUM.name, player) + return state.has_any_count(Items.PROG[Items.RARITANIUM.name], player) def has_zoomerator(state: CollectionState, player: int) -> bool: - return state.has(Items.ZOOMERATOR.name, player) + return state.has_any_count(Items.PROG[Items.ZOOMERATOR.name], player) def has_hoverboard(state: CollectionState, player: int) -> bool: - return state.has(Items.HOVERBOARD.name, player) + return state.has_any_count(Items.PROG[Items.HOVERBOARD.name], player) def has_o2_mask(state: CollectionState, player: int) -> bool: - return state.has(Items.O2_MASK.name, player) + return state.has_any_count(Items.PROG[Items.O2_MASK.name], player) def has_trespasser(state: CollectionState, player: int) -> bool: @@ -76,7 +73,7 @@ def has_hologuise(state: CollectionState, player: int) -> bool: def has_pilots_helmet(state: CollectionState, player: int) -> bool: - return state.has(Items.PILOTS_HELMET.name, player) + return state.has_any_count(Items.PROG[Items.PILOTS_HELMET.name], player) def has_codebot(state: CollectionState, player: int) -> bool: @@ -92,16 +89,16 @@ def has_metal_detector(state: CollectionState, player: int) -> bool: def has_explosive_weapon(state: CollectionState, player: int) -> bool: - return (state.has_any( - [Items.BOMB_GLOVE.name, Items.MINE_GLOVE.name, Items.DEVASTATOR.name, Items.VISIBOMB.name, Items.RYNO.name], - player)) + return (state.has_any_count(Items.PROG[Items.BOMB_GLOVE.name], player) or + state.has_any_count(Items.PROG[Items.MINE_GLOVE.name], player) or + state.has_any_count(Items.PROG[Items.DEVASTATOR.name], player) or + state.has_any([Items.VISIBOMB.name, Items.RYNO.name], player)) def has_long_range_weapon(state: CollectionState, player: int) -> bool: - return (state.has_any([Items.BLASTER.name, - Items.DEVASTATOR.name, - Items.VISIBOMB.name, - Items.RYNO.name], player)) + return (state.has_any_count(Items.PROG[Items.BLASTER.name], player) or + state.has_any_count(Items.PROG[Items.DEVASTATOR.name], player) or + state.has_any([Items.VISIBOMB.name, Items.RYNO.name], player)) def has_40_gold_bolts(state: CollectionState, player: int) -> bool: diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 0d78a8df961b..26eb7cab8c44 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -7,7 +7,7 @@ from worlds.LauncherComponents import Component, components, SuffixIdentifier, Type from . import ItemPool from .data import Items, Locations, Planets -from .data.Items import ALL_WEAPONS, CollectableData, ItemData, progression_rules, set_quantity +from .data.Items import ALL_WEAPONS, CollectableData, progression_rules, set_quantity from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, POOL_WEAPON) @@ -60,8 +60,8 @@ class RacWorld(World): location_name_groups = location_groups item_pool: dict[str, list[Item]] = {} starting_planet = Items.NOVALIS_INFOBOT.name - starting_items: list[Item] = [] preplaced_items: list[Item] = [] + orders: dict[str, list[int]] = {} def get_filler_item_name(self) -> str: return Items.BOLT_PACK.name @@ -75,7 +75,6 @@ def generate_early(self) -> None: self.player_name) self.item_pool: dict[str, list[Item]] = {} self.starting_planet = Items.NOVALIS_INFOBOT.name - self.starting_items = [] self.preplaced_items = [] rac_logger.debug(f"Pre-placed Item List: {self.preplaced_items}") rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") @@ -130,9 +129,6 @@ def generate_early(self) -> None: rac_logger.debug(f"Useful Pools: {useful_pools}") rac_logger.debug(f"Enabled Pools: {enabled_pools}") - rac_logger.debug(f"Creating Regions") - create_regions(self) - if self.options.shuffle_gold_bolts.value: pass else: @@ -146,16 +142,40 @@ def generate_early(self) -> None: f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}, Bolt pack size: " f"{self.options.pack_size_bolts.value}") - rac_logger.debug(f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}") + rac_logger.debug(f"Choose Progression Order") + self.orders = { + "progressive_suck_cannon_order": [Items.SUCK_CANNON.item_id, Items.GOLDEN_SUCK_CANNON.item_id], + "progressive_bomb_glove_order": [Items.BOMB_GLOVE.item_id, Items.GOLDEN_BOMB_GLOVE.item_id], + "progressive_devastator_order": [Items.DEVASTATOR.item_id, Items.GOLDEN_DEVASTATOR.item_id], + "progressive_blaster_order": [Items.BLASTER.item_id, Items.GOLDEN_BLASTER.item_id], + "progressive_pyrocitor_order": [Items.PYROCITOR.item_id, Items.GOLDEN_PYROCITOR.item_id], + "progressive_mine_glove_order": [Items.MINE_GLOVE.item_id, Items.GOLDEN_MINE_GLOVE.item_id], + "progressive_tesla_claw_order": [Items.TESLA_CLAW.item_id, Items.GOLDEN_TESLA_CLAW.item_id], + "progressive_glove_of_doom_order": [Items.GLOVE_OF_DOOM.item_id, Items.GOLDEN_GLOVE_OF_DOOM.item_id], + "progressive_morph_o_ray_order": [Items.MORPH_O_RAY.item_id, Items.GOLDEN_MORPH_O_RAY.item_id], + "progressive_decoy_glove_order": [Items.DECOY_GLOVE.item_id, Items.GOLDEN_DECOY_GLOVE.item_id], + "progressive_packs_order": [Items.HELI_PACK.item_id, Items.THRUSTER_PACK.item_id, Items.HYDRO_PACK.item_id], + "progressive_helmets_order": [Items.O2_MASK.item_id, Items.SONIC_SUMMONER.item_id, Items.PILOTS_HELMET.item_id], + "progressive_boots_order": [Items.GRINDBOOTS.item_id, Items.MAGNEBOOTS.item_id], + "progressive_hoverboard_order": [Items.HOVERBOARD.item_id, Items.ZOOMERATOR.item_id], + "progressive_raritanium_order": [Items.RARITANIUM.item_id, Items.PERSUADER.item_id], + "progressive_nanotech_order": [Items.PREMIUM_NANOTECH.item_id, Items.ULTRA_NANOTECH.item_id], + } + progression_rules(self) + rac_logger.debug(f"Progression Order: {self.orders}") + rac_logger.debug(f"Creating Regions") + create_regions(self) + rac_logger.debug(f"___Generate Item Pool___") option_list = Items.get_pool(self.options) rac_logger.debug(f"length of option_list: {len(option_list)}") rac_logger.debug(f"gold bolts in list: {option_list.count(Items.GOLD_BOLT)}") for item in option_list: rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") - item_list = self.item_pool.get(item.name) or [] - item_list.append(self.create_item(item.name)) - self.item_pool[item.name] = item_list + item_temp = self.create_item(item.name) + item_list = self.item_pool.get(item_temp.name) or [] + item_list.append(self.create_item(item_temp.name)) + self.item_pool[item_temp.name] = item_list # if item.name in self.item_pool.keys(): # self.item_pool[item.name].append(self.create_item(item.name)) # else: @@ -192,7 +212,7 @@ def generate_early(self) -> None: self.random.shuffle(starting_item) starting_item = self.item_pool[starting_item[0].name].pop(0) - self.starting_items = [starting_item, starting_planet] + self.preplaced_items = [starting_item, starting_planet] self.multiworld.push_precollected(starting_item) self.multiworld.push_precollected(starting_planet) for name, count in self.options.start_inventory: @@ -201,11 +221,11 @@ def generate_early(self) -> None: f"{len(self.item_pool[name])} of {count} copies") for i in range(count): if self.item_pool[name]: - self.starting_items += [self.item_pool[name].pop(0)] + self.preplaced_items += [self.item_pool[name].pop(0)] else: break - rac_logger.debug(f"Starting items: {self.starting_items}") + rac_logger.debug(f"Starting items: {self.preplaced_items}") rac_logger.debug(f"___Vanilla Locations___") self.preplaced_items += self.fill_pool(disabled_pools, 0) @@ -220,7 +240,6 @@ def generate_early(self) -> None: def fill_pool(self, pools, scope) -> (list, list): multiworld = self.multiworld placed_items = self.preplaced_items - placed_items += self.starting_items placed_items += self.item_pool[Items.GOLD_BOLT.name] # for name in self.item_pool: # if Items.from_name(name).pool == POOL_SKILLPOINT: @@ -375,8 +394,7 @@ def create_event(self, name: str) -> "Item": def get_pre_fill_items(self) -> list["Item"]: rac_logger.debug(f"fetching preplaced_items") - items = self.starting_items - items += self.preplaced_items + items = self.preplaced_items return items def create_items(self) -> None: @@ -421,6 +439,8 @@ def fill_slot_data(self) -> Mapping[str, Any]: slot_data: dict[str, Any] = {} slot_data |= Options.get_options_as_dict(self.options) slot_data["starting_planet"] = self.item_name_to_id[self.starting_planet] + for item, value in self.orders.items(): + slot_data[item] = value return slot_data # def post_fill(self) -> None: diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 4dedc71baec5..f25b76848238 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Sequence +from typing import Mapping, Sequence from BaseClasses import Item from worlds.RAC1 import Options @@ -340,11 +340,10 @@ class CollectableData(ItemData): ] ALL: Sequence[ItemData] = [*WEAPONS, *NON_PROGRESSIVE_WEAPONS, *PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, - *PROGRESSIVE_GOLDEN_WEAPONS, *GADGETS, *PACKS, *PROGRESSIVE_PACKS, *HELMETS, - *PROGRESSIVE_HELMETS, *BOOTS, *PROGRESSIVE_BOOTS, *EXTRA_ITEMS, - *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, - *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS, GOLD_BOLT, - *PLANETS, *SKILLPOINTS, BOLT_PACK] + *GADGETS, *PACKS, *PROGRESSIVE_PACKS, *HELMETS, *PROGRESSIVE_HELMETS, *BOOTS, + *PROGRESSIVE_BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, + *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, + *PROGRESSIVE_NANOTECHS, GOLD_BOLT, *PLANETS, *SKILLPOINTS, BOLT_PACK] ITEM_POOL: Sequence[ItemData] = [*PLANETS, *WEAPONS, *NON_PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, *GADGETS, *PACKS, *HELMETS, *BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, @@ -357,8 +356,290 @@ class CollectableData(ItemData): ALL_EXTRA_ITEMS: Sequence[ItemData] = [*EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS] +ALL_HOVERBOARD: Sequence[ItemData] = [*NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS] +ALL_TRADE: Sequence[ItemData] = [*NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES] +ALL_NANOTECH: Sequence[ItemData] = [*NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS] ALL_STARTING: Sequence[ItemData] = [*ALL_WEAPONS, *GADGETS] +SUCK_GROUP: Sequence[ItemData] = [SUCK_CANNON, GOLDEN_SUCK_CANNON, PROGRESSIVE_SUCK] +BOMB_GROUP: Sequence[ItemData] = [BOMB_GLOVE, GOLDEN_BOMB_GLOVE, PROGRESSIVE_BOMB] +DEVASTATOR_GROUP: Sequence[ItemData] = [DEVASTATOR, GOLDEN_DEVASTATOR, PROGRESSIVE_DEVASTATOR] +BLASTER_GROUP: Sequence[ItemData] = [BLASTER, GOLDEN_BLASTER, PROGRESSIVE_BLASTER] +PYROCITOR_GROUP: Sequence[ItemData] = [PYROCITOR, GOLDEN_PYROCITOR, PROGRESSIVE_PYROCITOR] +MINE_GROUP: Sequence[ItemData] = [MINE_GLOVE, GOLDEN_MINE_GLOVE, PROGRESSIVE_MINE] +TESLA_GROUP: Sequence[ItemData] = [TESLA_CLAW, GOLDEN_TESLA_CLAW, PROGRESSIVE_TESLA] +DOOM_GROUP: Sequence[ItemData] = [GLOVE_OF_DOOM, GOLDEN_GLOVE_OF_DOOM, PROGRESSIVE_DOOM] +MORPH_GROUP: Sequence[ItemData] = [MORPH_O_RAY, GOLDEN_MORPH_O_RAY, PROGRESSIVE_MORPH] +DECOY_GROUP: Sequence[ItemData] = [DECOY_GLOVE, GOLDEN_DECOY_GLOVE, PROGRESSIVE_DECOY] + +PROG: dict[str, Mapping[str, int]] = { + HELI_PACK.name: {HELI_PACK.name: 1}, + THRUSTER_PACK.name: {THRUSTER_PACK.name: 1}, + HYDRO_PACK.name: {HYDRO_PACK.name: 1}, + SONIC_SUMMONER.name: {SONIC_SUMMONER.name: 1, PROGRESSIVE_HELMET.name: 2}, + O2_MASK.name: {O2_MASK.name: 1, PROGRESSIVE_HELMET.name: 1}, + PILOTS_HELMET.name: {PILOTS_HELMET.name: 1, PROGRESSIVE_HELMET.name: 3}, + SUCK_CANNON.name: {SUCK_CANNON.name: 1}, + GOLDEN_SUCK_CANNON.name: {SUCK_CANNON.name: 1, GOLDEN_SUCK_CANNON.name: 1}, + BOMB_GLOVE.name: {BOMB_GLOVE.name: 1}, + GOLDEN_BOMB_GLOVE.name: {BOMB_GLOVE.name: 1, GOLDEN_BOMB_GLOVE.name: 1}, + DEVASTATOR.name: {DEVASTATOR.name: 1}, + GOLDEN_DEVASTATOR.name: {DEVASTATOR.name: 1, GOLDEN_DEVASTATOR.name: 1}, + BLASTER.name: {BLASTER.name: 1}, + GOLDEN_BLASTER.name: {BLASTER.name: 1, GOLDEN_BLASTER.name: 1}, + PYROCITOR.name: {PYROCITOR.name: 1}, + GOLDEN_PYROCITOR.name: {PYROCITOR.name: 1, GOLDEN_PYROCITOR.name: 1}, + MINE_GLOVE.name: {MINE_GLOVE.name: 1}, + GOLDEN_MINE_GLOVE.name: {MINE_GLOVE.name: 1, GOLDEN_MINE_GLOVE.name: 1}, + TESLA_CLAW.name: {TESLA_CLAW.name: 1}, + GOLDEN_TESLA_CLAW.name: {TESLA_CLAW.name: 1, GOLDEN_TESLA_CLAW.name: 1}, + GLOVE_OF_DOOM.name: {GLOVE_OF_DOOM.name: 1}, + GOLDEN_GLOVE_OF_DOOM.name: {GLOVE_OF_DOOM.name: 1, GOLDEN_GLOVE_OF_DOOM.name: 1}, + MORPH_O_RAY.name: {MORPH_O_RAY.name: 1}, + GOLDEN_MORPH_O_RAY.name: {MORPH_O_RAY.name: 1, GOLDEN_MORPH_O_RAY.name: 1}, + DECOY_GLOVE.name: {DECOY_GLOVE.name: 1}, + GOLDEN_DECOY_GLOVE.name: {DECOY_GLOVE.name: 1, GOLDEN_DECOY_GLOVE.name: 1}, + MAGNEBOOTS.name: {MAGNEBOOTS.name: 1, PROGRESSIVE_BOOT.name: 2}, + GRINDBOOTS.name: {GRINDBOOTS.name: 1, PROGRESSIVE_BOOT.name: 1}, + HOVERBOARD.name: {HOVERBOARD.name: 1, PROGRESSIVE_HOVERBOARD.name: 1}, + ZOOMERATOR.name: {ZOOMERATOR.name: 1, PROGRESSIVE_HOVERBOARD.name: 2}, + PERSUADER.name: {PERSUADER.name: 1, PROGRESSIVE_TRADE.name: 1}, + RARITANIUM.name: {RARITANIUM.name: 1, PROGRESSIVE_TRADE.name: 2}, + PREMIUM_NANOTECH.name: {PREMIUM_NANOTECH.name: 1, PROGRESSIVE_NANOTECH.name: 1}, + ULTRA_NANOTECH.name: {ULTRA_NANOTECH.name: 1, PROGRESSIVE_NANOTECH.name: 2}, +} + + +def progression_rules(world): + match world.options.progressive_weapons.value: + case Options.GoldenWeaponProgression.option_normal: + PROG[SUCK_CANNON.name] = {SUCK_CANNON.name: 1, GOLDEN_SUCK_CANNON.name: 1} + PROG[GOLDEN_SUCK_CANNON.name] = {GOLDEN_SUCK_CANNON.name: 1} + PROG[BOMB_GLOVE.name] = {BOMB_GLOVE.name: 1, GOLDEN_BOMB_GLOVE.name: 1} + PROG[GOLDEN_BOMB_GLOVE.name] = {GOLDEN_BOMB_GLOVE.name: 1} + PROG[DEVASTATOR.name] = {DEVASTATOR.name: 1, GOLDEN_DEVASTATOR.name: 1} + PROG[GOLDEN_DEVASTATOR.name] = {GOLDEN_DEVASTATOR.name: 1} + PROG[BLASTER.name] = {BLASTER.name: 1, GOLDEN_BLASTER.name: 1} + PROG[GOLDEN_BLASTER.name] = {GOLDEN_BLASTER.name: 1} + PROG[PYROCITOR.name] = {PYROCITOR.name: 1, GOLDEN_PYROCITOR.name: 1} + PROG[GOLDEN_PYROCITOR.name] = {GOLDEN_PYROCITOR.name: 1} + PROG[MINE_GLOVE.name] = {MINE_GLOVE.name: 1, GOLDEN_MINE_GLOVE.name: 1} + PROG[GOLDEN_MINE_GLOVE.name] = {GOLDEN_MINE_GLOVE.name: 1} + PROG[TESLA_CLAW.name] = {TESLA_CLAW.name: 1, GOLDEN_TESLA_CLAW.name: 1} + PROG[GOLDEN_TESLA_CLAW.name] = {GOLDEN_TESLA_CLAW.name: 1} + PROG[GLOVE_OF_DOOM.name] = {GLOVE_OF_DOOM.name: 1, GOLDEN_GLOVE_OF_DOOM.name: 1} + PROG[GOLDEN_GLOVE_OF_DOOM.name] = {GOLDEN_GLOVE_OF_DOOM.name: 1} + PROG[MORPH_O_RAY.name] = {MORPH_O_RAY.name: 1, GOLDEN_MORPH_O_RAY.name: 1} + PROG[GOLDEN_MORPH_O_RAY.name] = {GOLDEN_MORPH_O_RAY.name: 1} + PROG[DECOY_GLOVE.name] = {DECOY_GLOVE.name: 1, GOLDEN_DECOY_GLOVE.name: 1} + PROG[GOLDEN_DECOY_GLOVE.name] = {GOLDEN_DECOY_GLOVE.name: 1} + case Options.GoldenWeaponProgression.option_progressive: + PROG[SUCK_CANNON.name] = {PROGRESSIVE_SUCK.name: 1} + PROG[GOLDEN_SUCK_CANNON.name] = {PROGRESSIVE_SUCK.name: 2} + PROG[BOMB_GLOVE.name] = {PROGRESSIVE_BOMB.name: 1} + PROG[GOLDEN_BOMB_GLOVE.name] = {PROGRESSIVE_BOMB.name: 2} + PROG[DEVASTATOR.name] = {PROGRESSIVE_DEVASTATOR.name: 1} + PROG[GOLDEN_DEVASTATOR.name] = {PROGRESSIVE_DEVASTATOR.name: 2} + PROG[BLASTER.name] = {PROGRESSIVE_BLASTER.name: 1} + PROG[GOLDEN_BLASTER.name] = {PROGRESSIVE_BLASTER.name: 2} + PROG[PYROCITOR.name] = {PROGRESSIVE_PYROCITOR.name: 1} + PROG[GOLDEN_PYROCITOR.name] = {PROGRESSIVE_PYROCITOR.name: 2} + PROG[MINE_GLOVE.name] = {PROGRESSIVE_MINE.name: 1} + PROG[GOLDEN_MINE_GLOVE.name] = {PROGRESSIVE_MINE.name: 2} + PROG[TESLA_CLAW.name] = {PROGRESSIVE_TESLA.name: 1} + PROG[GOLDEN_TESLA_CLAW.name] = {PROGRESSIVE_TESLA.name: 2} + PROG[GLOVE_OF_DOOM.name] = {PROGRESSIVE_DOOM.name: 1} + PROG[GOLDEN_GLOVE_OF_DOOM.name] = {PROGRESSIVE_DOOM.name: 2} + PROG[MORPH_O_RAY.name] = {PROGRESSIVE_MORPH.name: 1} + PROG[GOLDEN_MORPH_O_RAY.name] = {PROGRESSIVE_MORPH.name: 2} + PROG[DECOY_GLOVE.name] = {PROGRESSIVE_DECOY.name: 1} + PROG[GOLDEN_DECOY_GLOVE.name] = {PROGRESSIVE_DECOY.name: 2} + case Options.GoldenWeaponProgression.option_progressive_reversed: + world.orders["progressive_suck_cannon_order"].reverse() + PROG[SUCK_CANNON.name] = {PROGRESSIVE_SUCK.name: 1} + PROG[GOLDEN_SUCK_CANNON.name] = {PROGRESSIVE_SUCK.name: 1} + world.orders["progressive_bomb_glove_order"].reverse() + PROG[BOMB_GLOVE.name] = {PROGRESSIVE_BOMB.name: 1} + PROG[GOLDEN_BOMB_GLOVE.name] = {PROGRESSIVE_BOMB.name: 1} + world.orders["progressive_devastator_order"].reverse() + PROG[DEVASTATOR.name] = {PROGRESSIVE_DEVASTATOR.name: 1} + PROG[GOLDEN_DEVASTATOR.name] = {PROGRESSIVE_DEVASTATOR.name: 1} + world.orders["progressive_blaster_order"].reverse() + PROG[BLASTER.name] = {PROGRESSIVE_BLASTER.name: 1} + PROG[GOLDEN_BLASTER.name] = {PROGRESSIVE_BLASTER.name: 1} + world.orders["progressive_pyrocitor_order"].reverse() + PROG[PYROCITOR.name] = {PROGRESSIVE_PYROCITOR.name: 1} + PROG[GOLDEN_PYROCITOR.name] = {PROGRESSIVE_PYROCITOR.name: 1} + world.orders["progressive_mine_glove_order"].reverse() + PROG[MINE_GLOVE.name] = {PROGRESSIVE_MINE.name: 1} + PROG[GOLDEN_MINE_GLOVE.name] = {PROGRESSIVE_MINE.name: 1} + world.orders["progressive_tesla_claw_order"].reverse() + PROG[TESLA_CLAW.name] = {PROGRESSIVE_TESLA.name: 1} + PROG[GOLDEN_TESLA_CLAW.name] = {PROGRESSIVE_TESLA.name: 1} + world.orders["progressive_glove_of_doom_order"].reverse() + PROG[GLOVE_OF_DOOM.name] = {PROGRESSIVE_DOOM.name: 1} + PROG[GOLDEN_GLOVE_OF_DOOM.name] = {PROGRESSIVE_DOOM.name: 1} + world.orders["progressive_morph_o_ray_order"].reverse() + PROG[MORPH_O_RAY.name] = {PROGRESSIVE_MORPH.name: 1} + PROG[GOLDEN_MORPH_O_RAY.name] = {PROGRESSIVE_MORPH.name: 1} + world.orders["progressive_decoy_glove_order"].reverse() + PROG[DECOY_GLOVE.name] = {PROGRESSIVE_DECOY.name: 1} + PROG[GOLDEN_DECOY_GLOVE.name] = {PROGRESSIVE_DECOY.name: 1} + case Options.GoldenWeaponProgression.option_progressive_random: + world.random.shuffle(world.orders["progressive_suck_cannon_order"]) + PROG[SUCK_CANNON.name] = {PROGRESSIVE_SUCK.name: 1} + PROG[GOLDEN_SUCK_CANNON.name] = {PROGRESSIVE_SUCK.name: 1 + world.orders[ + "progressive_suck_cannon_order"].index(GOLDEN_SUCK_CANNON.item_id)} + world.random.shuffle(world.orders["progressive_bomb_glove_order"]) + PROG[BOMB_GLOVE.name] = {PROGRESSIVE_BOMB.name: 1} + PROG[GOLDEN_BOMB_GLOVE.name] = {PROGRESSIVE_BOMB.name: 1 + world.orders[ + "progressive_bomb_glove_order"].index(GOLDEN_BOMB_GLOVE.item_id)} + world.random.shuffle(world.orders["progressive_devastator_order"]) + PROG[DEVASTATOR.name] = {PROGRESSIVE_DEVASTATOR.name: 1} + PROG[GOLDEN_DEVASTATOR.name] = {PROGRESSIVE_DEVASTATOR.name: 1 + world.orders[ + "progressive_devastator_order"].index(GOLDEN_DEVASTATOR.item_id)} + world.random.shuffle(world.orders["progressive_blaster_order"]) + PROG[BLASTER.name] = {PROGRESSIVE_BLASTER.name: 1} + PROG[GOLDEN_BLASTER.name] = {PROGRESSIVE_BLASTER.name: 1 + world.orders[ + "progressive_blaster_order"].index(GOLDEN_BLASTER.item_id)} + world.random.shuffle(world.orders["progressive_pyrocitor_order"]) + PROG[PYROCITOR.name] = {PROGRESSIVE_PYROCITOR.name: 1} + PROG[GOLDEN_PYROCITOR.name] = {PROGRESSIVE_PYROCITOR.name: 1 + world.orders[ + "progressive_pyrocitor_order"].index(GOLDEN_PYROCITOR.item_id)} + world.random.shuffle(world.orders["progressive_mine_glove_order"]) + PROG[MINE_GLOVE.name] = {PROGRESSIVE_MINE.name: 1} + PROG[GOLDEN_MINE_GLOVE.name] = {PROGRESSIVE_MINE.name: 1 + world.orders[ + "progressive_mine_glove_order"].index(GOLDEN_MINE_GLOVE.item_id)} + world.random.shuffle(world.orders["progressive_tesla_claw_order"]) + PROG[TESLA_CLAW.name] = {PROGRESSIVE_TESLA.name: 1} + PROG[GOLDEN_TESLA_CLAW.name] = {PROGRESSIVE_TESLA.name: 1 + world.orders[ + "progressive_tesla_claw_order"].index(TESLA_CLAW.item_id)} + world.random.shuffle(world.orders["progressive_glove_of_doom_order"]) + PROG[GLOVE_OF_DOOM.name] = {PROGRESSIVE_DOOM.name: 1} + PROG[GOLDEN_GLOVE_OF_DOOM.name] = {PROGRESSIVE_DOOM.name: 1 + world.orders[ + "progressive_glove_of_doom_order"].index(GOLDEN_GLOVE_OF_DOOM.item_id)} + world.random.shuffle(world.orders["progressive_morph_o_ray_order"]) + PROG[MORPH_O_RAY.name] = {PROGRESSIVE_MORPH.name: 1} + PROG[GOLDEN_MORPH_O_RAY.name] = {PROGRESSIVE_MORPH.name: 1 + world.orders[ + "progressive_morph_o_ray_order"].index(GOLDEN_MORPH_O_RAY.item_id)} + world.random.shuffle(world.orders["progressive_decoy_glove_order"]) + PROG[DECOY_GLOVE.name] = {PROGRESSIVE_DECOY.name: 1} + PROG[GOLDEN_DECOY_GLOVE.name] = {PROGRESSIVE_DECOY.name: 1 + world.orders[ + "progressive_decoy_glove_order"].index(GOLDEN_DECOY_GLOVE.item_id)} + case _: + pass + + match world.options.progressive_packs.value: + case Options.ProgressiveOptions.option_progressive: + PROG[HELI_PACK.name] = {PROGRESSIVE_PACK.name: 1} + PROG[THRUSTER_PACK.name] = {PROGRESSIVE_PACK.name: 2} + PROG[HYDRO_PACK.name] = {PROGRESSIVE_PACK.name: 3} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_packs_order"].reverse() + PROG[HELI_PACK.name] = {PROGRESSIVE_PACK.name: 3} + PROG[THRUSTER_PACK.name] = {PROGRESSIVE_PACK.name: 2} + PROG[HYDRO_PACK.name] = {PROGRESSIVE_PACK.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_packs_order"]) + PROG[HELI_PACK.name] = { + PROGRESSIVE_PACK.name: 1 + world.orders["progressive_packs_order"].index(HELI_PACK.item_id)} + PROG[THRUSTER_PACK.name] = { + PROGRESSIVE_PACK.name: 1 + world.orders["progressive_packs_order"].index(THRUSTER_PACK.item_id)} + PROG[HYDRO_PACK.name] = { + PROGRESSIVE_PACK.name: 1 + world.orders["progressive_packs_order"].index(HYDRO_PACK.item_id)} + case _: + pass + + match world.options.progressive_helmets.value: + case Options.ProgressiveOptions.option_progressive: + PROG[O2_MASK.name] = {PROGRESSIVE_HELMET.name: 1} + PROG[SONIC_SUMMONER.name] = {PROGRESSIVE_HELMET.name: 2} + PROG[PILOTS_HELMET.name] = {PROGRESSIVE_HELMET.name: 3} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_helmets_order"].reverse() + PROG[O2_MASK.name] = {PROGRESSIVE_HELMET.name: 3} + PROG[SONIC_SUMMONER.name] = {PROGRESSIVE_HELMET.name: 2} + PROG[PILOTS_HELMET.name] = {PROGRESSIVE_HELMET.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_helmets_order"]) + PROG[O2_MASK.name] = { + PROGRESSIVE_HELMET.name: 1 + world.orders["progressive_helmets_order"].index(O2_MASK.item_id)} + PROG[SONIC_SUMMONER.name] = { + PROGRESSIVE_HELMET.name: 1 + world.orders["progressive_helmets_order"].index(SONIC_SUMMONER.item_id)} + PROG[PILOTS_HELMET.name] = { + PROGRESSIVE_HELMET.name: 1 + world.orders["progressive_helmets_order"].index(PILOTS_HELMET.item_id)} + case _: + pass + + match world.options.progressive_boots.value: + case Options.ProgressiveOptions.option_progressive: + PROG[GRINDBOOTS.name] = {PROGRESSIVE_BOOT.name: 1} + PROG[MAGNEBOOTS.name] = {PROGRESSIVE_BOOT.name: 2} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_boots_order"].reverse() + PROG[GRINDBOOTS.name] = {PROGRESSIVE_BOOT.name: 2} + PROG[MAGNEBOOTS.name] = {PROGRESSIVE_BOOT.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_boots_order"]) + PROG[GRINDBOOTS.name] = { + PROGRESSIVE_BOOT.name: 1 + world.orders["progressive_boots_order"].index(GRINDBOOTS.item_id)} + PROG[MAGNEBOOTS.name] = { + PROGRESSIVE_BOOT.name: 1 + world.orders["progressive_boots_order"].index(MAGNEBOOTS.item_id)} + case _: + pass + + match world.options.progressive_hoverboard.value: + case Options.ProgressiveOptions.option_progressive: + PROG[HOVERBOARD.name] = {PROGRESSIVE_HOVERBOARD.name: 1} + PROG[ZOOMERATOR.name] = {PROGRESSIVE_HOVERBOARD.name: 2} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_hoverboard_order"].reverse() + PROG[HOVERBOARD.name] = {PROGRESSIVE_HOVERBOARD.name: 2} + PROG[ZOOMERATOR.name] = {PROGRESSIVE_HOVERBOARD.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_hoverboard_order"]) + PROG[HOVERBOARD.name] = { + PROGRESSIVE_HOVERBOARD.name: 1 + world.orders["progressive_hoverboard_order"].index(HOVERBOARD.item_id)} + PROG[ZOOMERATOR.name] = { + PROGRESSIVE_HOVERBOARD.name: 1 + world.orders["progressive_hoverboard_order"].index(ZOOMERATOR.item_id)} + case _: + pass + + match world.options.progressive_raritanium.value: + case Options.ProgressiveOptions.option_progressive: + PROG[RARITANIUM.name] = {PROGRESSIVE_TRADE.name: 1} + PROG[PERSUADER.name] = {PROGRESSIVE_TRADE.name: 2} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_raritanium_order"].reverse() + PROG[RARITANIUM.name] = {PROGRESSIVE_TRADE.name: 2} + PROG[PERSUADER.name] = {PROGRESSIVE_TRADE.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_raritanium_order"]) + PROG[RARITANIUM.name] = { + PROGRESSIVE_TRADE.name: 1 + world.orders["progressive_raritanium_order"].index(RARITANIUM.item_id)} + PROG[PERSUADER.name] = { + PROGRESSIVE_TRADE.name: 1 + world.orders["progressive_raritanium_order"].index(PERSUADER.item_id)} + case _: + pass + + match world.options.progressive_nanotech.value: + case Options.ProgressiveOptions.option_progressive: + PROG[PREMIUM_NANOTECH.name] = {PROGRESSIVE_NANOTECH.name: 1} + PROG[ULTRA_NANOTECH.name] = {PROGRESSIVE_NANOTECH.name: 2} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_nanotech_order"].reverse() + PROG[PREMIUM_NANOTECH.name] = {PROGRESSIVE_NANOTECH.name: 2} + PROG[ULTRA_NANOTECH.name] = {PROGRESSIVE_NANOTECH.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_nanotech_order"]) + PROG[PREMIUM_NANOTECH.name] = {PROGRESSIVE_NANOTECH.name: 1 + world.orders[ + "progressive_nanotech_order"].index(PREMIUM_NANOTECH.item_id)} + PROG[ULTRA_NANOTECH.name] = {PROGRESSIVE_NANOTECH.name: 1 + world.orders[ + "progressive_nanotech_order"].index(ULTRA_NANOTECH.item_id)} + case _: + pass + return + def get_pool(options) -> Sequence[ItemData]: pool = [] diff --git a/worlds/RAC1/data/Locations.py b/worlds/RAC1/data/Locations.py index 4b046906e183..7281286ce696 100644 --- a/worlds/RAC1/data/Locations.py +++ b/worlds/RAC1/data/Locations.py @@ -62,9 +62,9 @@ class LocationData: NOVALIS_GOLD_WEAPON_8 = LocationData(98, "Novalis", "Novalis: Golden Weapon 8 - 10,000", Items.GOLDEN_GLOVE_OF_DOOM.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_9 = LocationData(104, "Novalis", "Novalis: Golden Weapon 9 - 10,000", - Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_10 = LocationData(99, "Novalis", "Novalis: Golden Weapon 10 - 10,000", - Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) + Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) # Skill Point Locations NOVALIS_SKILLPOINT = LocationData( From 5fce0768b87e1cf4b06644efd4eaba2915c7a602 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Fri, 22 Aug 2025 04:09:05 -0500 Subject: [PATCH 25/28] RAC: Generation fixes --- worlds/RAC1/Options.py | 1 - worlds/RAC1/Regions.py | 8 +++++++- worlds/RAC1/__init__.py | 11 +++++------ worlds/RAC1/data/Locations.py | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 31b99555bf8a..08a61b06fea5 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -58,7 +58,6 @@ class ShuffleWeapons(ItemOptions): pool = "Weapons" -# TODO: Early Weapon option, off, shuffled amount (user states amount), list (user lists items) class EarlyWeapon(TextChoice): """ Force a weapon to be in your sphere 1. diff --git a/worlds/RAC1/Regions.py b/worlds/RAC1/Regions.py index 59d4f1010a08..69770b2506a2 100644 --- a/worlds/RAC1/Regions.py +++ b/worlds/RAC1/Regions.py @@ -2,7 +2,8 @@ from BaseClasses import CollectionState, Location, Region from .data import Planets -from .data.Locations import LocationData +from .data.Items import check_progressive_item, from_id +from .data.Locations import LocationData, POOL_GOLD_BOLT from .data.Planets import PlanetData if typing.TYPE_CHECKING: @@ -56,6 +57,11 @@ def access_rule(state: CollectionState): return access_rule region.add_locations({location_data.name: location_data.location_id}, RacLocation) + if POOL_GOLD_BOLT in location_data.pools: + location_data.vanilla_item = from_id(301).name + elif location_data.vanilla_item is not None: + location_data.vanilla_item = check_progressive_item(world.options, location_data.vanilla_item) + location = world.multiworld.get_location(location_data.name, world.player) location.access_rule = generate_access_rule(location_data) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 26eb7cab8c44..0c577c608941 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -7,7 +7,7 @@ from worlds.LauncherComponents import Component, components, SuffixIdentifier, Type from . import ItemPool from .data import Items, Locations, Planets -from .data.Items import ALL_WEAPONS, CollectableData, progression_rules, set_quantity +from .data.Items import ALL_WEAPONS, check_progressive_item, CollectableData, progression_rules, set_quantity from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, POOL_WEAPON) @@ -79,8 +79,6 @@ def generate_early(self) -> None: rac_logger.debug(f"Pre-placed Item List: {self.preplaced_items}") rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") - # TODO: Item Pools - shuffle_pools: list = [ self.options.shuffle_infobots, self.options.shuffle_packs, @@ -155,7 +153,8 @@ def generate_early(self) -> None: "progressive_morph_o_ray_order": [Items.MORPH_O_RAY.item_id, Items.GOLDEN_MORPH_O_RAY.item_id], "progressive_decoy_glove_order": [Items.DECOY_GLOVE.item_id, Items.GOLDEN_DECOY_GLOVE.item_id], "progressive_packs_order": [Items.HELI_PACK.item_id, Items.THRUSTER_PACK.item_id, Items.HYDRO_PACK.item_id], - "progressive_helmets_order": [Items.O2_MASK.item_id, Items.SONIC_SUMMONER.item_id, Items.PILOTS_HELMET.item_id], + "progressive_helmets_order": [Items.O2_MASK.item_id, Items.SONIC_SUMMONER.item_id, + Items.PILOTS_HELMET.item_id], "progressive_boots_order": [Items.GRINDBOOTS.item_id, Items.MAGNEBOOTS.item_id], "progressive_hoverboard_order": [Items.HOVERBOARD.item_id, Items.ZOOMERATOR.item_id], "progressive_raritanium_order": [Items.RARITANIUM.item_id, Items.PERSUADER.item_id], @@ -194,7 +193,7 @@ def generate_early(self) -> None: if (self.options.shuffle_weapons == ShuffleWeapons.option_vanilla or self.options.starting_item == StartingItem.option_vanilla): - starting_item = self.item_pool[Items.BOMB_GLOVE.name].pop(0) + starting_item = self.item_pool[check_progressive_item(self.options, Items.BOMB_GLOVE.name)].pop(0) elif self.options.starting_item == StartingItem.option_random_same: starting_item = [] weapon_list = [item.name for item in Items.ALL_WEAPONS] @@ -360,7 +359,7 @@ def fill_pool(self, pools, scope) -> (list, list): reachable = [loc for loc in multiworld.get_reachable_locations(base_state, self.player) if loc in loc_temp] rac_logger.debug(f"Reachable Locations: {reachable}") - # TODO: Try using remaining_fill() to prevent deadend seeds + fill_restrictive(multiworld, base_state, loc_temp, item_temp, single_player_placement=True, lock=False, swap=True, allow_partial=True, name="RAC1 Useful Item Fill") for item in item_temp: diff --git a/worlds/RAC1/data/Locations.py b/worlds/RAC1/data/Locations.py index 7281286ce696..623a1d75d96f 100644 --- a/worlds/RAC1/data/Locations.py +++ b/worlds/RAC1/data/Locations.py @@ -65,7 +65,7 @@ class LocationData: Items.GOLDEN_DECOY_GLOVE.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) NOVALIS_GOLD_WEAPON_10 = LocationData(99, "Novalis", "Novalis: Golden Weapon 10 - 10,000", Items.GOLDEN_SUCK_CANNON.name, {POOL_GOLDEN_WEAPON}, novalis_gold_weapon_rule) - +# TODO: Skillpoint Locations # Skill Point Locations NOVALIS_SKILLPOINT = LocationData( 105, "Novalis", "Novalis: Skillpoint: Take Aim", Items.TAKE_AIM.name, {POOL_SKILLPOINT}, novalis_skillpoint_rule) From 91e9b71747b07a2dd243aa47e7e7bc2857db16ac Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sun, 24 Aug 2025 11:02:37 -0500 Subject: [PATCH 26/28] RAC: Item Pack rework --- worlds/RAC1/ItemPool.py | 4 +- worlds/RAC1/Logic.py | 56 ++++++-- worlds/RAC1/Options.py | 35 ++++- worlds/RAC1/Regions.py | 9 +- worlds/RAC1/__init__.py | 41 ++---- worlds/RAC1/data/Items.py | 285 ++++++++++++++++++++++++++++++++++++-- 6 files changed, 375 insertions(+), 55 deletions(-) diff --git a/worlds/RAC1/ItemPool.py b/worlds/RAC1/ItemPool.py index d768659a1b9f..a3c9082eadba 100644 --- a/worlds/RAC1/ItemPool.py +++ b/worlds/RAC1/ItemPool.py @@ -7,7 +7,8 @@ def get_classification(item: ItemData) -> ItemClassification: if (item in Items.PLANETS or item in Items.ALL_PACKS or item in Items.GADGETS - or item in Items.ALL_BOOTS): + or item in Items.ALL_BOOTS + or item in Items.GOLD_BOLTS): return ItemClassification.progression if item in [ Items.TAUNTER, @@ -29,7 +30,6 @@ def get_classification(item: ItemData) -> ItemClassification: Items.VISIBOMB, Items.RYNO, Items.PROGRESSIVE_TRADE, - Items.GOLD_BOLT, ]: return ItemClassification.progression if (item == Items.SONIC_SUMMONER diff --git a/worlds/RAC1/Logic.py b/worlds/RAC1/Logic.py index b5e81736f907..8976712369d1 100644 --- a/worlds/RAC1/Logic.py +++ b/worlds/RAC1/Logic.py @@ -83,7 +83,7 @@ def has_codebot(state: CollectionState, player: int) -> bool: def has_taunter(state: CollectionState, player: int) -> bool: return state.has(Items.TAUNTER.name, player) - +# TODO Logic for accessing dig spots on each planet def has_metal_detector(state: CollectionState, player: int) -> bool: return state.has(Items.METAL_DETECTOR.name, player) @@ -102,16 +102,54 @@ def has_long_range_weapon(state: CollectionState, player: int) -> bool: def has_40_gold_bolts(state: CollectionState, player: int) -> bool: - count, mod = divmod(20, Items.GOLD_BOLT.quantity) - if mod != 0: - count = count // 1 - if count < 1: - count = 1 - if state.count(Items.GOLD_BOLT.name, player) < count: + lookup: dict[int, tuple[str, int]] = { + 1: (Items.GOLD_BOLT_1.name, 40), + 2: (Items.GOLD_BOLT_2.name, 20), + 3: (Items.GOLD_BOLT_3.name, 14), + 4: (Items.GOLD_BOLT_4.name, 10), + 5: (Items.GOLD_BOLT_5.name, 8), + 6: (Items.GOLD_BOLT_6.name, 7), + 7: (Items.GOLD_BOLT_7.name, 6), + 8: (Items.GOLD_BOLT_8.name, 5), + 9: (Items.GOLD_BOLT_9.name, 5), + 10: (Items.GOLD_BOLT_10.name, 4), + 11: (Items.GOLD_BOLT_11.name, 4), + 12: (Items.GOLD_BOLT_12.name, 4), + 13: (Items.GOLD_BOLT_13.name, 4), + 14: (Items.GOLD_BOLT_14.name, 3), + 15: (Items.GOLD_BOLT_15.name, 3), + 16: (Items.GOLD_BOLT_16.name, 3), + 17: (Items.GOLD_BOLT_17.name, 3), + 18: (Items.GOLD_BOLT_18.name, 3), + 19: (Items.GOLD_BOLT_19.name, 3), + 20: (Items.GOLD_BOLT_20.name, 2), + 21: (Items.GOLD_BOLT_21.name, 2), + 22: (Items.GOLD_BOLT_22.name, 2), + 23: (Items.GOLD_BOLT_23.name, 2), + 24: (Items.GOLD_BOLT_24.name, 2), + 25: (Items.GOLD_BOLT_25.name, 2), + 26: (Items.GOLD_BOLT_26.name, 2), + 27: (Items.GOLD_BOLT_27.name, 2), + 28: (Items.GOLD_BOLT_28.name, 2), + 29: (Items.GOLD_BOLT_29.name, 2), + 30: (Items.GOLD_BOLT_30.name, 2), + 31: (Items.GOLD_BOLT_31.name, 2), + 32: (Items.GOLD_BOLT_32.name, 2), + 33: (Items.GOLD_BOLT_33.name, 2), + 34: (Items.GOLD_BOLT_34.name, 2), + 35: (Items.GOLD_BOLT_35.name, 2), + 36: (Items.GOLD_BOLT_36.name, 2), + 37: (Items.GOLD_BOLT_37.name, 2), + 38: (Items.GOLD_BOLT_38.name, 2), + 39: (Items.GOLD_BOLT_39.name, 2), + 40: (Items.GOLD_BOLT_40.name, 1), + } + item, count = lookup[state.multiworld.worlds[player].options.pack_size_gold_bolts.value] + if state.count(item, player) < count: rac_logger.debug(f"Missing gold bolt packs from world, expected {count} but only had" - f" {state.count(Items.GOLD_BOLT.name, player)}. Can reach " + f" {state.count(item, player)}. Can reach " f"{state.prog_items}") - return state.has(Items.GOLD_BOLT.name, player, count) + return state.has(item, player, count) # Novalis diff --git a/worlds/RAC1/Options.py b/worlds/RAC1/Options.py index 08a61b06fea5..975933108bad 100644 --- a/worlds/RAC1/Options.py +++ b/worlds/RAC1/Options.py @@ -148,12 +148,37 @@ class GoldBoltPackSize(Range): range_end = 40 -class BoltPackSize(Range): +class BoltPackSize(Choice): """Number of Bolts received each time you collect a pack of Bolts.""" display_name = "Bolt Pack Size" - default = 15000 - range_start = 0 - range_end = 1000000 + option_0 = 0 + option_1 = 1 + option_10 = 10 + option_100 = 100 + option_250 = 250 + option_500 = 500 + option_750 = 750 + option_1000 = 1000 + option_2000 = 2000 + option_3000 = 3000 + option_4000 = 4000 + option_5000 = 5000 + option_6000 = 6000 + option_7000 = 7000 + option_8000 = 8000 + option_9000 = 9000 + option_10000 = 10000 + option_12500 = 12500 + option_15000 = 15000 + option_17500 = 17500 + option_20000 = 20000 + option_25000 = 25000 + option_30000 = 30000 + option_40000 = 40000 + option_50000 = 50000 + option_75000 = 75000 + option_100000 = 100000 + default = option_15000 class ShuffleInfobots(ItemOptions): @@ -205,6 +230,8 @@ class MDBoltMultiplier(Range): range_end = 100 +# TODO Option: Vendor in logic without metal detector + class ProgressiveOptions(Choice): """Template vanilla: These items are not progressive, each item is independent of other items. diff --git a/worlds/RAC1/Regions.py b/worlds/RAC1/Regions.py index 69770b2506a2..9169dda2ac11 100644 --- a/worlds/RAC1/Regions.py +++ b/worlds/RAC1/Regions.py @@ -2,9 +2,10 @@ from BaseClasses import CollectionState, Location, Region from .data import Planets -from .data.Items import check_progressive_item, from_id -from .data.Locations import LocationData, POOL_GOLD_BOLT +from .data.Items import check_progressive_item, get_gold_bolts +from .data.Locations import LocationData, POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON from .data.Planets import PlanetData +from ..generic.Rules import forbid_item if typing.TYPE_CHECKING: from . import RacWorld @@ -58,12 +59,14 @@ def access_rule(state: CollectionState): region.add_locations({location_data.name: location_data.location_id}, RacLocation) if POOL_GOLD_BOLT in location_data.pools: - location_data.vanilla_item = from_id(301).name + location_data.vanilla_item = get_gold_bolts(world.options) elif location_data.vanilla_item is not None: location_data.vanilla_item = check_progressive_item(world.options, location_data.vanilla_item) location = world.multiworld.get_location(location_data.name, world.player) location.access_rule = generate_access_rule(location_data) + if POOL_GOLDEN_WEAPON in location_data.pools: + forbid_item(location, get_gold_bolts(world.options), world.player) # from Utils import visualize_regions # visualize_regions(world.multiworld.get_region("Menu", world.player), "my_world.puml") diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 0c577c608941..60f424661f92 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -7,7 +7,7 @@ from worlds.LauncherComponents import Component, components, SuffixIdentifier, Type from . import ItemPool from .data import Items, Locations, Planets -from .data.Items import ALL_WEAPONS, check_progressive_item, CollectableData, progression_rules, set_quantity +from .data.Items import ALL_WEAPONS, check_progressive_item, CollectableData, get_bolt_pack, progression_rules from .data.Locations import (ALL_POOLS, DEFAULT_LIST, LocationData, POOL_BOOT, POOL_EXTRA_ITEM, POOL_GADGET, POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, POOL_WEAPON) @@ -64,7 +64,7 @@ class RacWorld(World): orders: dict[str, list[int]] = {} def get_filler_item_name(self) -> str: - return Items.BOLT_PACK.name + return get_bolt_pack(self.options) def generate_early(self) -> None: rac_logger.debug(f"_________START EARLY GENERATION____________") @@ -127,15 +127,9 @@ def generate_early(self) -> None: rac_logger.debug(f"Useful Pools: {useful_pools}") rac_logger.debug(f"Enabled Pools: {enabled_pools}") - if self.options.shuffle_gold_bolts.value: - pass - else: + if not self.options.shuffle_gold_bolts.value: self.options.pack_size_gold_bolts.value = 1 - self.item_name_to_id[set_quantity(Items.GOLD_BOLT, self.options.pack_size_gold_bolts.value)] = ( - Items.GOLD_BOLT.item_id) - self.item_name_to_id[set_quantity(Items.BOLT_PACK, self.options.pack_size_bolts.value)] = ( - Items.BOLT_PACK.item_id) rac_logger.debug( f"Gold Bolt Pack Size: {self.options.pack_size_gold_bolts.value}, Bolt pack size: " f"{self.options.pack_size_bolts.value}") @@ -168,17 +162,11 @@ def generate_early(self) -> None: rac_logger.debug(f"___Generate Item Pool___") option_list = Items.get_pool(self.options) rac_logger.debug(f"length of option_list: {len(option_list)}") - rac_logger.debug(f"gold bolts in list: {option_list.count(Items.GOLD_BOLT)}") for item in option_list: rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") - item_temp = self.create_item(item.name) - item_list = self.item_pool.get(item_temp.name) or [] - item_list.append(self.create_item(item_temp.name)) - self.item_pool[item_temp.name] = item_list - # if item.name in self.item_pool.keys(): - # self.item_pool[item.name].append(self.create_item(item.name)) - # else: - # self.item_pool |= {item.name: [self.create_item(item.name)]} + item_list = self.item_pool.get(item.name) or [] + item_list.append(self.create_item(item.name)) + self.item_pool[item.name] = item_list rac_logger.debug(f"item_pool size: {len(self.item_pool.values())}") if (self.options.shuffle_infobots == ShuffleInfobots.option_vanilla or @@ -264,13 +252,13 @@ def fill_pool(self, pools, scope) -> (list, list): raise FillError(f"Slot {self.player_name} selected vanilla {pool}, but Location:" f" {loc.name} was already filled") elif pool == Items.GOLD_BOLT.pool: - item = self.item_pool[Items.GOLD_BOLT.name].pop(0) + item = self.item_pool[Items.GOLD_BOLT_1.name].pop(0) elif self.item_pool[loc.vanilla_item]: item = self.item_pool[loc.vanilla_item].pop(0) else: rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be placed at {loc.name}, " f"filler bolt pack placed instead") - item = self.create_item(Items.BOLT_PACK.name) + item = self.create_item(get_bolt_pack(self.options)) self.get_location(loc.name).place_locked_item(item) add_items += [item] rac_logger.debug(f"vanilla: {loc.name}, item: {item}") @@ -308,7 +296,7 @@ def fill_pool(self, pools, scope) -> (list, list): else: rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be shuffled into pool {pool}" f", filler bolt pack added instead") - item_temp += [self.create_item(Items.BOLT_PACK.name)] + item_temp += [self.create_item(get_bolt_pack(self.options))] if pool == POOL_WEAPON and POOL_GOLDEN_WEAPON in pools: if POOL_GOLDEN_WEAPON in loc.pools and loc.vanilla_item is not None: loc_temp += [self.get_location(loc.name)] @@ -317,7 +305,7 @@ def fill_pool(self, pools, scope) -> (list, list): else: rac_logger.warning(f"vanilla item {loc.vanilla_item} can't be shuffled into pool" f" {pool}, filler bolt pack added instead") - item_temp += [self.create_item(Items.BOLT_PACK.name)] + item_temp += [self.create_item(get_bolt_pack(self.options))] rac_logger.debug(f"Randomize Locations: {loc_temp}") add_items += item_temp self.random.shuffle(item_temp) @@ -380,9 +368,10 @@ def fill_pool(self, pools, scope) -> (list, list): def create_item(self, name: str, override: Optional[ItemClassification] = None) -> "Item": new_name = Items.check_progressive_item(self.options, name) - if Items.from_name(name).pool == POOL_WEAPON or Items.from_name(name).pool == POOL_GOLDEN_WEAPON: - rac_logger.debug(f"Checking progressive weapon: {name}") - rac_logger.debug(f"Weapon is: {new_name}") + if new_name is not name: + rac_logger.warning(f"Item {name} was not initially set to its progressive item: {new_name}") + if name == Items.GOLD_BOLT or name == Items.BOLT_PACK: + rac_logger.warning(f"{name} should not be in the item pool!!! Please report") if override: return RacItem(new_name, override, self.item_name_to_id[new_name], self.player) item_data = Items.from_name(new_name) @@ -417,7 +406,7 @@ def create_items(self) -> None: else: rac_logger.debug(f"Not enough items to fill all locations. Adding {remain} filler items to the item pool") for _ in range(remain): - items_to_add.append(self.create_item(Items.BOLT_PACK.name)) + items_to_add.append(self.create_item(get_bolt_pack(self.options))) rac_logger.debug(f"Add item pool to multiworld: {items_to_add}") self.multiworld.itempool.extend(items_to_add) rac_logger.debug(f"_________END ITEM CREATION__________") diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index f25b76848238..cabfca6ed908 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -139,8 +139,76 @@ class CollectableData(ItemData): # Collectables -GOLD_BOLT = ItemData(301, "Gold Bolt Pack", "GoldBolts") -BOLT_PACK = ItemData(302, "Bolt Pack", "Filler", 15000) +GOLD_BOLT = ItemData(261, "Generic Gold Bolt", "GoldBolts") +GOLD_BOLT_1 = ItemData(262, "1 Gold Bolt", "GoldBolts", 1) +GOLD_BOLT_2 = ItemData(263, "2 Gold Bolts", "GoldBolts", 2) +GOLD_BOLT_3 = ItemData(264, "3 Gold Bolts", "GoldBolts", 3) +GOLD_BOLT_4 = ItemData(265, "4 Gold Bolts", "GoldBolts", 4) +GOLD_BOLT_5 = ItemData(266, "5 Gold Bolts", "GoldBolts", 5) +GOLD_BOLT_6 = ItemData(267, "6 Gold Bolts", "GoldBolts", 6) +GOLD_BOLT_7 = ItemData(268, "7 Gold Bolts", "GoldBolts", 7) +GOLD_BOLT_8 = ItemData(269, "8 Gold Bolts", "GoldBolts", 8) +GOLD_BOLT_9 = ItemData(270, "9 Gold Bolts", "GoldBolts", 9) +GOLD_BOLT_10 = ItemData(271, "10 Gold Bolts", "GoldBolts", 10) +GOLD_BOLT_11 = ItemData(272, "11 Gold Bolts", "GoldBolts", 11) +GOLD_BOLT_12 = ItemData(273, "12 Gold Bolts", "GoldBolts", 12) +GOLD_BOLT_13 = ItemData(274, "13 Gold Bolts", "GoldBolts", 13) +GOLD_BOLT_14 = ItemData(275, "14 Gold Bolts", "GoldBolts", 14) +GOLD_BOLT_15 = ItemData(276, "15 Gold Bolts", "GoldBolts", 15) +GOLD_BOLT_16 = ItemData(277, "16 Gold Bolts", "GoldBolts", 16) +GOLD_BOLT_17 = ItemData(278, "17 Gold Bolts", "GoldBolts", 17) +GOLD_BOLT_18 = ItemData(279, "18 Gold Bolts", "GoldBolts", 18) +GOLD_BOLT_19 = ItemData(280, "19 Gold Bolts", "GoldBolts", 19) +GOLD_BOLT_20 = ItemData(281, "20 Gold Bolts", "GoldBolts", 20) +GOLD_BOLT_21 = ItemData(282, "21 Gold Bolts", "GoldBolts", 21) +GOLD_BOLT_22 = ItemData(283, "22 Gold Bolts", "GoldBolts", 22) +GOLD_BOLT_23 = ItemData(284, "23 Gold Bolts", "GoldBolts", 23) +GOLD_BOLT_24 = ItemData(285, "24 Gold Bolts", "GoldBolts", 24) +GOLD_BOLT_25 = ItemData(286, "25 Gold Bolts", "GoldBolts", 25) +GOLD_BOLT_26 = ItemData(287, "26 Gold Bolts", "GoldBolts", 26) +GOLD_BOLT_27 = ItemData(288, "27 Gold Bolts", "GoldBolts", 27) +GOLD_BOLT_28 = ItemData(289, "28 Gold Bolts", "GoldBolts", 28) +GOLD_BOLT_29 = ItemData(290, "29 Gold Bolts", "GoldBolts", 29) +GOLD_BOLT_30 = ItemData(291, "30 Gold Bolts", "GoldBolts", 30) +GOLD_BOLT_31 = ItemData(292, "31 Gold Bolts", "GoldBolts", 31) +GOLD_BOLT_32 = ItemData(293, "32 Gold Bolts", "GoldBolts", 32) +GOLD_BOLT_33 = ItemData(294, "33 Gold Bolts", "GoldBolts", 33) +GOLD_BOLT_34 = ItemData(295, "34 Gold Bolts", "GoldBolts", 34) +GOLD_BOLT_35 = ItemData(296, "35 Gold Bolts", "GoldBolts", 35) +GOLD_BOLT_36 = ItemData(297, "36 Gold Bolts", "GoldBolts", 36) +GOLD_BOLT_37 = ItemData(298, "37 Gold Bolts", "GoldBolts", 37) +GOLD_BOLT_38 = ItemData(299, "38 Gold Bolts", "GoldBolts", 38) +GOLD_BOLT_39 = ItemData(300, "39 Gold Bolts", "GoldBolts", 39) +GOLD_BOLT_40 = ItemData(301, "40 Gold Bolts", "GoldBolts", 40) + +BOLT_PACK = ItemData(302, "Generic Bolt Pack", "Filler") +BOLT_PACK_0 = ItemData(400, "Nothing", "Filler", 0) +BOLT_PACK_1 = ItemData(401, "A single bolt", "Filler", 1) +BOLT_PACK_2 = ItemData(402, "10 bolts", "Filler", 10) +BOLT_PACK_3 = ItemData(403, "100 bolts", "Filler", 100) +BOLT_PACK_4 = ItemData(404, "250 bolts", "Filler", 250) +BOLT_PACK_5 = ItemData(405, "500 bolts", "Filler", 500) +BOLT_PACK_6 = ItemData(406, "750 bolts", "Filler", 750) +BOLT_PACK_7 = ItemData(407, "1,000 bolts", "Filler", 1000) +BOLT_PACK_8 = ItemData(408, "2,000 bolts", "Filler", 2000) +BOLT_PACK_9 = ItemData(409, "3,000 bolts", "Filler", 3000) +BOLT_PACK_10 = ItemData(410, "4,000 bolts", "Filler", 4000) +BOLT_PACK_11 = ItemData(411, "5,000 bolts", "Filler", 5000) +BOLT_PACK_12 = ItemData(412, "6,000 bolts", "Filler", 6000) +BOLT_PACK_13 = ItemData(413, "7,000 bolts", "Filler", 7000) +BOLT_PACK_14 = ItemData(414, "8,000 bolts", "Filler", 8000) +BOLT_PACK_15 = ItemData(415, "9,000 bolts", "Filler", 9000) +BOLT_PACK_16 = ItemData(416, "10,000 bolts", "Filler", 10000) +BOLT_PACK_17 = ItemData(417, "12,500 bolts", "Filler", 12500) +BOLT_PACK_18 = ItemData(418, "15,000 bolts", "Filler", 15000) +BOLT_PACK_19 = ItemData(419, "17,500 bolts", "Filler", 17500) +BOLT_PACK_20 = ItemData(420, "20,000 bolts", "Filler", 20000) +BOLT_PACK_21 = ItemData(421, "25,000 bolts", "Filler", 25000) +BOLT_PACK_22 = ItemData(422, "30,000 bolts", "Filler", 30000) +BOLT_PACK_23 = ItemData(423, "40,000 bolts", "Filler", 40000) +BOLT_PACK_24 = ItemData(424, "50,000 bolts", "Filler", 50000) +BOLT_PACK_25 = ItemData(425, "75,000 bolts", "Filler", 75000) +BOLT_PACK_26 = ItemData(426, "100,000 bolts", "Filler", 100000) WEAPONS: Sequence[ItemData] = [ TAUNTER, @@ -273,8 +341,79 @@ class CollectableData(ItemData): *[PROGRESSIVE_NANOTECH] * 2, ] -GOLD_BOLTS: Sequence[CollectableData] = [ - *[GOLD_BOLT] * 40, +GOLD_BOLTS: Sequence[ItemData] = [ + GOLD_BOLT, + GOLD_BOLT_1, + GOLD_BOLT_2, + GOLD_BOLT_3, + GOLD_BOLT_4, + GOLD_BOLT_5, + GOLD_BOLT_6, + GOLD_BOLT_7, + GOLD_BOLT_8, + GOLD_BOLT_9, + GOLD_BOLT_10, + GOLD_BOLT_11, + GOLD_BOLT_12, + GOLD_BOLT_13, + GOLD_BOLT_14, + GOLD_BOLT_15, + GOLD_BOLT_16, + GOLD_BOLT_17, + GOLD_BOLT_18, + GOLD_BOLT_19, + GOLD_BOLT_20, + GOLD_BOLT_21, + GOLD_BOLT_22, + GOLD_BOLT_23, + GOLD_BOLT_24, + GOLD_BOLT_25, + GOLD_BOLT_26, + GOLD_BOLT_27, + GOLD_BOLT_28, + GOLD_BOLT_29, + GOLD_BOLT_30, + GOLD_BOLT_31, + GOLD_BOLT_32, + GOLD_BOLT_33, + GOLD_BOLT_34, + GOLD_BOLT_35, + GOLD_BOLT_36, + GOLD_BOLT_37, + GOLD_BOLT_38, + GOLD_BOLT_39, + GOLD_BOLT_40, +] + +BOLT_PACKS: Sequence[ItemData] = [ + BOLT_PACK, + BOLT_PACK_0, + BOLT_PACK_1, + BOLT_PACK_2, + BOLT_PACK_3, + BOLT_PACK_4, + BOLT_PACK_5, + BOLT_PACK_6, + BOLT_PACK_7, + BOLT_PACK_8, + BOLT_PACK_9, + BOLT_PACK_10, + BOLT_PACK_11, + BOLT_PACK_12, + BOLT_PACK_13, + BOLT_PACK_14, + BOLT_PACK_15, + BOLT_PACK_16, + BOLT_PACK_17, + BOLT_PACK_18, + BOLT_PACK_19, + BOLT_PACK_20, + BOLT_PACK_21, + BOLT_PACK_22, + BOLT_PACK_23, + BOLT_PACK_24, + BOLT_PACK_25, + BOLT_PACK_26, ] PLANETS: Sequence[ItemData] = [ @@ -343,7 +482,7 @@ class CollectableData(ItemData): *GADGETS, *PACKS, *PROGRESSIVE_PACKS, *HELMETS, *PROGRESSIVE_HELMETS, *BOOTS, *PROGRESSIVE_BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, - *PROGRESSIVE_NANOTECHS, GOLD_BOLT, *PLANETS, *SKILLPOINTS, BOLT_PACK] + *PROGRESSIVE_NANOTECHS, *GOLD_BOLTS, *PLANETS, *SKILLPOINTS, *BOLT_PACKS] ITEM_POOL: Sequence[ItemData] = [*PLANETS, *WEAPONS, *NON_PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, *GADGETS, *PACKS, *HELMETS, *BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, @@ -410,6 +549,48 @@ class CollectableData(ItemData): } +def get_bolt_pack(options: Options) -> str: + lookup: dict[int, str] = { + BOLT_PACK_0.quantity: BOLT_PACK_0.name, + BOLT_PACK_1.quantity: BOLT_PACK_1.name, + BOLT_PACK_2.quantity: BOLT_PACK_2.name, + BOLT_PACK_3.quantity: BOLT_PACK_3.name, + BOLT_PACK_4.quantity: BOLT_PACK_4.name, + BOLT_PACK_5.quantity: BOLT_PACK_5.name, + BOLT_PACK_6.quantity: BOLT_PACK_6.name, + BOLT_PACK_7.quantity: BOLT_PACK_7.name, + BOLT_PACK_8.quantity: BOLT_PACK_8.name, + BOLT_PACK_9.quantity: BOLT_PACK_9.name, + BOLT_PACK_10.quantity: BOLT_PACK_10.name, + BOLT_PACK_11.quantity: BOLT_PACK_11.name, + BOLT_PACK_12.quantity: BOLT_PACK_12.name, + BOLT_PACK_13.quantity: BOLT_PACK_13.name, + BOLT_PACK_14.quantity: BOLT_PACK_14.name, + BOLT_PACK_15.quantity: BOLT_PACK_15.name, + BOLT_PACK_16.quantity: BOLT_PACK_16.name, + BOLT_PACK_17.quantity: BOLT_PACK_17.name, + BOLT_PACK_18.quantity: BOLT_PACK_18.name, + BOLT_PACK_19.quantity: BOLT_PACK_19.name, + BOLT_PACK_20.quantity: BOLT_PACK_20.name, + BOLT_PACK_21.quantity: BOLT_PACK_21.name, + BOLT_PACK_22.quantity: BOLT_PACK_22.name, + BOLT_PACK_23.quantity: BOLT_PACK_23.name, + BOLT_PACK_24.quantity: BOLT_PACK_24.name, + BOLT_PACK_25.quantity: BOLT_PACK_25.name, + BOLT_PACK_26.quantity: BOLT_PACK_26.name, + } + return lookup[options.pack_size_bolts.value] + + +def get_gold_bolts(options: Options) -> str: + lookup: dict[int, str] = {} + for gold_bolt in GOLD_BOLTS: + if gold_bolt.name.startswith("Generic"): + continue + lookup.update({gold_bolt.quantity: gold_bolt.name}) + return lookup[options.pack_size_gold_bolts.value] + + def progression_rules(world): match world.options.progressive_weapons.value: case Options.GoldenWeaponProgression.option_normal: @@ -645,12 +826,94 @@ def get_pool(options) -> Sequence[ItemData]: pool = [] for item in ITEM_POOL: pool += [item] - gb_count = 0 - if pool.count(GOLD_BOLT) > 0: - raise AssertionError("Gold Bolts should not be in the pool before getting added") - while gb_count < 40: - pool += [GOLD_BOLT] - gb_count += options.pack_size_gold_bolts + if options.progressive_weapons.value > Options.GoldenWeaponProgression.option_normal: + for item in PROGRESSIVE_WEAPONS: + pool += [item, item] + else: + for item in NON_PROGRESSIVE_WEAPONS: + pool += [item] + for item in GOLDEN_WEAPONS: + pool += [item] + if options.progressive_packs.value > Options.ProgressiveOptions.option_vanilla: + for item in PROGRESSIVE_PACKS: + pool += [item] + else: + for item in PACKS: + pool += [item] + if options.progressive_helmets.value > Options.ProgressiveOptions.option_vanilla: + for item in PROGRESSIVE_HELMETS: + pool += [item] + else: + for item in HELMETS: + pool += [item] + if options.progressive_boots.value > Options.ProgressiveOptions.option_vanilla: + for item in PROGRESSIVE_BOOTS: + pool += [item] + else: + for item in BOOTS: + pool += [item] + if options.progressive_hoverboard.value > Options.ProgressiveOptions.option_vanilla: + for item in PROGRESSIVE_HOVERBOARDS: + pool += [item] + else: + for item in NON_PROGRESSIVE_HOVERBOARDS: + pool += [item] + if options.progressive_raritanium.value > Options.ProgressiveOptions.option_vanilla: + for item in PROGRESSIVE_TRADES: + pool += [item] + else: + for item in NON_PROGRESSIVE_TRADES: + pool += [item] + if options.progressive_nanotech.value > Options.ProgressiveOptions.option_vanilla: + for item in PROGRESSIVE_NANOTECHS: + pool += [item] + else: + for item in NON_PROGRESSIVE_NANOTECHS: + pool += [item] + lookup: dict[int, tuple[ItemData, int]] = { + 1: (GOLD_BOLT_1, 40), + 2: (GOLD_BOLT_2, 30), + 3: (GOLD_BOLT_3, 20), + 4: (GOLD_BOLT_4, 15), + 5: (GOLD_BOLT_5, 12), + 6: (GOLD_BOLT_6, 10), + 7: (GOLD_BOLT_7, 9), + 8: (GOLD_BOLT_8, 8), + 9: (GOLD_BOLT_9, 7), + 10: (GOLD_BOLT_10, 6), + 11: (GOLD_BOLT_11, 5), + 12: (GOLD_BOLT_12, 5), + 13: (GOLD_BOLT_13, 5), + 14: (GOLD_BOLT_14, 4), + 15: (GOLD_BOLT_15, 4), + 16: (GOLD_BOLT_16, 4), + 17: (GOLD_BOLT_17, 4), + 18: (GOLD_BOLT_18, 4), + 19: (GOLD_BOLT_19, 4), + 20: (GOLD_BOLT_20, 3), + 21: (GOLD_BOLT_21, 3), + 22: (GOLD_BOLT_22, 3), + 23: (GOLD_BOLT_23, 3), + 24: (GOLD_BOLT_24, 3), + 25: (GOLD_BOLT_25, 3), + 26: (GOLD_BOLT_26, 3), + 27: (GOLD_BOLT_27, 3), + 28: (GOLD_BOLT_28, 3), + 29: (GOLD_BOLT_29, 3), + 30: (GOLD_BOLT_30, 2), + 31: (GOLD_BOLT_31, 2), + 32: (GOLD_BOLT_32, 2), + 33: (GOLD_BOLT_33, 2), + 34: (GOLD_BOLT_34, 2), + 35: (GOLD_BOLT_35, 2), + 36: (GOLD_BOLT_36, 2), + 37: (GOLD_BOLT_37, 2), + 38: (GOLD_BOLT_38, 2), + 39: (GOLD_BOLT_39, 2), + 40: (GOLD_BOLT_40, 1), + } + for _ in range(lookup[options.pack_size_gold_bolts.value][1]): + pool += [lookup[options.pack_size_gold_bolts.value][0]] return pool From 714b9f05d8016b5272f0fdb940869c03e843c542 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sun, 24 Aug 2025 11:07:33 -0500 Subject: [PATCH 27/28] RAC: Pack rework cleanup --- worlds/RAC1/__init__.py | 9 +++++++-- worlds/RAC1/data/Items.py | 28 ---------------------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 60f424661f92..6e2a4822181d 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -227,7 +227,6 @@ def generate_early(self) -> None: def fill_pool(self, pools, scope) -> (list, list): multiworld = self.multiworld placed_items = self.preplaced_items - placed_items += self.item_pool[Items.GOLD_BOLT.name] # for name in self.item_pool: # if Items.from_name(name).pool == POOL_SKILLPOINT: # placed_items += self.item_pool[name] @@ -236,7 +235,13 @@ def fill_pool(self, pools, scope) -> (list, list): for name, items in self.item_pool.items(): rac_logger.debug(f"Checking if {name} is unplaced") if items: - if name == Items.GOLD_BOLT.name or items[0].name.endswith("Skill Point"): + if items[0].name.endswith("Gold Bolts"): + placed_items += self.item_pool[name] + continue + elif items[0].name.endswith("Skill Point"): + continue + elif items[0].name.endswith("Gold Bolt"): + placed_items += self.item_pool[name] continue else: rac_logger.debug(f"Add to unplaced: {name}") diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index cabfca6ed908..2c5d21f968e5 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -1009,31 +1009,3 @@ def check_progressive_item(options, item) -> str: if options.progressive_nanotech.value: new_item = PROGRESSIVE_NANOTECH.name return new_item - - -def set_quantity(item, count) -> str: - item.quantity = count - match item.item_id: - case BOLT_PACK.item_id: - if count == 1: - item.name = f"A Single Bolt" - elif count == 0: - item.name = f"Nothing" - elif 1000 <= count < 1000000: - temp0 = count // 1000 - temp1 = count - (temp0 * 1000) - item.name = f"{temp0},{temp1} Bolts" - elif count == 1000000: - item.name = f"1 MILLION BOLTS!!!" - else: - item.name = f"{item.quantity} Bolts" - BOLT_PACK.name = item.name - case GOLD_BOLT.item_id: - if count == 1: - item.name = f"A Gold Bolt" - else: - item.name = f"{item.quantity} Gold Bolts" - GOLD_BOLT.name = item.name - case _: - raise Exception(f"Awww heck! {item.name} was tried to be turned into a pack!") - return item.name From 11b95f857cb0e7deaa17b5e01ae5cc6f013c8119 Mon Sep 17 00:00:00 2001 From: Myth197 Date: Sun, 24 Aug 2025 11:11:36 -0500 Subject: [PATCH 28/28] RAC: Starting Weapon, Golden Weapon Progressive, RYNO, and Progressive Items in Vanilla Locations fixes --- worlds/RAC1/__init__.py | 21 +++---- worlds/RAC1/data/Items.py | 129 +++++++++++++++++++++++++------------- 2 files changed, 96 insertions(+), 54 deletions(-) diff --git a/worlds/RAC1/__init__.py b/worlds/RAC1/__init__.py index 6e2a4822181d..2c6d25e20aa8 100644 --- a/worlds/RAC1/__init__.py +++ b/worlds/RAC1/__init__.py @@ -12,7 +12,7 @@ POOL_GOLD_BOLT, POOL_GOLDEN_WEAPON, POOL_HELMET, POOL_INFOBOT, POOL_PACK, POOL_SKILLPOINT, POOL_WEAPON) from .data.Planets import ALL_LOCATIONS, location_groups, PlanetData -from .Options import RacOptions, ShuffleInfobots, ShuffleWeapons, StartingItem, StartingLocation +from .Options import RacOptions, ShuffleGadgets, ShuffleInfobots, ShuffleWeapons, StartingItem, StartingLocation from .Regions import create_regions rac_logger = logging.getLogger("Ratchet & Clank") @@ -182,19 +182,16 @@ def generate_early(self) -> None: if (self.options.shuffle_weapons == ShuffleWeapons.option_vanilla or self.options.starting_item == StartingItem.option_vanilla): starting_item = self.item_pool[check_progressive_item(self.options, Items.BOMB_GLOVE.name)].pop(0) - elif self.options.starting_item == StartingItem.option_random_same: - starting_item = [] - weapon_list = [item.name for item in Items.ALL_WEAPONS] - for name, item in self.item_pool.items(): - if name in weapon_list: - starting_item.extend(item) - self.random.shuffle(starting_item) - starting_item = self.item_pool[starting_item[0].name].pop(0) else: starting_item = [] - equip_list = [item.name for item in Items.ALL_STARTING] + item_list = [item.name for item in Items.STARTING_WEAPONS] + if (self.options.starting_item == StartingItem.option_random_item and + self.options.shuffle_gadgets > ShuffleGadgets.option_random_same): + item_list += [item.name for item in Items.GADGETS] + if self.options.progressive_weapons.value is Options.GoldenWeaponProgression.option_normal: + item_list += [item.name for item in Items.GOLDEN_WEAPONS] for name, item in self.item_pool.items(): - if name in equip_list: + if name in item_list: starting_item.extend(item) self.random.shuffle(starting_item) starting_item = self.item_pool[starting_item[0].name].pop(0) @@ -206,7 +203,7 @@ def generate_early(self) -> None: if count > len(self.item_pool[name]): rac_logger.warning(f"Too many copies of {name} in yaml start inventory! Giving only " f"{len(self.item_pool[name])} of {count} copies") - for i in range(count): + for _ in range(count): if self.item_pool[name]: self.preplaced_items += [self.item_pool[name].pop(0)] else: diff --git a/worlds/RAC1/data/Items.py b/worlds/RAC1/data/Items.py index 2c5d21f968e5..8f6cfa6c2002 100644 --- a/worlds/RAC1/data/Items.py +++ b/worlds/RAC1/data/Items.py @@ -214,6 +214,7 @@ class CollectableData(ItemData): TAUNTER, VISIBOMB, WALLOPER, + RYNO, DRONE_DEVICE, ] @@ -227,7 +228,6 @@ class CollectableData(ItemData): TESLA_CLAW, GLOVE_OF_DOOM, MORPH_O_RAY, - RYNO, DECOY_GLOVE, ] @@ -484,11 +484,11 @@ class CollectableData(ItemData): *NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES, *NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS, *GOLD_BOLTS, *PLANETS, *SKILLPOINTS, *BOLT_PACKS] -ITEM_POOL: Sequence[ItemData] = [*PLANETS, *WEAPONS, *NON_PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, *GADGETS, *PACKS, - *HELMETS, *BOOTS, *EXTRA_ITEMS, *NON_PROGRESSIVE_HOVERBOARDS, *NON_PROGRESSIVE_TRADES, - *NON_PROGRESSIVE_NANOTECHS] # *SKILLPOINTS -ALL_WEAPONS: Sequence[ItemData] = [*WEAPONS, *NON_PROGRESSIVE_WEAPONS, *PROGRESSIVE_WEAPONS, *GOLDEN_WEAPONS, - *PROGRESSIVE_GOLDEN_WEAPONS] +ITEM_POOL: Sequence[ItemData] = [*PLANETS, *WEAPONS, *GADGETS, *EXTRA_ITEMS] # *SKILLPOINTS + +STARTING_WEAPONS: Sequence[ItemData] = [*WEAPONS, *NON_PROGRESSIVE_WEAPONS, *PROGRESSIVE_WEAPONS, + *PROGRESSIVE_GOLDEN_WEAPONS] +ALL_WEAPONS: Sequence[ItemData] = [*STARTING_WEAPONS, *GOLDEN_WEAPONS] ALL_PACKS: Sequence[ItemData] = [*PACKS, *PROGRESSIVE_PACKS] ALL_HELMETS: Sequence[ItemData] = [*HELMETS, *PROGRESSIVE_HELMETS] ALL_BOOTS: Sequence[ItemData] = [*BOOTS, *PROGRESSIVE_BOOTS] @@ -498,7 +498,7 @@ class CollectableData(ItemData): ALL_HOVERBOARD: Sequence[ItemData] = [*NON_PROGRESSIVE_HOVERBOARDS, *PROGRESSIVE_HOVERBOARDS] ALL_TRADE: Sequence[ItemData] = [*NON_PROGRESSIVE_TRADES, *PROGRESSIVE_TRADES] ALL_NANOTECH: Sequence[ItemData] = [*NON_PROGRESSIVE_NANOTECHS, *PROGRESSIVE_NANOTECHS] -ALL_STARTING: Sequence[ItemData] = [*ALL_WEAPONS, *GADGETS] +ALL_STARTING: Sequence[ItemData] = [*STARTING_WEAPONS, *GADGETS] SUCK_GROUP: Sequence[ItemData] = [SUCK_CANNON, GOLDEN_SUCK_CANNON, PROGRESSIVE_SUCK] BOMB_GROUP: Sequence[ItemData] = [BOMB_GLOVE, GOLDEN_BOMB_GLOVE, PROGRESSIVE_BOMB] @@ -734,8 +734,14 @@ def progression_rules(world): match world.options.progressive_helmets.value: case Options.ProgressiveOptions.option_progressive: PROG[O2_MASK.name] = {PROGRESSIVE_HELMET.name: 1} - PROG[SONIC_SUMMONER.name] = {PROGRESSIVE_HELMET.name: 2} - PROG[PILOTS_HELMET.name] = {PROGRESSIVE_HELMET.name: 3} + if world.options.shuffle_helmets.value <= Options.ItemOptions.option_random_same: + PROG[SONIC_SUMMONER.name] = {PROGRESSIVE_HELMET.name: 3} + PROG[PILOTS_HELMET.name] = {PROGRESSIVE_HELMET.name: 2} + world.orders["progressive_helmets_order"] = [O2_MASK.item_id, PILOTS_HELMET.item_id, + SONIC_SUMMONER.item_id] + else: + PROG[SONIC_SUMMONER.name] = {PROGRESSIVE_HELMET.name: 2} + PROG[PILOTS_HELMET.name] = {PROGRESSIVE_HELMET.name: 3} case Options.ProgressiveOptions.option_progressive_reversed: world.orders["progressive_helmets_order"].reverse() PROG[O2_MASK.name] = {PROGRESSIVE_HELMET.name: 3} @@ -749,6 +755,18 @@ def progression_rules(world): PROGRESSIVE_HELMET.name: 1 + world.orders["progressive_helmets_order"].index(SONIC_SUMMONER.item_id)} PROG[PILOTS_HELMET.name] = { PROGRESSIVE_HELMET.name: 1 + world.orders["progressive_helmets_order"].index(PILOTS_HELMET.item_id)} + if (world.options.shuffle_helmets.value <= Options.ItemOptions.option_random_same and + PROG[PILOTS_HELMET.name].values() == 3): + temp = PROG[PILOTS_HELMET.name] + PROG[PILOTS_HELMET.name] = PROG[SONIC_SUMMONER.name] + PROG[SONIC_SUMMONER.name] = temp + if world.orders["progressive_helmets_order"].index(O2_MASK.item_id) == 0: + world.orders["progressive_helmets_order"] = [O2_MASK.item_id, PILOTS_HELMET.item_id, + SONIC_SUMMONER.item_id] + else: + world.orders["progressive_helmets_order"] = [PILOTS_HELMET.item_id, O2_MASK.item_id, + SONIC_SUMMONER.item_id] + case _: pass @@ -769,39 +787,46 @@ def progression_rules(world): case _: pass - match world.options.progressive_hoverboard.value: - case Options.ProgressiveOptions.option_progressive: - PROG[HOVERBOARD.name] = {PROGRESSIVE_HOVERBOARD.name: 1} - PROG[ZOOMERATOR.name] = {PROGRESSIVE_HOVERBOARD.name: 2} - case Options.ProgressiveOptions.option_progressive_reversed: - world.orders["progressive_hoverboard_order"].reverse() - PROG[HOVERBOARD.name] = {PROGRESSIVE_HOVERBOARD.name: 2} - PROG[ZOOMERATOR.name] = {PROGRESSIVE_HOVERBOARD.name: 1} - case Options.ProgressiveOptions.option_progressive_random: - world.random.shuffle(world.orders["progressive_hoverboard_order"]) - PROG[HOVERBOARD.name] = { - PROGRESSIVE_HOVERBOARD.name: 1 + world.orders["progressive_hoverboard_order"].index(HOVERBOARD.item_id)} - PROG[ZOOMERATOR.name] = { - PROGRESSIVE_HOVERBOARD.name: 1 + world.orders["progressive_hoverboard_order"].index(ZOOMERATOR.item_id)} - case _: - pass - - match world.options.progressive_raritanium.value: - case Options.ProgressiveOptions.option_progressive: - PROG[RARITANIUM.name] = {PROGRESSIVE_TRADE.name: 1} - PROG[PERSUADER.name] = {PROGRESSIVE_TRADE.name: 2} - case Options.ProgressiveOptions.option_progressive_reversed: - world.orders["progressive_raritanium_order"].reverse() - PROG[RARITANIUM.name] = {PROGRESSIVE_TRADE.name: 2} - PROG[PERSUADER.name] = {PROGRESSIVE_TRADE.name: 1} - case Options.ProgressiveOptions.option_progressive_random: - world.random.shuffle(world.orders["progressive_raritanium_order"]) - PROG[RARITANIUM.name] = { - PROGRESSIVE_TRADE.name: 1 + world.orders["progressive_raritanium_order"].index(RARITANIUM.item_id)} - PROG[PERSUADER.name] = { - PROGRESSIVE_TRADE.name: 1 + world.orders["progressive_raritanium_order"].index(PERSUADER.item_id)} - case _: - pass + if world.options.shuffle_extra_items.value == Options.ItemOptions.option_vanilla: + PROG[HOVERBOARD.name] = {HOVERBOARD.name: 1, PROGRESSIVE_HOVERBOARD.name: 1} + PROG[ZOOMERATOR.name] = {ZOOMERATOR.name: 1, PROGRESSIVE_HOVERBOARD.name: 2} + else: + match world.options.progressive_hoverboard.value: + case Options.ProgressiveOptions.option_progressive: + PROG[HOVERBOARD.name] = {PROGRESSIVE_HOVERBOARD.name: 1} + PROG[ZOOMERATOR.name] = {PROGRESSIVE_HOVERBOARD.name: 2} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_hoverboard_order"].reverse() + PROG[HOVERBOARD.name] = {PROGRESSIVE_HOVERBOARD.name: 2} + PROG[ZOOMERATOR.name] = {PROGRESSIVE_HOVERBOARD.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_hoverboard_order"]) + PROG[HOVERBOARD.name] = { + PROGRESSIVE_HOVERBOARD.name: 1 + world.orders["progressive_hoverboard_order"].index(HOVERBOARD.item_id)} + PROG[ZOOMERATOR.name] = { + PROGRESSIVE_HOVERBOARD.name: 1 + world.orders["progressive_hoverboard_order"].index(ZOOMERATOR.item_id)} + case _: + pass + if world.options.shuffle_extra_items.value == Options.ItemOptions.option_vanilla: + PROG[RARITANIUM.name] = {RARITANIUM.name: 1, PROGRESSIVE_TRADE.name: 1} + PROG[PERSUADER.name] = {PERSUADER.name: 1, PROGRESSIVE_TRADE.name: 2} + else: + match world.options.progressive_raritanium.value: + case Options.ProgressiveOptions.option_progressive: + PROG[RARITANIUM.name] = {PROGRESSIVE_TRADE.name: 1} + PROG[PERSUADER.name] = {PROGRESSIVE_TRADE.name: 2} + case Options.ProgressiveOptions.option_progressive_reversed: + world.orders["progressive_raritanium_order"].reverse() + PROG[RARITANIUM.name] = {PROGRESSIVE_TRADE.name: 2} + PROG[PERSUADER.name] = {PROGRESSIVE_TRADE.name: 1} + case Options.ProgressiveOptions.option_progressive_random: + world.random.shuffle(world.orders["progressive_raritanium_order"]) + PROG[RARITANIUM.name] = { + PROGRESSIVE_TRADE.name: 1 + world.orders["progressive_raritanium_order"].index(RARITANIUM.item_id)} + PROG[PERSUADER.name] = { + PROGRESSIVE_TRADE.name: 1 + world.orders["progressive_raritanium_order"].index(PERSUADER.item_id)} + case _: + pass match world.options.progressive_nanotech.value: case Options.ProgressiveOptions.option_progressive: @@ -970,24 +995,44 @@ def check_progressive_item(options, item) -> str: match item: case SUCK_CANNON.name: new_item = PROGRESSIVE_SUCK.name + case GOLDEN_SUCK_CANNON.name: + new_item = PROGRESSIVE_SUCK.name case BOMB_GLOVE.name: new_item = PROGRESSIVE_BOMB.name + case GOLDEN_BOMB_GLOVE.name: + new_item = PROGRESSIVE_BOMB.name case DEVASTATOR.name: new_item = PROGRESSIVE_DEVASTATOR.name + case GOLDEN_DEVASTATOR.name: + new_item = PROGRESSIVE_DEVASTATOR.name case BLASTER.name: new_item = PROGRESSIVE_BLASTER.name + case GOLDEN_BLASTER.name: + new_item = PROGRESSIVE_BLASTER.name case PYROCITOR.name: new_item = PROGRESSIVE_PYROCITOR.name + case GOLDEN_PYROCITOR.name: + new_item = PROGRESSIVE_PYROCITOR.name case MINE_GLOVE.name: new_item = PROGRESSIVE_MINE.name + case GOLDEN_MINE_GLOVE.name: + new_item = PROGRESSIVE_MINE.name case TESLA_CLAW.name: new_item = PROGRESSIVE_TESLA.name + case GOLDEN_TESLA_CLAW.name: + new_item = PROGRESSIVE_TESLA.name case GLOVE_OF_DOOM.name: new_item = PROGRESSIVE_DOOM.name + case GOLDEN_GLOVE_OF_DOOM.name: + new_item = PROGRESSIVE_DOOM.name case MORPH_O_RAY.name: new_item = PROGRESSIVE_MORPH.name + case GOLDEN_MORPH_O_RAY.name: + new_item = PROGRESSIVE_MORPH.name case DECOY_GLOVE.name: new_item = PROGRESSIVE_DECOY.name + case GOLDEN_DECOY_GLOVE.name: + new_item = PROGRESSIVE_DECOY.name case HELI_PACK.pool: if options.progressive_packs.value: new_item = PROGRESSIVE_PACK.name