diff --git a/worlds/manual_mp9v3_squidy/Data.py b/worlds/manual_mp9v3_squidy/Data.py new file mode 100644 index 000000000000..3e3f26c6f346 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Data.py @@ -0,0 +1,21 @@ +import json +import os +import pkgutil + +# blatantly copied from the minecraft ap world because why not +def load_data_file(*args) -> dict: + fname = os.path.join("data", *args) + + try: + filedata = json.loads(pkgutil.get_data(__name__, fname).decode()) + except: + filedata = [] + + return filedata + +game_table = load_data_file('game.json') +item_table = load_data_file('items.json') +#progressive_item_table = load_data_file('progressive_items.json') +progressive_item_table = {} +location_table = load_data_file('locations.json') +region_table = load_data_file('regions.json') diff --git a/worlds/manual_mp9v3_squidy/Game.py b/worlds/manual_mp9v3_squidy/Game.py new file mode 100644 index 000000000000..bec964e40b47 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Game.py @@ -0,0 +1,15 @@ +from .Data import game_table + +game_name = "Manual_%s_%s" % (game_table["game"], game_table["player"]) +filler_item_name = game_table["filler_item_name"] + +# Programmatically generate starting indexes for items and locations based upon the game name and player name to aim for non-colliding indexes +starting_index = (ord(game_table["game"][:1]) * 1000000) + \ + (ord(game_table["game"][1:2]) * 100000) + \ + (ord(game_table["game"][2:3]) * 100000) + \ + (ord(game_table["game"][3:4]) * 100000) + \ + (ord(game_table["game"][4:5]) * 100000) + \ + (ord(game_table["game"][-1:]) * 100000) + \ + (ord(game_table["player"][:1]) * 10000) + \ + (ord(game_table["player"][1:2]) * 10000) + \ + (ord(game_table["player"][-1:]) * 1000) diff --git a/worlds/manual_mp9v3_squidy/Items.py b/worlds/manual_mp9v3_squidy/Items.py new file mode 100644 index 000000000000..761e7e99d5fc --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Items.py @@ -0,0 +1,63 @@ +from BaseClasses import Item +from .Data import item_table, progressive_item_table +from .Game import filler_item_name, starting_index + +###################### +# Generate item lookups +###################### + +item_id_to_name = {} +item_name_to_item = {} +advancement_item_names = set() +lastItemId = -1 + +count = starting_index + +# add the filler item to the list of items for lookup +item_table.append({ + "name": filler_item_name +}) + +# add sequential generated ids to the lists +for key, val in enumerate(item_table): + item_table[key]["id"] = count + item_table[key]["progression"] = val["progression"] if "progression" in val else False + count += 1 + +for item in item_table: + item_name = item["name"] + item_id_to_name[item["id"]] = item_name + item_name_to_item[item_name] = item + if item["progression"]: + advancement_item_names.add(item_name) + + if item["id"] != None: + lastItemId = max(lastItemId, item["id"]) + +progressive_item_list = {} + +for item in progressive_item_table: + progressiveName = progressive_item_table[item] + if progressiveName not in progressive_item_list: + progressive_item_list[progressiveName] = [] + progressive_item_list[progressiveName].append(item) + +for progressiveItemName in progressive_item_list.keys(): + lastItemId += 1 + generatedItem = {} + generatedItem["id"] = lastItemId + generatedItem["name"] = progressiveItemName + generatedItem["progression"] = item_name_to_item[progressive_item_list[progressiveItemName][0]]["progression"] + item_name_to_item[progressiveItemName] = generatedItem + item_id_to_name[lastItemId] = progressiveItemName + +item_id_to_name[None] = "__Victory__" +item_name_to_id = {name: id for id, name in item_id_to_name.items()} + +###################### +# Item classes +###################### + + +class ManualItem(Item): + game = "Manual" diff --git a/worlds/manual_mp9v3_squidy/Locations.py b/worlds/manual_mp9v3_squidy/Locations.py new file mode 100644 index 000000000000..91e4cb0fb9f9 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Locations.py @@ -0,0 +1,55 @@ +from BaseClasses import Location +from .Data import location_table +from .Game import starting_index + +###################### +# Generate location lookups +###################### + +count = starting_index + 500 # 500 each for items and locations +custom_victory_location = {} +victory_key = {} + +# add sequential generated ids to the lists +for key, _ in enumerate(location_table): + if "victory" in location_table[key] and location_table[key]["victory"]: + custom_victory_location = location_table[key] + victory_key = key # store the victory location to be removed later + + continue + + location_table[key]["id"] = count + + if not "region" in location_table[key]: + location_table[key]["region"] = "Manual" # all locations are in the same region for Manual + + count += 1 + +if victory_key: + location_table.pop(victory_key) + +# Add the game completion location, which will have the Victory item assigned to it automatically +location_table.append({ + "id": count + 1, + "name": "__Manual Game Complete__", + "region": custom_victory_location["region"] if "region" in custom_victory_location else "Manual", + "requires": custom_victory_location["requires"] if "requires" in custom_victory_location else [] +}) + +location_id_to_name = {} +location_name_to_location = {} + +for item in location_table: + location_id_to_name[item["id"]] = item["name"] + location_name_to_location[item["name"]] = item + +# location_id_to_name[None] = "__Manual Game Complete__" +location_name_to_id = {name: id for id, name in location_id_to_name.items()} + +###################### +# Location classes +###################### + + +class ManualLocation(Location): + game = "Manual" diff --git a/worlds/manual_mp9v3_squidy/Options.py b/worlds/manual_mp9v3_squidy/Options.py new file mode 100644 index 000000000000..10a5fa730c9c --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Options.py @@ -0,0 +1,15 @@ +from Options import FreeText +from BaseClasses import MultiWorld +from typing import Union + +manual_options = {} + +def is_option_enabled(world: MultiWorld, player: int, name: str) -> bool: + return get_option_value(world, player, name) > 0 + +def get_option_value(world: MultiWorld, player: int, name: str) -> Union[int, dict]: + option = getattr(world, name, None) + if option == None: + return 0 + + return option[player].value \ No newline at end of file diff --git a/worlds/manual_mp9v3_squidy/Regions.py b/worlds/manual_mp9v3_squidy/Regions.py new file mode 100644 index 000000000000..2760bc384c47 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Regions.py @@ -0,0 +1,61 @@ +from BaseClasses import Entrance, MultiWorld, Region +from .Data import region_table +from .Locations import ManualLocation +from ..AutoWorld import World + +if not region_table: + region_table = {} + +regionMap = { **region_table } +regionMap["Manual"] = { + "requires": [], + "connects_to": region_table.keys() # the Manual region connects to all user-defined regions automatically +} + +def create_regions(base: World, world: MultiWorld, player: int): + # Create regions and assign locations to each region + for region in regionMap: + # if it's an empty or unusable region, skip it + if not regionMap[region]: + continue + + exit_array = None + + if "connects_to" in regionMap[region]: + exit_array = regionMap[region]["connects_to"] + + if not exit_array: + exit_array = None + + new_region = create_region(base, world, player, region, [ + location["name"] for location in base.location_table if location["region"] == region + ], exit_array) + world.regions += [new_region] + + menu = create_region(base, world, player, "Menu", None, ["Manual"]) + world.regions += [menu] + menuConn = world.get_entrance("MenuToManual", player) + menuConn.connect(world.get_region("Manual", player)) + + # Link regions together + for region in regionMap: + if "connects_to" in regionMap[region]: + for linkedRegion in regionMap[region]["connects_to"]: + connection = world.get_entrance(getConnectionName(region, linkedRegion), player) + connection.connect(world.get_region(linkedRegion, player)) + +def create_region(base: World, world: MultiWorld, player: int, name: str, locations=None, exits=None): + ret = Region(name, player, world) + + if locations: + for location in locations: + loc_id = base.location_name_to_id.get(location, 0) + locationObj = ManualLocation(player, location, loc_id, ret) + ret.locations.append(locationObj) + if exits: + for exit in exits: + ret.exits.append(Entrance(player, getConnectionName(name, exit), ret)) + return ret + +def getConnectionName(entranceName: str, exitName: str): + return entranceName + "To" + exitName diff --git a/worlds/manual_mp9v3_squidy/Rules.py b/worlds/manual_mp9v3_squidy/Rules.py new file mode 100644 index 000000000000..46dcea95e7cf --- /dev/null +++ b/worlds/manual_mp9v3_squidy/Rules.py @@ -0,0 +1,181 @@ +from ..generic.Rules import set_rule +from .Regions import regionMap +from ..AutoWorld import World +from BaseClasses import MultiWorld +import re + + +def infix_to_postfix(expr): + prec = {"&": 2, "|": 2, "!": 3} + + stack = [] + postfix = "" + + for c in expr: + if c.isnumeric(): + postfix += c + elif c in prec: + while stack and stack[-1] != "(" and prec[c] <= prec[stack[-1]]: + postfix += stack.pop() + stack.append(c) + elif c == "(": + stack.append(c) + elif c == ")": + while stack and stack[-1] != "(": + postfix += stack.pop() + stack.pop() + while stack: + postfix += stack.pop() + + return postfix + + +def evaluate_postfix(expr, location): + stack = [] + for c in expr: + if c == "0": + stack.append(False) + elif c == "1": + stack.append(True) + elif c == "&": + op2 = stack.pop() + op1 = stack.pop() + stack.append(op1 and op2) + elif c == "|": + op2 = stack.pop() + op1 = stack.pop() + stack.append(op1 or op2) + elif c == "!": + op = stack.pop() + stack.append(not op) + + if len(stack) != 1: + raise KeyError("Invalid logic format for location {}.".format(location["name"])) + return stack.pop() + + +def set_rules(base: World, world: MultiWorld, player: int): + # this is only called when the area (think, location or region) has a "requires" field that is a string + def checkRequireStringForArea(state, area): + # parse user written statement into list of each item + reqires_raw = re.split('(\AND|\)|\(|OR|\|)', area["requires"]) + remove_spaces = [x.strip() for x in reqires_raw] + remove_empty = [x for x in remove_spaces if x != ''] + requires_list = [x for x in remove_empty if x != '|'] + + for i, item in enumerate(requires_list): + if item.lower() == "or": + requires_list[i] = "|" + elif item.lower() == "and": + requires_list[i] = "&" + elif item == ")" or item == "(": + continue + else: + item_parts = item.split(":") + item_name = item + item_count = 1 + + if len(item_parts) > 1: + item_name = item_parts[0] + item_count = int(item_parts[1]) + + if state.has(item_name, player, item_count): + requires_list[i] = "1" + else: + requires_list[i] = "0" + + requires_string = infix_to_postfix("".join(requires_list)) + return (evaluate_postfix(requires_string, area)) + + # this is only called when the area (think, location or region) has a "requires" field that is a dict + def checkRequireDictForArea(state, area): + canAccess = True + + for item in area["requires"]: + # if the require entry is an object with "or" or a list of items, treat it as a standalone require of its own + if (isinstance(item, dict) and "or" in item and isinstance(item["or"], list)) or (isinstance(item, list)): + canAccessOr = True + or_items = item + + if isinstance(item, dict): + or_items = item["or"] + + for or_item in or_items: + or_item_parts = or_item.split(":") + or_item_name = or_item + or_item_count = 1 + + if len(or_item_parts) > 1: + or_item_name = or_item_parts[0] + or_item_count = int(or_item_parts[1]) + + if not state.has(or_item_name, player, or_item_count): + canAccessOr = False + + if canAccessOr: + canAccess = True + break + else: + item_parts = item.split(":") + item_name = item + item_count = 1 + + if len(item_parts) > 1: + item_name = item_parts[0] + item_count = int(item_parts[1]) + + if not state.has(item_name, player, item_count): + canAccess = False + + return canAccess + + # handle any type of checking needed, then ferry the check off to a dedicated method for that check + def fullLocationOrRegionCheck(state, area): + # if it's not a usable object of some sort, default to true + if not area: + return True + + if isinstance(area["requires"], str): + return checkRequireStringForArea(state, area) + else: # item access is in dict form + return checkRequireDictForArea(state, area) + + # Region access rules + for region in regionMap.keys(): + if region != "Menu": + for exitRegion in world.get_region(region, player).exits: + def fullRegionCheck(state, region=regionMap[region]): + return fullLocationOrRegionCheck(state, region) + + set_rule(world.get_entrance(exitRegion.name, player), fullRegionCheck) + + # Location access rules + for location in base.location_table: + locFromWorld = world.get_location(location["name"], player) + + locationRegion = regionMap[location["region"]] if "region" in location else None + + if "requires" in location: # Location has requires, check them alongside the region requires + def checkBothLocationAndRegion(state, location=location, region=locationRegion): + locationCheck = fullLocationOrRegionCheck(state, location) + regionCheck = True # default to true unless there's a region with requires + + if region: + regionCheck = fullLocationOrRegionCheck(state, region) + + return locationCheck and regionCheck + + set_rule(locFromWorld, checkBothLocationAndRegion) + elif "region" in location: # Only region access required, check the location's region's requires + def fullRegionCheck(state, region=locationRegion): + return fullLocationOrRegionCheck(state, region) + + set_rule(locFromWorld, fullRegionCheck) + else: # No location region and no location requires? It's accessible. + def allRegionsAccessible(state): + return True + + set_rule(locFromWorld, allRegionsAccessible) + + # Victory requirement + world.completion_condition[player] = lambda state: state.has("__Victory__", player) diff --git a/worlds/manual_mp9v3_squidy/__init__.py b/worlds/manual_mp9v3_squidy/__init__.py new file mode 100644 index 000000000000..21ae8be85abb --- /dev/null +++ b/worlds/manual_mp9v3_squidy/__init__.py @@ -0,0 +1,128 @@ +from .Data import item_table, progressive_item_table, location_table +from .Game import game_name, filler_item_name +from .Locations import location_id_to_name, location_name_to_id, location_name_to_location +from .Items import item_id_to_name, item_name_to_id, item_name_to_item, advancement_item_names + +from .Regions import create_regions +from .Items import ManualItem +from .Rules import set_rules +from .Options import get_option_value, manual_options + +from BaseClasses import ItemClassification, Tutorial, Item +from ..AutoWorld import World, WebWorld + + +class ManualWeb(WebWorld): + tutorials = [Tutorial( + "Multiworld Setup Guide", + "A guide to setting up manual game integration for Archipelago multiworld games.", + "English", + "setup_en.md", + "setup/en", + ["Fuzzy"] + )] + + +class ManualWorld(World): + """ + Manual games allow you to set custom check locations and custom item names that will be rolled into a multiworld. + This allows any variety of game -- PC, console, board games, Microsoft Word memes... really anything -- to be part of a multiworld randomizer. + The key component to including these games is some level of manual restriction. Since the items are not actually withheld from the player, + the player must manually refrain from using these gathered items until the tracker shows that they have been acquired or sent. + """ + game: str = game_name + web = ManualWeb() + + option_definitions = manual_options + data_version = 2 + required_client_version = (0, 3, 4) + + # These properties are set from the imports of the same name above. + item_table = item_table + progressive_item_table = progressive_item_table + item_id_to_name = item_id_to_name + item_name_to_id = item_name_to_id + item_name_to_item = item_name_to_item + advancement_item_names = advancement_item_names + location_table = location_table + location_id_to_name = location_id_to_name + location_name_to_id = location_name_to_id + location_name_to_location = location_name_to_location + + def pre_fill(self): + location_game_complete = self.multiworld.get_location("__Manual Game Complete__", self.player) + location_game_complete.address = None + + location_game_complete.place_locked_item( + ManualItem("__Victory__", ItemClassification.progression, None, player=self.player)) + + def generate_basic(self): + # Generate item pool + pool = [] + configured_item_names = self.item_id_to_name.copy() + + for name in configured_item_names.values(): + if name == "__Victory__": + continue + + # If it's the filler item, skip it until we know if we need any extra items + if name == filler_item_name: + continue + + # if (hasattr(self.multiworld, "progressive_items") and len(self.multiworld.progressive_items) > 0): + # shouldUseProgressive = (self.multiworld.progressive_items[self.player].value); + + # if shouldUseProgressive and name in self.progressive_item_table: + # name = self.progressive_item_table[name] + + item = self.item_name_to_item[name] + item_count = 1 + + if "count" in item: + item_count = int(item["count"]) + + for i in range(item_count): + new_item = self.create_item(name) + pool.append(new_item) + + + extras = len(location_table) - len(pool) - 1 # subtracting 1 because of Victory; seems right + + if extras > 0: + for i in range(0, extras): + extra_item = self.create_item(filler_item_name) + pool.append(extra_item) + + self.multiworld.itempool += pool + + def create_item(self, name: str) -> Item: + item = self.item_name_to_item[name] + classification = ItemClassification.filler + + if "trap" in item and item["trap"]: + classification = ItemClassification.trap + + if "useful" in item and item["useful"]: + classification = ItemClassification.useful + + if "progression" in item and item["progression"]: + classification = ItemClassification.progression + + return ManualItem(name, classification, + self.item_name_to_id[name], player=self.player) + + def set_rules(self): + set_rules(self, self.multiworld, self.player) + + def create_regions(self): + create_regions(self, self.multiworld, self.player) + + def get_pre_fill_items(self): + return [] + + def fill_slot_data(self): + # return { + # "DeathLink": bool(self.multiworld.death_link[self.player].value) + # } + + pass diff --git a/worlds/manual_mp9v3_squidy/data/game.json b/worlds/manual_mp9v3_squidy/data/game.json new file mode 100644 index 000000000000..e1d961bfbb40 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/data/game.json @@ -0,0 +1,6 @@ +{ + "game": "mp9v3", + "player": "squidy", + + "filler_item_name": "Nothing" +} \ No newline at end of file diff --git a/worlds/manual_mp9v3_squidy/data/items.json b/worlds/manual_mp9v3_squidy/data/items.json new file mode 100644 index 000000000000..2827babf104e --- /dev/null +++ b/worlds/manual_mp9v3_squidy/data/items.json @@ -0,0 +1,28 @@ +[ + { "name": "Bomb-omb Factory", "progression": true }, + { "name": "Boos Horror Castle", "progression": true }, + { "name": "Blooper Beach", "progression": true }, + { "name": "Magma Mine", "progression": true }, + { "name": "Bowser Station", "progression": true }, + { "name": "DK Jungle Ruins", "progression": true }, + { "name": "Step it up", "progression": true }, + { "name": "Garden Battle", "progression": true }, + { "name": "Choice Challenge", "progression": true }, + { "name": "High Rollers", "progression": true }, + { "name": "Time Attack", "progression": true }, + { "name": "Castle Clearout", "progression": true }, + { "name": "Shell Soccer", "progression": true }, + { "name": "Extra - Goomba Bowling", "progression": true }, + { "name": "Free For All Mini Game selector", "progression": true }, + { "name": "1 vs rivals mini game slector", "progression": true }, + { "name": "Boss selector", "progression": true }, + { "name": "slow dice block", "progression": true }, + { "name": "1-10 dice block", "progression": true }, + { "name": "0-1 dice block", "progression": true }, + { "name": "1-3 dice block", "progression": false }, + { "name": "4-6 dice block", "progression": false }, + { "name": "Trap: must use regular dice block next turn", "progression": false, "count": 10 }, + { "name": "Trap: HYDRATION", "count": 5 }, + { "name": "Trap: Can't use buttons during the next mini-game", "count": 3 } +] + diff --git a/worlds/manual_mp9v3_squidy/data/locations.json b/worlds/manual_mp9v3_squidy/data/locations.json new file mode 100644 index 000000000000..b133ce731871 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/data/locations.json @@ -0,0 +1,257 @@ +[ + { "name": "Toad Road - climb to the top of the vine (lucky event)", "requires": ["slow dice block"] }, + { "name": "Toad Road - miniboss" }, + { "name": "Toad Road - make it over the bridge gap", "requires": ["1-10 dice block"] }, + { "name": "Toad Road - reach top of 9 island", "requires": ["1-10 dice block"] }, + { "name": "Toad Road - almost there", "requires": ["1-10 dice block"]}, + { "name": "Toad Road - boss", "requires": ["1-10 dice block"] }, + { "name": "Toad Road - victory", "requires": ["1-10 dice block"] }, + { "name": "Bomb-omb Factory - miniboss", "requires": ["Bomb-omb Factory"] }, + { "name": "Bomb-omb Factory - Have bomb explode while your captain", + "requires": [ + "Bomb-omb Factory", "4-6 dice block", + {"or": ["Bomb-omb Factory", "1-10 dice block"] } + ] + }, + { "name": "Bomb-omb Factory - pipe(lucky space event)", "requires": ["Bomb-omb Factory"] }, + { "name": "Bomb-omb Factory - almost there", "requires": ["Bomb-omb Factory"] }, + { "name": "Bomb-omb Factory - boss", "requires": ["Bomb-omb Factory"] }, + { "name": "Bomb-omb Factory - victory", "requires": ["Bomb-omb Factory"] }, + { "name": "Bomb-omb Factory - captain event", "requires": ["Bomb-omb Factory"] }, + { "name": "Boos Horror Castle - get caught by boo as captain", + "requires": [ + "1-3 dice block", + {"or": ["0-1 dice block"] }, + {"or": ["slow dice block"] } + ] +}, + { "name": "Boos Horror Castle - miniboss", "requires": ["Boos Horror Castle"] }, + { "name": "Boos Horror Castle - catch rat", "requires": ["Boos Horror Castle"] }, + { "name": "Boos Horror Castle - almost there", "requires": ["Boos Horror Castle"] }, + { "name": "Boos Horror Castle - boss", "requires": ["Boos Horror Castle"] }, + { "name": "Boos Horror Castle - victory", "requires": ["Boos Horror Castle"] }, + { "name": "Blooper Beach - miniboss", "requires": ["Blooper Beach"] }, + { "name": "Blooper Beach - get sucked up by Blooper(unlucky space event)", "requires": ["Blooper Beach", "slow dice block"] }, + { "name": "Blooper Beach - almost there", "requires": ["Blooper Beach"] }, + { + "name": "Blooper Beach - go to star island", + "requires": ["Blooper Beach", "slow dice block"] + }, + { "name": "Blooper Beach - boss", "requires": ["Blooper Beach"] }, + { "name": "Blooper Beach - victory", "requires": ["Blooper Beach"] }, + { "name": "Blooper Beach - get dolphin mini stars", "requires": ["Blooper Beach"] }, + { "name": "Blooper Beach - recover 10 mini-stars (captain event)", "requires": ["Blooper Beach"] }, + { "name": "Blooper Beach - recover 15 mini-stars (captain event)", "requires": ["Blooper Beach"] }, + { "name": "Magma Mine - miniboss", "requires": ["Magma Mine"] }, + { "name": "Magma Mine - get burnt by the lava as captian", "requires": ["Magma Mine"] }, + { "name": "Magma Mine - dont fall (captain event)", "requires": ["Magma Mine"] }, + { "name": "Magma Mine - almost there", "requires": ["Magma Mine"] }, + { "name": "Magma Mine - boss", "requires": ["Magma Mine"] }, + { "name": "Magma Mine - victory", "requires": ["Magma Mine"] }, + { "name": "Bowser Station - Captain Event 1", "requires": ["Bowser Station"] }, + { "name": "Bowers Station - Have 20 stars in the jackpot machine", "requires": ["Bowser Station"] }, + { "name": "Bowser Station - win a jackpot minigame", "requires": ["Bowser Station"] }, + { "name": "Bowser Station - miniboss", "requires": ["Bowser Station"] }, + { "name": "Bowser Station - bingo", "requires": ["Bowser Station", "1-10 dice block"]}, + { "name": "Bowser Station - almost there", "requires": ["Bowser Station", "1-10 dice block"] }, + { "name": "Bowser Station - Captain Event 3", "requires": ["Bowser Station", "1-10 dice block"] }, + { "name": "Bowser Station - boss", "requires": ["Bowser Station", "1-10 dice block"] }, + { "name": "Bowser Station - victory", "victory": true, "requires": ["Bowser Station", "1-10 dice block"] }, + { "name": "DK Jungle Ruins - land on a dk space", "requires": ["DK Jungle Ruins", "slow dice block"] }, + { "name": "DK Jungle Ruins - barrel shuffle diddy only (captian event)", "requires": ["DK Jungle Ruins"] }, + { "name": "DK Jungle Ruins - DK hands launcher(lucky event)", "requires": ["DK Jungle Ruins", "slow dice block"] }, + { "name": "DK Jungle Ruins - miniboss", "requires": ["DK Jungle Ruins"] }, + { "name": "DK Jungle Ruins - barrel shuffle both (captian event)", "requires": ["DK Jungle Ruins"] }, + { "name": "DK Jungle Ruins - almost there", "requires": ["DK Jungle Ruins"] }, + { "name": "DK Jungle Ruins - boss", "requires": ["DK Jungle Ruins"] }, + { "name": "DK Jungle Ruins - victory", "requires": ["DK Jungle Ruins"] }, + { "name": "DK Jungle Ruins - Victory with over 100 bannanas", "requires": ["DK Jungle Ruins"] }, + { "name": "land on 3 event spaces", "requires": ["slow dice block"] }, + { "name": "land on a back space", "requires": ["slow dice block"] }, + { "name": "land on a dash space", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins", "slow dice block"] }, + {"or": ["Magma Mine", "slow dice block"] }, + {"or": ["Blooper Beach", "slow dice block"] }, + {"or": ["1-10 dice block", "slow dice block"] }, + {"or": ["Boos Horror Castle", "slow dice block"] } + ] + }, + { "name": "land on play a 1 vs rivals game", "requires": ["slow dice block"] }, + { "name": "land on a unlucky space", "requires": ["slow dice block"] }, + { "name": "land on a boswer jr. space", "requires": ["slow dice block"] }, + { "name": "finish with over 50 mini stars", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins"] }, + {"or": ["Magma Mine"] }, + {"or": ["Blooper Beach"] }, + {"or": ["1-10 dice block"] }, + {"or": ["Boos Horror Castle"] } + ] + }, + { "name": "roll a 0 ", "requires": ["0-1 dice block"] }, + { "name": "roll a 10", "requires": ["1-10 dice block"] }, + { "name": "land on 3 lucky spaces", "requires": ["slow dice block"] }, + { "name": "win the mini game bonus star", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins"] }, + {"or": ["Magma Mine"] }, + {"or": ["Blooper Beach"] }, + {"or": ["1-10 dice block"] }, + {"or": ["Boos Horror Castle"] } + ] +}, + { "name": "win the slow bonus star", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins"] }, + {"or": ["Magma Mine"] }, + {"or": ["Blooper Beach"] }, + {"or": ["1-10 dice block"] }, + {"or": ["Boos Horror Castle"] } + ] +}, + { "name": "win the spin bonus star", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins"] }, + {"or": ["Magma Mine"] }, + {"or": ["Blooper Beach"] }, + {"or": ["1-10 dice block"] }, + {"or": ["Boos Horror Castle"] } + ] + }, + { "name": "win the far bonus star", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins"] }, + {"or": ["Magma Mine"] }, + {"or": ["Blooper Beach"] }, + {"or": ["1-10 dice block"] }, + {"or": ["Boos Horror Castle"] } + ] + }, + { "name": "win the minus bonus star", + "requires": [ + "Bomb-omb Factory", + {"or": ["DK Jungle Ruins"] }, + {"or": ["Magma Mine"] }, + {"or": ["Blooper Beach"] }, + {"or": ["1-10 dice block"] }, + {"or": ["Boos Horror Castle"] } + ] + }, + { "name": "win a game with over 100 mini stars", "requires": ["Blooper Beach"] }, + { "name": "win a reverse Mini-Game Play", "requires": ["slow dice block"] }, + { "name": "Use 5 dice blocks on one game", + "requires": [ + "slow dice block", + {"or": ["0-1 dice block"] }, + {"or": ["1-3 dice block"] }, + {"or": ["1-10 dice block"] }, + {"or": ["4-6 dice block"] } + + ] + }, + { "name": "use every dice block type", "requires": ["slow dice block", "0-1 dice block", "1-10 dice block", "1-3 dice block", "4-6 dice block", "0-1 dice block"] }, + { "name": "Play Mini-Game Buddy Bounce", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Logger Heads", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Pinball Fall", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Launch Break", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Goomba Village", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Speeding Bullets", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Pianta Pool", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Chain Event", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Skyjinks", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Skipping Class", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Mecha Choice", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Jigsaw Jumble", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Growing up", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Upward Mobility", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Ring Leader", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Smash Compactor", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Peak Precision", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game 10 to Win", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Tuber Tug", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Card Smarts", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Toad and Go seek", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Polar Extreme", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Goomba Bowling", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Tumble Temple", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Twist Ending", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Manor of Escape", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Player conveyor", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Ballisitc Beach", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Bumper Bubbles", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Finger Painting", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Bomb Barge", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Dont Look", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Snow Go", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Piranha Patch", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Plunder Ground", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Pier Pressure", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Ballistics", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Pit or Platter", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Thwomper Room", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Urn it", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Goomba Spotting", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Magma Mayhem", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Pizza Me Mario", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Fungi Frenzy", "requires": ["Free For All Mini Game selector"] }, + { "name": "Play Mini-Game Ruins Rumble", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Hazard Hold", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Line in the Sand", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Block and Roll", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Tackle Takedown", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Weird Wheels", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Spike-n-Span", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Hole hogs", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Pix Fix", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Mob Sleds", "requires": ["1 vs rivals mini game slector"] }, + { "name": "Play Mini-Game Mecha March", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Bowser Pop", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Double Pounder", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Zoom Room", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Cage Match", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Crossfire Caverns", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Bumper Sparks", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Sand Trap", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Pair of Aces", "requires": ["slow dice block"] }, + { "name": "Play Mini-Game Pedal to the medel", "requires": ["slow dice block"] }, + { "name": "Defeat Lakitu", "requires": ["Boss selector"] }, + { "name": "Defeat Whomp", "requires": ["Boss selector"] }, + { "name": "Defeat Dry bones", "requires": ["Boss selector"] }, + { "name": "Defeat Cheep Cheep", "requires": ["Boss selector"] }, + { "name": "Defeat Spike", "requires": ["Boss selector"] }, + { "name": "Defeat Bowser Jr", "requires": ["Bowser Station"] }, + { "name": "Defeat Wiggler", "requires": ["Boss selector"] }, + { "name": "Defeat King Bomb-omb", "requires": ["Boss selector"] }, + { "name": "Defeat King Boo", "requires": ["Boss selector"] }, + { "name": "Defeat Blooper Brrage", "requires": ["Boss selector"] }, + { "name": "Defeat Chain Chomp", "requires": ["Boss selector"] }, + { "name": "Defeat Bowser", "requires": ["1-10 dice block", "Bowser Station"] }, + { "name": "Castle Clearout - Reach level 5", "requires": ["Castle Clearout"] }, + { "name": "Castle Clearout - Reach level 10", "requires": ["Castle Clearout"] }, + { "name": "Shell Soccer - Victory", "requires": ["Shell Soccer"] }, + { "name": "Shell Soccer - Your team scores 3 points", "requires": ["Shell Soccer"] }, + { "name": "Extra - Goomba Bowling - Victory", "requires": ["Extra - Goomba Bowling"] }, + { "name": "Extra - Goomba Bowling - score 10 points in 1 frame", "requires": ["Extra - Goomba Bowling"] }, + { "name": "Step it up - 3 wins victory", "requires": ["Step it up"] }, + { "name": "Step it up - 5 wins victory", "requires": ["Step it up"] }, + { "name": "Step it up - 7 wins victory", "requires": ["Step it up"] }, + { "name": "Choice Challenge - victory", "requires": ["Choice Challenge"] }, + { "name": "Choice Challenge - Pick mini-game assigned to up", "requires": ["Choice Challenge"] }, + { "name": "Choice Challenge - Pick mini-game assigned to down", "requires": ["Choice Challenge"] }, + { "name": "Choice Challenge - Pick mini-game assigned to right", "requires": ["Choice Challenge"] }, + { "name": "Choice Challenge - Pick mini-game assigned to left", "requires": ["Choice Challenge"] }, + { "name": "Choice Challenge - Pick mini-game assigned to A", "requires": ["Choice Challenge"] }, + { "name": "Time Attack - Victory", "requires": ["Time Attack"] }, + { "name": "Garden Battle - Victory", "requires": ["Garden Battle"] }, + { "name": "Garden Battle - Pick the smallest plant", "requires": ["Garden Battle"] }, + { "name": "Garden Battle - Pick the largest plant", "requires": ["Garden Battle"] }, + { "name": "High Rollers - Victory", "requires": ["High Rollers"] }, + { "name": "High Rollers - Use the pow block", "requires": ["High Rollers"] } +] \ No newline at end of file diff --git a/worlds/manual_mp9v3_squidy/data/regions.json b/worlds/manual_mp9v3_squidy/data/regions.json new file mode 100644 index 000000000000..55da9e4ca0a9 --- /dev/null +++ b/worlds/manual_mp9v3_squidy/data/regions.json @@ -0,0 +1,87 @@ +{ + "Toad-Road Start": { + "connects_to": [ + ] + }, + "Toad-Road Main": { + "connects_to": [], + "requires": ["1-10 dice block"] + }, + "Bomb-omb Factory":{ + "connects_to": [ + ], + "requires": ["Bomb-omb Factory"] + }, + "Boos Horror Castle":{ + "connects_to": [ + ], + "requires": ["Boos Horror Castle"] + }, + "Blooper Beach": { + "connects_to": [ + ], + "requires": ["Blooper Beach"] + }, + "Magma Mine": { + "connects_to": [ + ], + "requires": ["Magma Mine"] + }, + "Bowser Station": { + "connects_to": [ + ], + "requires": ["Bowser Station"] + }, + "DK Jungle Ruins": { + "connects_to": [], + "requires": ["DK Jungle Ruins"] + }, + "Step it up": { + "connects_to": [], + "requires": ["Step it up"] + }, + "Garden Battle": { + "connects_to": [], + "requires": ["Garden Battle"] + }, + "Choice Challenge": { + "connects_to": [], + "requires": ["Choice Challenge"] + }, + "High Rollers": { + "connects_to": [], + "requires": ["High Rollers"] + }, + "Time Attack": { + "connects_to": [], + "requires": ["Time Attack"] + }, + "Castle Clearout": { + "connects_to": [], + "requires": ["Castle Clearout"] + }, + "Shell Soccer": { + "connects_to": [], + "requires": ["Shell Soccer"] + }, + "Extra - Goomba Bowling": { + "connects_to": [], + "requires": ["Extra - Goomba Bowling"] + }, + "Free for all mini games": { + "connects_to": [], + "requires": ["Free For All Mini Game selector"] + }, + "1 vs rivals mini games": { + "connects_to": [], + "requires": ["1 vs rivals mini game slector"] + }, + "Bosses": { + "connects_to": [], + "requires": ["Boss selector"] + }, + "Specific spaces": { + "connects_to": [], + "requires": ["slow dice block"] + } +} \ No newline at end of file