diff --git a/.gitignore b/.gitignore index 0caf00a9782..e0b47089e97 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.apm3 *.apmc *.apz5 +*.apg *.pyc *.pyd *.sfc @@ -17,6 +18,7 @@ *.gb *.gbc *.gba +*.iso *.wixobj *.lck *.db3 diff --git a/Patch.py b/Patch.py index 113d0658c6b..8f7b17e2268 100644 --- a/Patch.py +++ b/Patch.py @@ -1,3 +1,5 @@ + + from __future__ import annotations import os diff --git a/README.md b/README.md index a8f269f557f..f71a284a2e5 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Currently, the following games are supported: * Hylics 2 * Overcooked! 2 * Zillion +* Super Mario Galaxy + For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/). Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled diff --git a/worlds/smgalaxy/Options.py b/worlds/smgalaxy/Options.py new file mode 100644 index 00000000000..b0230d5c514 --- /dev/null +++ b/worlds/smgalaxy/Options.py @@ -0,0 +1,26 @@ +from typing import TypedDict +from Options import Choice, Range + +# this defines the enable_purple_coin_stars setting +class EnablePurpleCoinStars(Choice): + """tuning this off we allow purple coin stars to count as checks do note all purple coin stars are postgame only but one.""" + display_name = "Enable Purple Coin Stars" + option_main_game_only = 0 + option_all = 1 + option_none = 2 + +# this allows players to pick their own star count to finish the game. +class StarstoFinish(Range): + "This will set the number of stars required to reach the center of the universe." + display_name = "Stars_to_finish" + range_start = 25 + range_end = 99 + default = 60 + +# this defines all the options. +galaxy_options = { + "enable_purple_coin_stars": EnablePurpleCoinStars, + "Stars_to_finish": StarstoFinish, +} + + diff --git a/worlds/smgalaxy/Regions.py b/worlds/smgalaxy/Regions.py new file mode 100644 index 00000000000..70859f019c8 --- /dev/null +++ b/worlds/smgalaxy/Regions.py @@ -0,0 +1,152 @@ +import imp +import typing +from .Options import smg_options, EnablePurpleCoinStars +from BaseClasses import Region, Location, RegionType, Entrance, MultiWorld +from .locations import SMGLocation, location_table,locHH_table,locGE_table, \ + locSJ_table,locBR_table,locBB_table, \ + locGG_table,locFF_table,locDD_table,locDDune_table, \ + locGL_table,locSS_table,locTT_table, \ + locDN_table,locMM_table, \ + locHL_table,locbosses_table,locspecialstages_table + + +def create_regions(player: int, world: MultiWorld, regions: dict): + #defines the commet obserbatory + regspecialstages = Region("Menu", RegionType.Generic, "Ship", player, world) + locspecialstages_names = [name for name, id in locspecialstages_table.items()] + locspecialstages_names = [name for name, id in locHL_table.items()] + locspecialstages_names = [name for name, id in locbosses_table.items()] + regspecialstages.locations += [SMGLocation(player, loc_name, location_table[loc_name], regspecialstages) for loc_name in locspecialstages_names] + #if world.enable_purple_coin_stars[player] == EnablePurpleCoinStars.option_main_game_only: + # regspecialstages.locations.append(SMGLocation)(player, "GG: Gateway's Purple coins", location_table["GG: Gateway's Purple coins"], regspecialstages) + world.regions.append(regspecialstages) + # defines the good egg galaxy region + regGE = Region("Good Egg", player, world) + locGE_names = [name for name, id in locGE_table.items()] + regGE.locations += [SMGLocation(player, loc_name, location_table[loc_name], regGE) for loc_name in locGE_names] + if world.enable_purple_coin_stars[player].value == 1: + regGE.locations.append(SMGLocation)(player, "GE: Purple Coin Omelet", location_table["GE: Purple Coin Omelet"], regGE) + world.regions.append(regGE) + # defines the honeyhive galaxey region + regHH = Region("Honeyhive", player, world) + locHH_names = [name for name, id in locHH_table.items()] + regHH.locations += [SMGLocation(player, loc_name, location_table[loc_name], regHH) for loc_name in locHH_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regHH.locations.append(SMGLocation)(player, "GE: The Honeyhive's Purple Coins", location_table["HH: The Honeyhive's Purple Coins"], regHH) + world.regions.append(regHH) + # defines the Space Junk galaxy region + regSJ = Region("Space Junk", player, world) + locSJ_names = [name for name, id in locSJ_table.items()] + regSJ.locations += [SMGLocation(player, loc_name, location_table[loc_name], regSJ) for loc_name in locSJ_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regHH.locations.append(SMGLocation)(player, "SJ: Purple Coin Spacewalk", location_table["SJ: Purple Coin Spacewalk"], regSJ) + world.regions.append(regSJ) + # defines the Battlerock galaxy + regBR = Region("Battlerock", player, world) + locBR_names = [name for name, id in locBR_table.items()] + regBR.locations += [SMGLocation(player, loc_name, location_table[loc_name], regBR) for loc_name in locBR_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regBR.locations.append(SMGLocation)(player, "BR: Purple Coins on the Battlerock", location_table["BR: Purple Coins on the Battlerock"], regBR) + world.regions.append(regBR) + # defines the Beach Bowl galaxy + regBB = Region("Beach Bowl", player, world) + locBB_names = [name for name, id in locBB_table.items()] + regBB.locations += [SMGLocation(player, loc_name, location_table[loc_name], regBB) for loc_name in locBB_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regBB.locations.append(SMGLocation)(player, "BB: Beachcombing for Purple Coins", location_table["BB: Beachcombing for Purple Coins"], regBB) + world.regions.append(regBB) + # define Ghostly galaxy + regG = Region("Ghostly", player, world) + locG_names = [name for name, id in locGG_table.items()] + regG.locations += [SMGLocation(player, loc_name, location_table[loc_name], regG) for loc_name in locG_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regG.locations.append(SMGLocation)(player, "G: Purple Coins in the Bone Pen", location_table["G: Purple Coins in the Bone Pen"], regG) + world.regions.append(regG) + # defines the Gusty Gardens galaxy + regGG = Region("Gusty Gardens", player, world) + locGG_names = [name for name, id in locGG_table.items()] + regGG.locations += [SMGLocation(player, loc_name, location_table[loc_name], regGG) for loc_name in locGG_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regGG.locations.append(SMGLocation)(player, "GG: Purple Coins on the Puzzle Cube", location_table["GG: Purple Coins on the Puzzle Cube"], regGG) + world.regions.append(regGG) + # defines Freezeflame galaxy + regFF = Region("Freezeflame", player, world) + locFF_names = [name for name, id in locFF_table.items()] + regFF.locations += [SMGLocation(player, loc_name, location_table[loc_name], regFF) for loc_name in locFF_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regGG.locations.append(SMGLocation)(player, "FF: Purple Coins on the Summit", location_table["FF: Purple Coins on the Summit"], regGG) + world.regions.append(regFF) + # defines DustyDune Galaxy + regDDune = Region("Dusty Dune", player, world) + locDDune_names = [name for name, id in locDDune_table.items()] + regDDune.locations += [SMGLocation(player, loc_name, location_table[loc_name], regDDune) for loc_name in locDDune_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regDDune.locations.append(SMGLocation)(player, "DDune: Purple Coins in the Desert", location_table["DDune: Purple Coin in the Desert"], regDDune) + world.regions.append(regDDune) + # defines golden leaf galaxy + regGL = Region("Gold Leaf", player, world) + locGL_names = [name for name, id in locGL_table.items()] + regGL.locations += [SMGLocation(player, loc_name, location_table[loc_name], regGL) for loc_name in locGL_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regGL.locations.append(SMGLocation)(player, "GL: Purple Coins in the Woods", location_table["GL: Purple Coins in the Woods"], regGL) + world.regions.append(regGL) + # defines the Sea slide galaxy + regSS = Region("Sea Slide", player, world) + locSS_names = [name for name, id in locSS_table.items()] + regSS.locations += [SMGLocation(player, loc_name, location_table[loc_name], regSS) for loc_name in locSS_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regSS.locations.append(SMGLocation)(player, "SS: Purple Coins by the Seaside", location_table["SS: Purple Coins by the Seaside"], regSS) + world.regions.append(regSS) + # defines toy time galaxy + regTT = Region ("Toy Time", player, world) + locTT_names = [name for name, id in locTT_table.items()] + regTT.locations += [SMGLocation(player, loc_name, location_table[loc_name], regTT) for loc_name in locTT_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regSS.locations.append(SMGLocation)(player, "TT: Luigi's Purple Coins", location_table["TT: Luigi's Purple Coins"], regSS) + world.regions.append(regTT) + # defines deep dark galaxy + regDD = Region("Deep Dark", player, world) + locDD_names = [name for name, id in locDD_table.items()] + regDD.locations += [SMGLocation(player, loc_name, location_table[loc_name], regDD) for loc_name in locDD_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regDD.locations.append(SMGLocation)(player, "DD: Plunder the Purple Coins", location_table["DD: Plunder the Purple Coins"], regDD) + world.regions.append(regDD) + # defines Dreadnaught galaxy + regDN = Region("Dreadnaught", player, world) + locDN_names = [name for name, id in locDN_table.items()] + regDN.locations += [SMGLocation (player, loc_name, location_table[loc_name], regDN) for loc_name in locDN_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regDN.locations.append(SMGLocation)(player, "DN: Battlestation's Purple Coins", location_table["DN: Battlestation's Purple Coins"], regDN) + world.regions.append(regDN) + # defines Melty Molten galaxy + regMM = Region("Melty Molten", player, world) + locMM_names = [name for name, id in locMM_table.items()] + regMM.locations += [SMGLocation (player, loc_name, location_table[loc_name], regMM) for loc_name in locMM_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regMM.locations.append(SMGLocation)(player, "MM: Red-Hot Purple Coins", location_table["MM: Red-Hot Purple Coins"], regMM) + world.regions.append(regMM) + #defines the fountain + regFountain = Region("Fountain", player, world) + world.regions.append(regFountain) + #defines the kitchen + regKitchen = Region("Kitchen", player, world) + world.regions.append(regKitchen) + #defines the bedroom + regBedroom = Region("Bedroom", player, world) + world.regions.append(regBedroom) + #defines the Engine Room + regEngineRoom = Region("Engine Room", player, world) + world.regions.append(regEngineRoom) + #defines the garden + regGarden = Region("Garden", player, world) + world.regions.append(regGarden) + +def connect_regions(multiworld: MultiWorld, player: int, source: str, target: str, rule): + sourceRegion = multiworld.get_region(source, player) + targetRegion = multiworld.get_region(target, player) + + connection = Entrance(player,'', sourceRegion) + connection.access_rule = rule + + sourceRegion.exits.append(connection) + connection.connect(targetRegion) diff --git a/worlds/smgalaxy/Rules.py b/worlds/smgalaxy/Rules.py new file mode 100644 index 00000000000..5176ab2fe25 --- /dev/null +++ b/worlds/smgalaxy/Rules.py @@ -0,0 +1,97 @@ +from sqlite3 import connect + +from worlds.AutoWorld import LogicMixin +from ..generic.Rules import add_rule +from .regions import connect_regions + +class GalaxyLogic(LogicMixin): +# these are varible states that the game uses for logic in different points. + def smg_gate_open(self, player: int): + return self.has('Grand Star Engine Room', player) + + def smg_can_finish(self, player: int): + return self.has('Power Star 60') and self.has('Grand Star Bedroom') + + def smg_purple_coins(self, player: int): + return self.has('Power Star 60') and self.has('Grand Star Bedroom') and self.has('Grand Star Engine Room', player) + + def smg_can_get_comet(self, player: int): + return self.has('Power Star 13') + + def smg_trail(self, player: int): + return self.has('Green Star 3') + + # main stage logic +def set_star_rules(world,player): + connect_regions(world, player, "Menu", "Good Egg", lambda state: True) + connect_regions(world, player, "Menu", "Honeyhive", lambda state: state.has("Power Star", player, 3)) + connect_regions(world, player, "Menu", "Fountain", lambda state: state.has("Grand Star Terrace", player)) + connect_regions(world, player, "Fountain", "Space Junk", lambda state: state.has("Power Star", player, 9)) + connect_regions(world, player, "Fountain", "Space Junk", lambda state: state.has("Power Star", player, 12)) + connect_regions(world, player, "Menu", "Kitchen", lambda state: state.has("Grand Star Fountain", player)) + connect_regions(world, player, "Kitchen", "Beach Bowl", lambda state: state.has("Power Star", player, 18)) + connect_regions(world, player, "Kitchen", "Ghostly", lambda state: state.has("Power Star", player, 20)) + connect_regions(world, player, "Menu", "Bedroom", lambda state: state.has("Grand Star Kitchen", player)) + connect_regions(world, player, "Bedroom", "Gusty Gardens", lambda state: state.has("Power Star", player, 24)) + connect_regions(world, player, "Bedroom", "Freezeflame", lambda state: state.has("Power Star", player, 26)) + connect_regions(world, player, "Menu", "Engine Room", lambda state: state.has("Grand Star Bedroom", player)) + connect_regions(world, player, "Engine Room", "Gold Leaf", lambda state: state.has("Power Star", player, 34)) + connect_regions(world, player, "Engine Room", "Toy Time", lambda state: state.has("Power Star", player, 40)) + connect_regions(world, player, "Engine Room", "Sea Slide", lambda state: state.has("Power Star", player, 36)) + connect_regions(world, player, "Menu", "Garden", lambda state: state.has("Grand Star Engine Room", player)) + connect_regions(world, player, "Garden", "Deep Dark", lambda state: state.has("Power Star", player, 46)) + connect_regions(world, player, "Garden", "Dreadnaught", lambda state: state.has("Power Star", player, 48)) + connect_regions(world, player, "Garden", "Melty Molten", lambda state: state.has("Power Star", player, 52)) + # special stages logic + add_rule(world.get_location("LDL: Surfing 101", player), lambda state: state.has("Power Star", player, 5)) + add_rule(world.get_location("FS: Painting the Planet Yellow", player), lambda state: state.has("Power Star", player, 7)) + add_rule(world.get_location("RG: Rolling in the Clouds", player), lambda state: state.has("Power Star", player, 11) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("HS: Shrinking Satellite", player), lambda state: state.has ("Power Star", player, 18) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("BUB: Through the Poison Swamp", player), lambda state: state.has ("Power Star", player, 19) and state.has("Grand Star Fountain", player)) + add_rule(world.get_location("BB: The Secret of Buoy Base", player), lambda state: state.has ("Power Star", player, 30) and state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("BB: The Floating Fortress", player), lambda state: state.has ("Power Star", player, 30) and state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("GG: Gateway's Purple coins", player), lambda state: state.has("Grand Star Engine Room", player)) + add_rule(world.get_location("BF: Kingfin's Fearsome Waters", player), lambda state: state.has("Power Star", player, 55) and state.has("Grand Star Bedroom", player)) + add_rule(world.get_location("MS: Watch Your Step", player), lambda state: state.has("Power Star", player, 50) and state.has("Grand Star Engine Room", player) and state.has("Grand Star Bedroom", player)) + add_rule(world.get_location("DDR: Giant Eel Breakout", player), lambda state: state.has("Grand Star Fountain", player)) + add_rule(world.get_location("RGT: Gizmos, Gears, and Gadgets", player), lambda state: state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player) and state.smg_trail(player)) + add_rule(world.get_location("LDT: The Galaxy's Greatest Wave", player), lambda state: state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player) and state.has("Grand Star Kitchen", player) and state.smg_trail(player)) + add_rule(world.get_location("BBT: The Electric Labyrinth", player), lambda state: state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player) and state.has("Grand Star Kitchen", player) and state.smg_trail(player)) + add_rule(world.get_location("SS: Rocky Road", player), lambda state: state.has("Power Star", player, 7)) + add_rule(world.get_location("SP: A Very Sticky Situation", player), lambda state: state.has("Grand Star Terrace", player) and state.has("Power Star", player, 9)) + add_rule(world.get_location("BM: Bigmouth's Gold Bait", player), lambda state: state.has("Grand Star Kitchen", player) and state.has("Power Star", player, 29)) + add_rule(world.get_location("SS: Choosing a Favorite Snack", player), lambda state: state.has("Grand Star Bedroom", player) and state.has("Power Star", player, 36) and state.has("Grand Star Fountain", player)) + add_rule(world.get_location("BB: Racing the Spooky Speedster", player), lambda state: state.has("Grand Star Engine Room", player) and state.has("Grand Star Kitchen", player)) + add_rule(world.get_location("SC: Star Bunnies in the Snow", player), lambda state: state.has("Grand Star Engine Room", player) and state.has("Power Star", player, 52)) + # comet logic + add_rule(world.get_location("GE: Dino Piranha Speed Run", player), lambda state: state.has("Power Star", player, 13)) + add_rule(world.get_location("HH: Honeyhive Cosmic Mario Race", player), lambda state: state.has("Power Star", player, 13)) + add_rule(world.get_location("SJ: Pull Star Path Speed Run", player), lambda state: state.has("Power Star", player, 13)) + add_rule(world.get_location("BR: Topmanic's Dardevil Run", player), lambda state: state.smg_can_get_comet(player)) + add_rule(world.get_location("BB: Fast Foes on the Cyclone Stone", player), lambda state: state.smg_can_get_comet(player)) + # boss stage logic + add_rule(world.get_location("BJ: Megaleg's Moon", player), lambda state: state.has("Power Star", player, 8)) + add_rule(world.get_location("B: The Firery Stronghold", player), lambda state: state.has("Power Star", player, 15) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("BJ: Sinking the Airships", player), lambda state: state.has("Power Star", player, 23) and state.has("Grand Star Fountain", player)) + add_rule(world.get_location("BJ: King Kaliente's Spicy Return", player), lambda state: state.has("Power Star", player, 45) and state.has("Grand Star Engine Room", player)) + add_rule(world.get_location("B: Darkness on the Horizon", player), lambda state: state.has("Power Star", player, 33) and state.has("Grand Star Kitchen", player)) + + + # purple coin star logic + if world.EnablePurpleCoinStars[player]: + add_rule(world.get_location("DN: Battlestation's Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("MM: Red-Hot Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("TT: Luigi's Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("DD: Plunder the Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("GL: Purple Coins in the Woods", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("FF: Purple Coins on the Summit", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("SS: Purple Coins by the Seaside", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("GG: Purple Coins on the Puzzle Cube", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("G: Purple Coins in the Bone Pen", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("DDune: Purple Coin in the Desert", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("BR: Purple Coins on the Battlerock", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("GE: Purple Coin Omelet", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("HH: Honeyhive's Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("SJ: Purple Coin Spacewalk", player), lambda state: state.smg_purple_coins(player)) + + world.completion_condition[player] = lambda state: state.smg_can_finish(player) diff --git a/worlds/smgalaxy/__init__.py b/worlds/smgalaxy/__init__.py new file mode 100644 index 00000000000..f158342f106 --- /dev/null +++ b/worlds/smgalaxy/__init__.py @@ -0,0 +1,78 @@ +import string +from .items import item_table, SMGItem +from .locations import location_table, SMGLocation +from .Options import EnablePurpleCoinStars, galaxy_options +from .Rules import set_star_rules +from .regions import create_regions +from BaseClasses import Item, Tutorial, ItemClassification, Region, Location, RegionType, Entrance, MultiWorld +from ..AutoWorld import World, WebWorld + +client_version = 1 + + +class SMGWeb(WebWorld): + tutorials = [Tutorial( + "Multiworld Setup Guide", + "A guide to setting up Super Mario Galaxy for MultiWorld.", + "English", + "setup_en.md", + "setup/en", + ["squidy"] + )] + +class SuperMarioGalaxy(World): + """ + Super Mario Galaxy allows you to explore the cosomos with rosalinna in the comet obserbatory. + Mario must collect Power Stars and Grand Stars to power the obserbatory so it can go to the + center of the universe in order to save peach. + """ + + game: str = "Super Mario Galaxy" + topology_present = False + + item_name_to_id = item_table + location_name_to_id = location_table + + data_version = 1 + forced_auto_forfeit = False + + option_definitions = galaxy_options + + def create_regions(self): + create_regions(self.multiworld, location_table, self) + + def set_star_rules(self): + set_star_rules(self.multiworld, self.player) + + def create_item(self, name: str) -> Item: + item_id = item_table[name] + if name == "Power Star": + classification = ItemClassification.progression_skip_balancing + else: + classification = ItemClassification.progression + item = SMGItem(name, True, item_id, self.player) + + return item + + + def generate_basic(multiworld, self, player): + gstaritem = self.create_item("Green Star") + self.multiworld.itempool += [gstaritem for i in range(0,3)] + + staritem = self.create_item("Power Star") + # check to see what setting enable purple coin stars is on to see how many stars to create + if self.multiworld.enable_purple_coin_stars[player] == EnablePurpleCoinStars.option_main_game_only: + self.multiworld.itempool += [staritem for i in range(0,102)] + + elif self.multiworld.enable_purple_coin_stars[player] == EnablePurpleCoinStars.option_all: + self.multiworld.itempool += [staritem for i in range(0,118)] + + else: + self.multiworld.itempool += [staritem for i in range(0,101)] + + grandstar1 = self.create_item("Grand Star Terrace") + grandstar2 = self.create_item("Grand Star Fountain") + grandstar3 = self.create_item("Grand Star Kitchen") + grandstar4 = self.create_item("Grand Star Bedroom") + grandstar5 = self.create_item("Grand Star Engine Room") + self.multiworld.itempool += [grandstar1,grandstar2,grandstar3,grandstar4,grandstar5] diff --git a/worlds/smgalaxy/docs/en_Super_Mario_Galaxy.md b/worlds/smgalaxy/docs/en_Super_Mario_Galaxy.md new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/worlds/smgalaxy/docs/en_Super_Mario_Galaxy.md @@ -0,0 +1 @@ + diff --git a/worlds/smgalaxy/items.py b/worlds/smgalaxy/items.py new file mode 100644 index 00000000000..e575e05e561 --- /dev/null +++ b/worlds/smgalaxy/items.py @@ -0,0 +1,15 @@ +from BaseClasses import Item + +# this lets us use these items by using SMGItem. +class SMGItem(Item): + game: str = "Super Mario Galaxy" +# This is all the items that are used by the game we define them here so the they can be used. +item_table = { + "Power Star": 170000000, + "Grand Star Terrace": 170000001, + "Grand Star Fountain": 170000002, + "Grand Star Kitchen": 170000003, + "Grand Star Bedroom": 170000004, + "Grand Star Engine Room": 170000005, + "Green Star": 170000006, +} diff --git a/worlds/smgalaxy/locations.py b/worlds/smgalaxy/locations.py new file mode 100644 index 00000000000..cb51c57f6f6 --- /dev/null +++ b/worlds/smgalaxy/locations.py @@ -0,0 +1,171 @@ +from BaseClasses import Location + +class SMGLocation(Location): + game: str = "Super Mario Galaxy" + +# good egg galaxy +locGE_table = { + "GE: Dino Piranha": 170000000, + "GE: A Snack of Cosmic Proportions": 170000001, + "GE: King Kaliente's Battle Fleet": 170000002, + "GE: Luigi on the Roof": 170000003, + "GE: Dino Piranha Speed Run": 170000004 +} +# +locHH_table = { + "HH: Bee Mario Takes Flight": 170000006, + "HH: Trouble on the Tower": 170000007, + "HH: Big Bad Bugabooom": 170000008, + "HH: Luigi in the Honeyhive Kingdom": 17000009, + "HH: Honeyhive Cosmic Mario Race": 170000010 +} + +locspecialstages_table = { + "LDL: Surfing 101": 170000012, + "FS: Painting the Planet Yellow": 170000013, + "RG: Rolling in the Clouds": 170000014, + "HS: Shrinking Satellite": 170000015, + "BUB: Through the Poison Swamp": 170000016, + "BB: The Floating Fortress": 170000017, + "BB: The Secret of Buoy Base": 170000018, + "GG: Grand Star Rescue": 170000019, + "BF: Kingfin's Fearsome Waters": 170000021, + "MS: Watch Your Step": 170000022, + "RGT: Gizmos, Gears, and Gadgets": 170000023, + "LDT: The Galaxy's Greatest Wave": 170000024, + "BBT: The Electric Labyrinth": 170000025 +} + +locbosses_table = { + "BJ: Megaleg's Moon": 170000026, + "B: The Firery Stronghold": 170000027, + "BJ: Sinking the Airships": 170000028, + "BJ: King Kaliente's Spicy Return": 170000029, + "B: Darkness on the Horizon": 170000030 +} + +locSJ_table = { + "SJ: Pull Star Path": 170000031, + "SJ: Kamella's Airship Attack": 170000032, + "SJ: Tarantox's Tangled Web": 170000033, + "SJ: Yoshi's Unexpected Apparence": 170000034, + "SJ: Pull Star Path Speed Run": 170000035 +} +locBR_table = { + "BR: Battlerock Barrage": 170000037, + "BR: Breaking into the Battlerock": 170000038, + "BR: Topmaniac's Garbage dump": 170000039, + "BR: Topmanic's Dardevil Run": 170000040, + "BR: Luigi under the Saucer": 170000042 +} +locBB_table = { + "BB: Sunken Treasure": 170000043, + "BB: Passing the Swim Test": 170000044, + "BB: The Secret Undersea Cavern": 170000045, + "BB: Fast Foes on the Cyclone Stone": 170000046, + "BB: Wall Jumping Water Falls": 170000048 +} +locG_table = { + "G: Luigi and the Haunted Mansion": 170000049, + "G: A Very Spooky Spirit": 170000050, + "G: Beware of Bouldergeist": 170000051, + "G: Bouldergeist's Daredevil Run": 170000052, + "G: Matter Splatter Mansion": 170000054 +} +locGG_table = { + "GG: Bunnies in the Wind": 170000055, + "GG: The Dirty Tricks of Major Burrows": 170000056, + "GG: Gusty Garden's Gravity Scramble": 170000057, + "GG: Major Burrows's Daredevil Run": 170000058, + "GG: The Golden Chomp": 170000060 +} +locFF_table = { + "FF: The Frozen Peak of Baron Brr": 170000061, + "FF: Freezeflame's Blistering Coore": 170000062, + "FF: Hot and Cold Collide": 170000063, + "FF: Conquring the Summit": 170000064, + "FF: Frosty Cosmic Mario race": 170000065 +} +locDDune_table = { + "DDune: Soaring on the Desert Winds": 170000067, + "DDune: Blasting through the Sand": 170000068, + "DDune: Sunbaked Sand Castle": 170000069, + "DDune: Bullet Bill on Your Back": 170000071, + "DDune: Bullet Bill on Your Back": 170000072, + "DDune: Treasure of the Pyramid": 170000073 +} +locGL_table = { + "GL: Star Bunnies on the Hunt": 170000074, + "GL: Cataquack to the skies": 170000075, + "GL: When it Rains, it Pours": 170000076, + "GL: Cosmic Mario Forest Race": 170000077, + "GL: The Bell on the Big Trees": 170000079 + } +locSS_table = { + "SS: Going After Guppy": 170000080, + "SS: Faster Than a Speedrunning Penguin": 170000081, + "SS: The Silver Stars of Sea Slide": 170000082, + "SS: Underwater Cosmic Mario Race": 170000083, + "SS: Hurry, He's Hungry": 170000085 +} +locTT_table = { + "TT: Heavy Metal Mecha Boswer": 170000086, + "TT: Mario (or Luigi) Meets Mario": 170000087, + "TT: Bouncing Down Cake Lane": 170000088, + "TT: The Flipswitch Chain": 170000089, + "TT: Fast Foes of Toy Time": 170000090 +} +locDD_table = { + "DD: The Underground Ghost Ship": 170000092, + "DD: Bubble Blastoff": 170000093, + "DD: Guppy and the Underground Lake": 170000094, + "DD: Ghost Ship Daredevil Run": 170000095, + "DD: Boo in Box": 170000097 +} +locDN_table = { + "DN: Inflitrating the Dreadnought": 170000098, + "DN: Dreanought's Colossal Cannons": 170000099, + "DN: Revenge of the Topman Tribe": 170000100, + "DN: Topman Tribe Speed Run": 170000101, + "DN: Dreadnought's Garbage Dump": 170000103 +} +locMM_table = { + "MM: The Sinking Lava Spire": 170000104, + "MM: Through the Meteor Storm": 170000105, + "MM: Fiery Dino Piranha": 170000106, + "MM: Lava Spire Daredevil Run": 170000107, + "MM Burning Tide": 170000109 +} +locHL_table = { + "SS: Rocky Road": 170000110, + "SP: A Very Sticky Situation": 170000111, + "DDR: Giant Eel Breakout": 170000112, + "BM: Bigmouth's Gold Bait": 170000113, + "SS: Choosing a Favorite Snack": 170000114, + "BB: Racing the Spooky Speedster": 170000115, + "SC: Star Bunnies in the Snow": 170000116 +} +locPC_table = { + "TT: Luigi's Purple Coins": 170000091, + "DN: Battlestation's Purple Coins": 170000102, + "MM: Red-Hot Purple Coins": 170000108, + "DD: Plunder the Purple Coins": 170000096, + "SS: Purple Coins by the Seaside": 170000084, + "GE: Purple Coin Omelet": 170000005, + "GG: Gateway's Purple coins": 170000020, + "BR: Purple Coins on the Battlerock": 170000041, + "SJ: Purple Coin Spacewalk": 170000036, + "GG: Purple Coins on the Puzzle Cube": 170000059, + "BB: Beachcombing for Purple Coins": 170000047, + "FF: Purple Coins on the Summit": 170000066, + "G: Purple Coins in the Bone Pen": 170000053, + "GL: Purple Coins in the Woods": 170000078, + "DDune: Purple Coin in the Desert": 170000070, + "HH: The Honeyhive's Purple Coins": 170000011 +} +location_table = { **locGE_table,**locHH_table, \ + **locSJ_table,**locBR_table,**locBB_table, \ + **locGG_table,**locFF_table,**locDDune_table, \ + **locGL_table,**locSS_table,**locTT_table, \ + **locDD_table,**locDN_table,**locMM_table, \ + **locPC_table,**locHL_table,**locspecialstages_table,**locbosses_table} diff --git a/worlds/smgalaxy/regions.py b/worlds/smgalaxy/regions.py new file mode 100644 index 00000000000..fd7ebc78e12 --- /dev/null +++ b/worlds/smgalaxy/regions.py @@ -0,0 +1,151 @@ +import imp +import typing +from .Options import EnablePurpleCoinStars, galaxy_options +from BaseClasses import Region, Location, RegionType, Entrance, MultiWorld +from .locations import SMGLocation, location_table,locHH_table,locGE_table, \ + locSJ_table,locBR_table,locBB_table, \ + locGG_table,locFF_table,locDD_table,locDDune_table, \ + locGL_table,locSS_table,locTT_table, \ + locDN_table,locMM_table, \ + locHL_table,locbosses_table,locspecialstages_table + +def create_regions(player: int, world: MultiWorld, self: int): + #defines the commet obserbatory + regspecialstages = Region("Menu", RegionType.Generic, "Ship", player, world) + locspecialstages_names = [name for name, id in locspecialstages_table.items()] + locspecialstages_names = [name for name, id in locHL_table.items()] + locspecialstages_names = [name for name, id in locbosses_table.items()] + regspecialstages.locations += [SMGLocation(player, loc_name, location_table[loc_name], regspecialstages) for loc_name in locspecialstages_names] + if (self.multiworld.enable_purple_coin_stars[self.player] == EnablePurpleCoinStars.option_main_game_only): + regspecialstages.locations.append(SMGLocation)(player, "GG: Gateway's Purple coins", location_table["GG: Gateway's Purple coins"], regspecialstages) + world.region.append(regspecialstages) + # defines the good egg galaxy region + regGE = Region("Good Egg", player, world) + locGE_names = [name for name, id in locGE_table.items()] + regGE.locations += [SMGLocation(player, loc_name, location_table[loc_name], regGE) for loc_name in locGE_names] + if world.enable_purple_coin_stars[player].value == 1: + regGE.locations.append(SMGLocation)(player, "GE: Purple Coin Omelet", location_table["GE: Purple Coin Omelet"], regGE) + world.regions.append(regGE) + # defines the honeyhive galaxey region + regHH = Region("Honeyhive", player, world) + locHH_names = [name for name, id in locHH_table.items()] + regHH.locations += [SMGLocation(player, loc_name, location_table[loc_name], regHH) for loc_name in locHH_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regHH.locations.append(SMGLocation)(player, "GE: The Honeyhive's Purple Coins", location_table["HH: The Honeyhive's Purple Coins"], regHH) + world.regions.append(regHH) + # defines the Space Junk galaxy region + regSJ = Region("Space Junk", player, world) + locSJ_names = [name for name, id in locSJ_table.items()] + regSJ.locations += [SMGLocation(player, loc_name, location_table[loc_name], regSJ) for loc_name in locSJ_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regHH.locations.append(SMGLocation)(player, "SJ: Purple Coin Spacewalk", location_table["SJ: Purple Coin Spacewalk"], regSJ) + world.regions.append(regSJ) + # defines the Battlerock galaxy + regBR = Region("Battlerock", player, world) + locBR_names = [name for name, id in locBR_table.items()] + regBR.locations += [SMGLocation(player, loc_name, location_table[loc_name], regBR) for loc_name in locBR_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regBR.locations.append(SMGLocation)(player, "BR: Purple Coins on the Battlerock", location_table["BR: Purple Coins on the Battlerock"], regBR) + world.regions.append(regBR) + # defines the Beach Bowl galaxy + regBB = Region("Beach Bowl", player, world) + locBB_names = [name for name, id in locBB_table.items()] + regBB.locations += [SMGLocation(player, loc_name, location_table[loc_name], regBB) for loc_name in locBB_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regBB.locations.append(SMGLocation)(player, "BB: Beachcombing for Purple Coins", location_table["BB: Beachcombing for Purple Coins"], regBB) + world.regions.append(regBB) + # define Ghostly galaxy + regG = Region("Ghostly", player, world) + locG_names = [name for name, id in locGG_table.items()] + regG.locations += [SMGLocation(player, loc_name, location_table[loc_name], regG) for loc_name in locG_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regG.locations.append(SMGLocation)(player, "G: Purple Coins in the Bone Pen", location_table["G: Purple Coins in the Bone Pen"], regG) + world.regions.append(regG) + # defines the Gusty Gardens galaxy + regGG = Region("Gusty Gardens", player, world) + locGG_names = [name for name, id in locGG_table.items()] + regGG.locations += [SMGLocation(player, loc_name, location_table[loc_name], regGG) for loc_name in locGG_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regGG.locations.append(SMGLocation)(player, "GG: Purple Coins on the Puzzle Cube", location_table["GG: Purple Coins on the Puzzle Cube"], regGG) + world.regions.append(regGG) + # defines Freezeflame galaxy + regFF = Region("Freezeflame", player, world) + locFF_names = [name for name, id in locFF_table.items()] + regFF.locations += [SMGLocation(player, loc_name, location_table[loc_name], regFF) for loc_name in locFF_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regGG.locations.append(SMGLocation)(player, "FF: Purple Coins on the Summit", location_table["FF: Purple Coins on the Summit"], regGG) + world.regions.append(regFF) + # defines DustyDune Galaxy + regDDune = Region("Dusty Dune", player, world) + locDDune_names = [name for name, id in locDDune_table.items()] + regDDune.locations += [SMGLocation(player, loc_name, location_table[loc_name], regDDune) for loc_name in locDDune_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regDDune.locations.append(SMGLocation)(player, "DDune: Purple Coins in the Desert", location_table["DDune: Purple Coin in the Desert"], regDDune) + world.regions.append(regDDune) + # defines golden leaf galaxy + regGL = Region("Gold Leaf", player, world) + locGL_names = [name for name, id in locGL_table.items()] + regGL.locations += [SMGLocation(player, loc_name, location_table[loc_name], regGL) for loc_name in locGL_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regGL.locations.append(SMGLocation)(player, "GL: Purple Coins in the Woods", location_table["GL: Purple Coins in the Woods"], regGL) + world.regions.append(regGL) + # defines the Sea slide galaxy + regSS = Region("Sea Slide", player, world) + locSS_names = [name for name, id in locSS_table.items()] + regSS.locations += [SMGLocation(player, loc_name, location_table[loc_name], regSS) for loc_name in locSS_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regSS.locations.append(SMGLocation)(player, "SS: Purple Coins by the Seaside", location_table["SS: Purple Coins by the Seaside"], regSS) + world.regions.append(regSS) + # defines toy time galaxy + regTT = Region ("Toy Time", player, world) + locTT_names = [name for name, id in locTT_table.items()] + regTT.locations += [SMGLocation(player, loc_name, location_table[loc_name], regTT) for loc_name in locTT_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regSS.locations.append(SMGLocation)(player, "TT: Luigi's Purple Coins", location_table["TT: Luigi's Purple Coins"], regSS) + world.regions.append(regTT) + # defines deep dark galaxy + regDD = Region("Deep Dark", player, world) + locDD_names = [name for name, id in locDD_table.items()] + regDD.locations += [SMGLocation(player, loc_name, location_table[loc_name], regDD) for loc_name in locDD_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regDD.locations.append(SMGLocation)(player, "DD: Plunder the Purple Coins", location_table["DD: Plunder the Purple Coins"], regDD) + world.regions.append(regDD) + # defines Dreadnaught galaxy + regDN = Region("Dreadnaught", player, world) + locDN_names = [name for name, id in locDN_table.items()] + regDN.locations += [SMGLocation (player, loc_name, location_table[loc_name], regDN) for loc_name in locDN_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regDN.locations.append(SMGLocation)(player, "DN: Battlestation's Purple Coins", location_table["DN: Battlestation's Purple Coins"], regDN) + world.regions.append(regDN) + # defines Melty Molten galaxy + regMM = Region("Melty Molten", player, world) + locMM_names = [name for name, id in locMM_table.items()] + regMM.locations += [SMGLocation (player, loc_name, location_table[loc_name], regMM) for loc_name in locMM_names] + if world.enable_purple_coin_stars[self.player].value == 1: + regMM.locations.append(SMGLocation)(player, "MM: Red-Hot Purple Coins", location_table["MM: Red-Hot Purple Coins"], regMM) + world.regions.append(regMM) + #defines the fountain + regFountain = Region("Fountain", player, world) + world.regions.append(regFountain) + #defines the kitchen + regKitchen = Region("Kitchen", player, world) + world.regions.append(regKitchen) + #defines the bedroom + regBedroom = Region("Bedroom", player, world) + world.regions.append(regBedroom) + #defines the Engine Room + regEngineRoom = Region("Engine Room", player, world) + world.regions.append(regEngineRoom) + #defines the garden + regGarden = Region("Garden", player, world) + world.regions.append(regGarden) + +def connect_regions(multiworld: MultiWorld, player: int, source: str, target: str, rule): + sourceRegion = multiworld.get_region(source, player) + targetRegion = multiworld.get_region(target, player) + + connection = Entrance(player,'', sourceRegion) + connection.access_rule = rule + + sourceRegion.exits.append(connection) + connection.connect(targetRegion) diff --git a/worlds/smgalaxy/rules.py b/worlds/smgalaxy/rules.py new file mode 100644 index 00000000000..5176ab2fe25 --- /dev/null +++ b/worlds/smgalaxy/rules.py @@ -0,0 +1,97 @@ +from sqlite3 import connect + +from worlds.AutoWorld import LogicMixin +from ..generic.Rules import add_rule +from .regions import connect_regions + +class GalaxyLogic(LogicMixin): +# these are varible states that the game uses for logic in different points. + def smg_gate_open(self, player: int): + return self.has('Grand Star Engine Room', player) + + def smg_can_finish(self, player: int): + return self.has('Power Star 60') and self.has('Grand Star Bedroom') + + def smg_purple_coins(self, player: int): + return self.has('Power Star 60') and self.has('Grand Star Bedroom') and self.has('Grand Star Engine Room', player) + + def smg_can_get_comet(self, player: int): + return self.has('Power Star 13') + + def smg_trail(self, player: int): + return self.has('Green Star 3') + + # main stage logic +def set_star_rules(world,player): + connect_regions(world, player, "Menu", "Good Egg", lambda state: True) + connect_regions(world, player, "Menu", "Honeyhive", lambda state: state.has("Power Star", player, 3)) + connect_regions(world, player, "Menu", "Fountain", lambda state: state.has("Grand Star Terrace", player)) + connect_regions(world, player, "Fountain", "Space Junk", lambda state: state.has("Power Star", player, 9)) + connect_regions(world, player, "Fountain", "Space Junk", lambda state: state.has("Power Star", player, 12)) + connect_regions(world, player, "Menu", "Kitchen", lambda state: state.has("Grand Star Fountain", player)) + connect_regions(world, player, "Kitchen", "Beach Bowl", lambda state: state.has("Power Star", player, 18)) + connect_regions(world, player, "Kitchen", "Ghostly", lambda state: state.has("Power Star", player, 20)) + connect_regions(world, player, "Menu", "Bedroom", lambda state: state.has("Grand Star Kitchen", player)) + connect_regions(world, player, "Bedroom", "Gusty Gardens", lambda state: state.has("Power Star", player, 24)) + connect_regions(world, player, "Bedroom", "Freezeflame", lambda state: state.has("Power Star", player, 26)) + connect_regions(world, player, "Menu", "Engine Room", lambda state: state.has("Grand Star Bedroom", player)) + connect_regions(world, player, "Engine Room", "Gold Leaf", lambda state: state.has("Power Star", player, 34)) + connect_regions(world, player, "Engine Room", "Toy Time", lambda state: state.has("Power Star", player, 40)) + connect_regions(world, player, "Engine Room", "Sea Slide", lambda state: state.has("Power Star", player, 36)) + connect_regions(world, player, "Menu", "Garden", lambda state: state.has("Grand Star Engine Room", player)) + connect_regions(world, player, "Garden", "Deep Dark", lambda state: state.has("Power Star", player, 46)) + connect_regions(world, player, "Garden", "Dreadnaught", lambda state: state.has("Power Star", player, 48)) + connect_regions(world, player, "Garden", "Melty Molten", lambda state: state.has("Power Star", player, 52)) + # special stages logic + add_rule(world.get_location("LDL: Surfing 101", player), lambda state: state.has("Power Star", player, 5)) + add_rule(world.get_location("FS: Painting the Planet Yellow", player), lambda state: state.has("Power Star", player, 7)) + add_rule(world.get_location("RG: Rolling in the Clouds", player), lambda state: state.has("Power Star", player, 11) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("HS: Shrinking Satellite", player), lambda state: state.has ("Power Star", player, 18) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("BUB: Through the Poison Swamp", player), lambda state: state.has ("Power Star", player, 19) and state.has("Grand Star Fountain", player)) + add_rule(world.get_location("BB: The Secret of Buoy Base", player), lambda state: state.has ("Power Star", player, 30) and state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("BB: The Floating Fortress", player), lambda state: state.has ("Power Star", player, 30) and state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("GG: Gateway's Purple coins", player), lambda state: state.has("Grand Star Engine Room", player)) + add_rule(world.get_location("BF: Kingfin's Fearsome Waters", player), lambda state: state.has("Power Star", player, 55) and state.has("Grand Star Bedroom", player)) + add_rule(world.get_location("MS: Watch Your Step", player), lambda state: state.has("Power Star", player, 50) and state.has("Grand Star Engine Room", player) and state.has("Grand Star Bedroom", player)) + add_rule(world.get_location("DDR: Giant Eel Breakout", player), lambda state: state.has("Grand Star Fountain", player)) + add_rule(world.get_location("RGT: Gizmos, Gears, and Gadgets", player), lambda state: state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player) and state.smg_trail(player)) + add_rule(world.get_location("LDT: The Galaxy's Greatest Wave", player), lambda state: state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player) and state.has("Grand Star Kitchen", player) and state.smg_trail(player)) + add_rule(world.get_location("BBT: The Electric Labyrinth", player), lambda state: state.has("Grand Star Fountain", player) and state.has("Grand Star Terrace", player) and state.has("Grand Star Kitchen", player) and state.smg_trail(player)) + add_rule(world.get_location("SS: Rocky Road", player), lambda state: state.has("Power Star", player, 7)) + add_rule(world.get_location("SP: A Very Sticky Situation", player), lambda state: state.has("Grand Star Terrace", player) and state.has("Power Star", player, 9)) + add_rule(world.get_location("BM: Bigmouth's Gold Bait", player), lambda state: state.has("Grand Star Kitchen", player) and state.has("Power Star", player, 29)) + add_rule(world.get_location("SS: Choosing a Favorite Snack", player), lambda state: state.has("Grand Star Bedroom", player) and state.has("Power Star", player, 36) and state.has("Grand Star Fountain", player)) + add_rule(world.get_location("BB: Racing the Spooky Speedster", player), lambda state: state.has("Grand Star Engine Room", player) and state.has("Grand Star Kitchen", player)) + add_rule(world.get_location("SC: Star Bunnies in the Snow", player), lambda state: state.has("Grand Star Engine Room", player) and state.has("Power Star", player, 52)) + # comet logic + add_rule(world.get_location("GE: Dino Piranha Speed Run", player), lambda state: state.has("Power Star", player, 13)) + add_rule(world.get_location("HH: Honeyhive Cosmic Mario Race", player), lambda state: state.has("Power Star", player, 13)) + add_rule(world.get_location("SJ: Pull Star Path Speed Run", player), lambda state: state.has("Power Star", player, 13)) + add_rule(world.get_location("BR: Topmanic's Dardevil Run", player), lambda state: state.smg_can_get_comet(player)) + add_rule(world.get_location("BB: Fast Foes on the Cyclone Stone", player), lambda state: state.smg_can_get_comet(player)) + # boss stage logic + add_rule(world.get_location("BJ: Megaleg's Moon", player), lambda state: state.has("Power Star", player, 8)) + add_rule(world.get_location("B: The Firery Stronghold", player), lambda state: state.has("Power Star", player, 15) and state.has("Grand Star Terrace", player)) + add_rule(world.get_location("BJ: Sinking the Airships", player), lambda state: state.has("Power Star", player, 23) and state.has("Grand Star Fountain", player)) + add_rule(world.get_location("BJ: King Kaliente's Spicy Return", player), lambda state: state.has("Power Star", player, 45) and state.has("Grand Star Engine Room", player)) + add_rule(world.get_location("B: Darkness on the Horizon", player), lambda state: state.has("Power Star", player, 33) and state.has("Grand Star Kitchen", player)) + + + # purple coin star logic + if world.EnablePurpleCoinStars[player]: + add_rule(world.get_location("DN: Battlestation's Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("MM: Red-Hot Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("TT: Luigi's Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("DD: Plunder the Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("GL: Purple Coins in the Woods", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("FF: Purple Coins on the Summit", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("SS: Purple Coins by the Seaside", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("GG: Purple Coins on the Puzzle Cube", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("G: Purple Coins in the Bone Pen", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("DDune: Purple Coin in the Desert", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("BR: Purple Coins on the Battlerock", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("GE: Purple Coin Omelet", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("HH: Honeyhive's Purple Coins", player), lambda state: state.smg_purple_coins(player)) + add_rule(world.get_location("SJ: Purple Coin Spacewalk", player), lambda state: state.smg_purple_coins(player)) + + world.completion_condition[player] = lambda state: state.smg_can_finish(player)