Bomb Rush Cyberfunk: Implement new game (#2925)

Adds Team Reptile's Bomb Rush Cyberfunk as a new game.
This commit is contained in:
Trevor L 2024-05-17 04:13:40 -06:00 committed by GitHub
parent 2447be92d8
commit 68323b46a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 3296 additions and 0 deletions

View File

@ -66,6 +66,7 @@ Currently, the following games are supported:
* A Short Hike
* Yoshi's Island
* Mario & Luigi: Superstar Saga
* Bomb Rush Cyberfunk
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

View File

@ -25,6 +25,9 @@
# Blasphemous
/worlds/blasphemous/ @TRPG0
# Bomb Rush Cyberfunk
/worlds/bomb_rush_cyberfunk/ @TRPG0
# Bumper Stickers
/worlds/bumpstik/ @FelicitusNeko

View File

@ -0,0 +1,553 @@
from typing import TypedDict, List, Dict, Set
from enum import Enum
class BRCType(Enum):
Music = 0
GraffitiM = 1
GraffitiL = 2
GraffitiXL = 3
Skateboard = 4
InlineSkates = 5
BMX = 6
Character = 7
Outfit = 8
REP = 9
Camera = 10
class ItemDict(TypedDict, total=False):
name: str
count: int
type: BRCType
base_id = 2308000
item_table: List[ItemDict] = [
# Music
{'name': "Music (GET ENUF)",
'type': BRCType.Music},
{'name': "Music (Chuckin Up)",
'type': BRCType.Music},
{'name': "Music (Spectres)",
'type': BRCType.Music},
{'name': "Music (You Can Say Hi)",
'type': BRCType.Music},
{'name': "Music (JACK DA FUNK)",
'type': BRCType.Music},
{'name': "Music (Feel The Funk (Computer Love))",
'type': BRCType.Music},
{'name': "Music (Big City Life)",
'type': BRCType.Music},
{'name': "Music (I Wanna Kno)",
'type': BRCType.Music},
{'name': "Music (Plume)",
'type': BRCType.Music},
{'name': "Music (Two Days Off)",
'type': BRCType.Music},
{'name': "Music (Scraped On The Way Out)",
'type': BRCType.Music},
{'name': "Music (Last Hoorah)",
'type': BRCType.Music},
{'name': "Music (State of Mind)",
'type': BRCType.Music},
{'name': "Music (AGUA)",
'type': BRCType.Music},
{'name': "Music (Condensed milk)",
'type': BRCType.Music},
{'name': "Music (Light Switch)",
'type': BRCType.Music},
{'name': "Music (Hair Dun Nails Dun)",
'type': BRCType.Music},
{'name': "Music (Precious Thing)",
'type': BRCType.Music},
{'name': "Music (Next To Me)",
'type': BRCType.Music},
{'name': "Music (Refuse)",
'type': BRCType.Music},
{'name': "Music (Iridium)",
'type': BRCType.Music},
{'name': "Music (Funk Express)",
'type': BRCType.Music},
{'name': "Music (In The Pocket)",
'type': BRCType.Music},
{'name': "Music (Bounce Upon A Time)",
'type': BRCType.Music},
{'name': "Music (hwbouths)",
'type': BRCType.Music},
{'name': "Music (Morning Glow)",
'type': BRCType.Music},
{'name': "Music (Chromebies)",
'type': BRCType.Music},
{'name': "Music (watchyaback!)",
'type': BRCType.Music},
{'name': "Music (Anime Break)",
'type': BRCType.Music},
{'name': "Music (DA PEOPLE)",
'type': BRCType.Music},
{'name': "Music (Trinitron)",
'type': BRCType.Music},
{'name': "Music (Operator)",
'type': BRCType.Music},
{'name': "Music (Sunshine Popping Mixtape)",
'type': BRCType.Music},
{'name': "Music (House Cats Mixtape)",
'type': BRCType.Music},
{'name': "Music (Breaking Machine Mixtape)",
'type': BRCType.Music},
{'name': "Music (Beastmode Hip Hop Mixtape)",
'type': BRCType.Music},
# Graffiti
{'name': "Graffiti (M - OVERWHELMME)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - QUICK BING)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - BLOCKY)",
'type': BRCType.GraffitiM},
#{'name': "Graffiti (M - Flow)",
# 'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Pora)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Teddy 4)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - BOMB BEATS)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - SPRAYTANICPANIC!)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - SHOGUN)",
'type': BRCType.GraffitiM},
#{'name': "Graffiti (M - EVIL DARUMA)",
# 'type': BRCType.GraffitiM},
{'name': "Graffiti (M - TeleBinge)",
'type': BRCType.GraffitiM},
#{'name': "Graffiti (M - All Screws Loose)",
# 'type': BRCType.GraffitiM},
{'name': "Graffiti (M - 0m33)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Vom'B)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Street classic)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Thick Candy)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - colorBOMB)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Zona Leste)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Stacked Symbols)",
'type': BRCType.GraffitiM},
#{'name': "Graffiti (M - Constellation Circle)",
# 'type': BRCType.GraffitiM},
{'name': "Graffiti (M - B-boy Love)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - Devil 68)",
'type': BRCType.GraffitiM},
{'name': "Graffiti (M - pico pow)",
'type': BRCType.GraffitiM},
#{'name': "Graffiti (M - 8 MINUTES OF LEAN MEAN)",
# 'type': BRCType.GraffitiM},
{'name': "Graffiti (L - WHOLE SIXER)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - INFINITY)",
'type': BRCType.GraffitiL},
#{'name': "Graffiti (L - Dynamo)",
# 'type': BRCType.GraffitiL},
{'name': "Graffiti (L - VoodooBoy)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Fang It Up!)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - FREAKS)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Graffo Le Fou)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Lauder)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - SpawningSeason)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Moai Marathon)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Tius)",
'type': BRCType.GraffitiL},
#{'name': "Graffiti (L - KANI-BOZU)",
# 'type': BRCType.GraffitiL},
{'name': "Graffiti (L - NOISY NINJA)",
'type': BRCType.GraffitiL},
#{'name': "Graffiti (L - Dinner On The Court)",
# 'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Campaign Trail)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - skate or di3)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Jd Vila Formosa)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Messenger Mural)",
'type': BRCType.GraffitiL},
#{'name': "Graffiti (L - Solstice Script)",
# 'type': BRCType.GraffitiL},
{'name': "Graffiti (L - RECORD.HEAD)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - Boom)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - wild rush)",
'type': BRCType.GraffitiL},
{'name': "Graffiti (L - buttercup)",
'type': BRCType.GraffitiL},
#{'name': "Graffiti (L - DIGITAL BLOCKBUSTER)",
# 'type': BRCType.GraffitiL},
{'name': "Graffiti (XL - Gold Rush)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - WILD STRUXXA)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - VIBRATIONS)",
'type': BRCType.GraffitiXL},
#{'name': "Graffiti (XL - Bevel)",
# 'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - SECOND SIGHT)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Bomb Croc)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - FATE)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Web Spitter)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - MOTORCYCLE GANG)",
'type': BRCType.GraffitiXL},
#{'name': "Graffiti (XL - CYBER TENGU)",
# 'type': BRCType.GraffitiXL},
#{'name': "Graffiti (XL - Don't Screw Around)",
# 'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Deep Dive)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - MegaHood)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Gamex UPA ABL)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - BiGSHiNYBoMB)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Bomb Burner)",
'type': BRCType.GraffitiXL},
#{'name': "Graffiti (XL - Astrological Augury)",
# 'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Pirate's Life 4 Me)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Bombing by FireMan)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - end 2 end)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - Raver Funk)",
'type': BRCType.GraffitiXL},
{'name': "Graffiti (XL - headphones on Helmet on)",
'type': BRCType.GraffitiXL},
#{'name': "Graffiti (XL - HIGH TECH WS)",
# 'type': BRCType.GraffitiXL},
# Skateboards
{'name': "Skateboard (Devon)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Terrence)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Maceo)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Lazer Accuracy)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Death Boogie)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Sylk)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Taiga)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Just Swell)",
'type': BRCType.Skateboard},
{'name': "Skateboard (Mantra)",
'type': BRCType.Skateboard},
# Inline Skates
{'name': "Inline Skates (Glaciers)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Sweet Royale)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Strawberry Missiles)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Ice Cold Killers)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Red Industry)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Mech Adversary)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Orange Blasters)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (ck)",
'type': BRCType.InlineSkates},
{'name': "Inline Skates (Sharpshooters)",
'type': BRCType.InlineSkates},
# BMX
{'name': "BMX (Mr. Taupe)",
'type': BRCType.BMX},
{'name': "BMX (Gum)",
'type': BRCType.BMX},
{'name': "BMX (Steel Wheeler)",
'type': BRCType.BMX},
{'name': "BMX (oyo)",
'type': BRCType.BMX},
{'name': "BMX (Rigid No.6)",
'type': BRCType.BMX},
{'name': "BMX (Ceremony)",
'type': BRCType.BMX},
{'name': "BMX (XXX)",
'type': BRCType.BMX},
{'name': "BMX (Terrazza)",
'type': BRCType.BMX},
{'name': "BMX (Dedication)",
'type': BRCType.BMX},
# Outfits
{'name': "Outfit (Red - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Red - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Tryce - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Tryce - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Bel - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Bel - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Vinyl - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Vinyl - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Solace - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Solace - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Felix - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Felix - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Rave - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Rave - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Mesh - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Mesh - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Shine - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Shine - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Rise - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Rise - Winter)",
'type': BRCType.Outfit},
{'name': "Outfit (Coil - Autumn)",
'type': BRCType.Outfit},
{'name': "Outfit (Coil - Winter)",
'type': BRCType.Outfit},
# Characters
{'name': "Tryce",
'type': BRCType.Character},
{'name': "Bel",
'type': BRCType.Character},
{'name': "Vinyl",
'type': BRCType.Character},
{'name': "Solace",
'type': BRCType.Character},
{'name': "Rave",
'type': BRCType.Character},
{'name': "Mesh",
'type': BRCType.Character},
{'name': "Shine",
'type': BRCType.Character},
{'name': "Rise",
'type': BRCType.Character},
{'name': "Coil",
'type': BRCType.Character},
{'name': "Frank",
'type': BRCType.Character},
{'name': "Rietveld",
'type': BRCType.Character},
{'name': "DJ Cyber",
'type': BRCType.Character},
{'name': "Eclipse",
'type': BRCType.Character},
{'name': "DOT.EXE",
'type': BRCType.Character},
{'name': "Devil Theory",
'type': BRCType.Character},
{'name': "Flesh Prince",
'type': BRCType.Character},
{'name': "Futurism",
'type': BRCType.Character},
{'name': "Oldhead",
'type': BRCType.Character},
# REP
{'name': "8 REP",
'type': BRCType.REP},
{'name': "16 REP",
'type': BRCType.REP},
{'name': "24 REP",
'type': BRCType.REP},
{'name': "32 REP",
'type': BRCType.REP},
{'name': "48 REP",
'type': BRCType.REP},
# App
{'name': "Camera App",
'type': BRCType.Camera}
]
group_table: Dict[str, Set[str]] = {
"graffitim": {"Graffiti (M - OVERWHELMME)",
"Graffiti (M - QUICK BING)",
"Graffiti (M - BLOCKY)",
"Graffiti (M - Pora)",
"Graffiti (M - Teddy 4)",
"Graffiti (M - BOMB BEATS)",
"Graffiti (M - SPRAYTANICPANIC!)",
"Graffiti (M - SHOGUN)",
"Graffiti (M - TeleBinge)",
"Graffiti (M - 0m33)",
"Graffiti (M - Vom'B)",
"Graffiti (M - Street classic)",
"Graffiti (M - Thick Candy)",
"Graffiti (M - colorBOMB)",
"Graffiti (M - Zona Leste)",
"Graffiti (M - Stacked Symbols)",
"Graffiti (M - B-boy Love)",
"Graffiti (M - Devil 68)",
"Graffiti (M - pico pow)"},
"graffitil": {"Graffiti (L - WHOLE SIXER)",
"Graffiti (L - INFINITY)",
"Graffiti (L - VoodooBoy)",
"Graffiti (L - Fang It Up!)",
"Graffiti (L - FREAKS)",
"Graffiti (L - Graffo Le Fou)",
"Graffiti (L - Lauder)",
"Graffiti (L - SpawningSeason)",
"Graffiti (L - Moai Marathon)",
"Graffiti (L - Tius)",
"Graffiti (L - NOISY NINJA)",
"Graffiti (L - Campaign Trail)",
"Graffiti (L - skate or di3)",
"Graffiti (L - Jd Vila Formosa)",
"Graffiti (L - Messenger Mural)",
"Graffiti (L - RECORD.HEAD)",
"Graffiti (L - Boom)",
"Graffiti (L - wild rush)",
"Graffiti (L - buttercup)"},
"graffitixl": {"Graffiti (XL - Gold Rush)",
"Graffiti (XL - WILD STRUXXA)",
"Graffiti (XL - VIBRATIONS)",
"Graffiti (XL - SECOND SIGHT)",
"Graffiti (XL - Bomb Croc)",
"Graffiti (XL - FATE)",
"Graffiti (XL - Web Spitter)",
"Graffiti (XL - MOTORCYCLE GANG)",
"Graffiti (XL - Deep Dive)",
"Graffiti (XL - MegaHood)",
"Graffiti (XL - Gamex UPA ABL)",
"Graffiti (XL - BiGSHiNYBoMB)",
"Graffiti (XL - Bomb Burner)",
"Graffiti (XL - Pirate's Life 4 Me)",
"Graffiti (XL - Bombing by FireMan)",
"Graffiti (XL - end 2 end)",
"Graffiti (XL - Raver Funk)",
"Graffiti (XL - headphones on Helmet on)"},
"skateboard": {"Skateboard (Devon)",
"Skateboard (Terrence)",
"Skateboard (Maceo)",
"Skateboard (Lazer Accuracy)",
"Skateboard (Death Boogie)",
"Skateboard (Sylk)",
"Skateboard (Taiga)",
"Skateboard (Just Swell)",
"Skateboard (Mantra)"},
"inline skates": {"Inline Skates (Glaciers)",
"Inline Skates (Sweet Royale)",
"Inline Skates (Strawberry Missiles)",
"Inline Skates (Ice Cold Killers)",
"Inline Skates (Red Industry)",
"Inline Skates (Mech Adversary)",
"Inline Skates (Orange Blasters)",
"Inline Skates (ck)",
"Inline Skates (Sharpshooters)"},
"skates": {"Inline Skates (Glaciers)",
"Inline Skates (Sweet Royale)",
"Inline Skates (Strawberry Missiles)",
"Inline Skates (Ice Cold Killers)",
"Inline Skates (Red Industry)",
"Inline Skates (Mech Adversary)",
"Inline Skates (Orange Blasters)",
"Inline Skates (ck)",
"Inline Skates (Sharpshooters)"},
"inline": {"Inline Skates (Glaciers)",
"Inline Skates (Sweet Royale)",
"Inline Skates (Strawberry Missiles)",
"Inline Skates (Ice Cold Killers)",
"Inline Skates (Red Industry)",
"Inline Skates (Mech Adversary)",
"Inline Skates (Orange Blasters)",
"Inline Skates (ck)",
"Inline Skates (Sharpshooters)"},
"bmx": {"BMX (Mr. Taupe)",
"BMX (Gum)",
"BMX (Steel Wheeler)",
"BMX (oyo)",
"BMX (Rigid No.6)",
"BMX (Ceremony)",
"BMX (XXX)",
"BMX (Terrazza)",
"BMX (Dedication)"},
"bike": {"BMX (Mr. Taupe)",
"BMX (Gum)",
"BMX (Steel Wheeler)",
"BMX (oyo)",
"BMX (Rigid No.6)",
"BMX (Ceremony)",
"BMX (XXX)",
"BMX (Terrazza)",
"BMX (Dedication)"},
"bicycle": {"BMX (Mr. Taupe)",
"BMX (Gum)",
"BMX (Steel Wheeler)",
"BMX (oyo)",
"BMX (Rigid No.6)",
"BMX (Ceremony)",
"BMX (XXX)",
"BMX (Terrazza)",
"BMX (Dedication)"},
"characters": {"Tryce",
"Bel",
"Vinyl",
"Solace",
"Rave",
"Mesh",
"Shine",
"Rise",
"Coil",
"Frank",
"Rietveld",
"DJ Cyber",
"Eclipse",
"DOT.EXE",
"Devil Theory",
"Flesh Prince",
"Futurism",
"Oldhead"},
"girl": {"Bel",
"Vinyl",
"Rave",
"Shine",
"Rise",
"Futurism"}
}

View File

@ -0,0 +1,785 @@
from typing import TypedDict, List
from .Regions import Stages
class LocationDict(TypedDict):
name: str
stage: Stages
game_id: str
class EventDict(TypedDict):
name: str
stage: Stages
item: str
location_table: List[LocationDict] = [
{'name': "Hideout: Half pipe CD",
'stage': Stages.H,
'game_id': "MusicTrack_CondensedMilk"},
{'name': "Hideout: Garage tower CD",
'stage': Stages.H,
'game_id': "MusicTrack_MorningGlow"},
{'name': "Hideout: Rooftop CD",
'stage': Stages.H,
'game_id': "MusicTrack_LightSwitch"},
{'name': "Hideout: Under staircase graffiti",
'stage': Stages.H,
'game_id': "UnlockGraffiti_grafTex_M1"},
{'name': "Hideout: Secret area graffiti",
'stage': Stages.H,
'game_id': "UnlockGraffiti_grafTex_L1"},
{'name': "Hideout: Rear studio graffiti",
'stage': Stages.H,
'game_id': "UnlockGraffiti_grafTex_XL1"},
{'name': "Hideout: Corner ledge graffiti",
'stage': Stages.H,
'game_id': "UnlockGraffiti_grafTex_M2"},
{'name': "Hideout: Upper platform skateboard",
'stage': Stages.H,
'game_id': "SkateboardDeck3"},
{'name': "Hideout: BMX garage skateboard",
'stage': Stages.H,
'game_id': "SkateboardDeck2"},
{'name': "Hideout: Unlock phone app",
'stage': Stages.H,
'game_id': "camera"},
{'name': "Hideout: Vinyl joins the crew",
'stage': Stages.H,
'game_id': "girl1"},
{'name': "Hideout: Solace joins the crew",
'stage': Stages.H,
'game_id': "dummy"},
{'name': "Versum Hill: Main street Robo Post graffiti",
'stage': Stages.VH1,
'game_id': "UnlockGraffiti_grafTex_L4"},
{'name': "Versum Hill: Behind glass graffiti",
'stage': Stages.VH1,
'game_id': "UnlockGraffiti_grafTex_L3"},
{'name': "Versum Hill: Office room graffiti",
'stage': Stages.VH1,
'game_id': "UnlockGraffiti_grafTex_M4"},
{'name': "Versum Hill: Under bridge graffiti",
'stage': Stages.VH2,
'game_id': "UnlockGraffiti_grafTex_XL4"},
{'name': "Versum Hill: Train rail ledge skateboard",
'stage': Stages.VH2,
'game_id': "SkateboardDeck6"},
{'name': "Versum Hill: Train station CD",
'stage': Stages.VH2,
'game_id': "MusicTrack_PreciousThing"},
{'name': "Versum Hill: Billboard platform outfit",
'stage': Stages.VH2,
'game_id': "MetalheadOutfit3"},
{'name': "Versum Hill: Hilltop Robo Post CD",
'stage': Stages.VH2,
'game_id': "MusicTrack_BounceUponATime"},
{'name': "Versum Hill: Hill secret skateboard",
'stage': Stages.VH2,
'game_id': "SkateboardDeck7"},
{'name': "Versum Hill: Rooftop CD",
'stage': Stages.VH2,
'game_id': "MusicTrack_NextToMe"},
{'name': "Versum Hill: Wallrunning challenge reward",
'stage': Stages.VH2,
'game_id': "UnlockGraffiti_grafTex_M3"},
{'name': "Versum Hill: Manual challenge reward",
'stage': Stages.VH2,
'game_id': "UnlockGraffiti_grafTex_L2"},
{'name': "Versum Hill: Corner challenge reward",
'stage': Stages.VH2,
'game_id': "UnlockGraffiti_grafTex_M13"},
{'name': "Versum Hill: Side street alley outfit",
'stage': Stages.VH3,
'game_id': "MetalheadOutfit4"},
{'name': "Versum Hill: Side street secret skateboard",
'stage': Stages.VH3,
'game_id': "SkateboardDeck9"},
{'name': "Versum Hill: Basketball court alley skateboard",
'stage': Stages.VH4,
'game_id': "SkateboardDeck5"},
{'name': "Versum Hill: Basketball court Robo Post CD",
'stage': Stages.VH4,
'game_id': "MusicTrack_Operator"},
{'name': "Versum Hill: Underground mall billboard graffiti",
'stage': Stages.VHO,
'game_id': "UnlockGraffiti_grafTex_XL3"},
{'name': "Versum Hill: Underground mall vending machine skateboard",
'stage': Stages.VHO,
'game_id': "SkateboardDeck8"},
{'name': "Versum Hill: BMX gate outfit",
'stage': Stages.VH1,
'game_id': "AngelOutfit3"},
{'name': "Versum Hill: Glass floor skates",
'stage': Stages.VH2,
'game_id': "InlineSkates4"},
{'name': "Versum Hill: Basketball court shortcut CD",
'stage': Stages.VH4,
'game_id': "MusicTrack_GetEnuf"},
{'name': "Versum Hill: Rave joins the crew",
'stage': Stages.VHO,
'game_id': "angel"},
{'name': "Versum Hill: Frank joins the crew",
'stage': Stages.VH2,
'game_id': "frank"},
{'name': "Versum Hill: Rietveld joins the crew",
'stage': Stages.VH4,
'game_id': "jetpackBossPlayer"},
{'name': "Versum Hill: Big Polo",
'stage': Stages.VH1,
'game_id': "PoloBuilding/Mascot_Polo_sit_big"},
{'name': "Versum Hill: Trash Polo",
'stage': Stages.VH1,
'game_id': "TrashCluster (1)/Mascot_Polo_street"},
{'name': "Versum Hill: Fruit stand Polo",
'stage': Stages.VHO,
'game_id': "SecretRoom/Mascot_Polo_street"},
{'name': "Millennium Square: Center ramp graffiti",
'stage': Stages.MS,
'game_id': "UnlockGraffiti_grafTex_L6"},
{'name': "Millennium Square: Rooftop staircase graffiti",
'stage': Stages.MS,
'game_id': "UnlockGraffiti_grafTex_M8"},
{'name': "Millennium Square: Toilet graffiti",
'stage': Stages.MS,
'game_id': "UnlockGraffiti_grafTex_XL6"},
{'name': "Millennium Square: Trash graffiti",
'stage': Stages.MS,
'game_id': "UnlockGraffiti_grafTex_M5"},
{'name': "Millennium Square: Center tower graffiti",
'stage': Stages.MS,
'game_id': "UnlockGraffiti_grafTex_M6"},
{'name': "Millennium Square: Rooftop billboard graffiti",
'stage': Stages.MS,
'game_id': "UnlockGraffiti_grafTex_XL7"},
{'name': "Millennium Square: Center Robo Post CD",
'stage': Stages.MS,
'game_id': "MusicTrack_FeelTheFunk"},
{'name': "Millennium Square: Parking garage Robo Post CD",
'stage': Stages.MS,
'game_id': "MusicTrack_Plume"},
{'name': "Millennium Square: Mall ledge outfit",
'stage': Stages.MS,
'game_id': "BlockGuyOutfit3"},
{'name': "Millennium Square: Alley rooftop outfit",
'stage': Stages.MS,
'game_id': "BlockGuyOutfit4"},
{'name': "Millennium Square: Alley staircase skateboard",
'stage': Stages.MS,
'game_id': "SkateboardDeck4"},
{'name': "Millennium Square: Secret painting skates",
'stage': Stages.MS,
'game_id': "InlineSkates2"},
{'name': "Millennium Square: Vending machine skates",
'stage': Stages.MS,
'game_id': "InlineSkates3"},
{'name': "Millennium Square: Walkway roof skates",
'stage': Stages.MS,
'game_id': "InlineSkates5"},
{'name': "Millennium Square: Alley ledge skates",
'stage': Stages.MS,
'game_id': "InlineSkates6"},
{'name': "Millennium Square: DJ Cyber joins the crew",
'stage': Stages.MS,
'game_id': "dj"},
{'name': "Millennium Square: Half pipe Polo",
'stage': Stages.MS,
'game_id': "propsSecretArea/Mascot_Polo_street"},
{'name': "Brink Terminal: Upside grind challenge reward",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_M10"},
{'name': "Brink Terminal: Manual challenge reward",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_L8"},
{'name': "Brink Terminal: Score challenge reward",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_M12"},
{'name': "Brink Terminal: Under square ledge graffiti",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_L9"},
{'name': "Brink Terminal: Bus graffiti",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_XL9"},
{'name': "Brink Terminal: Under square Robo Post graffiti",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_M9"},
{'name': "Brink Terminal: BMX gate graffiti",
'stage': Stages.BT1,
'game_id': "UnlockGraffiti_grafTex_L7"},
{'name': "Brink Terminal: Square tower CD",
'stage': Stages.BT1,
'game_id': "MusicTrack_Chapter1Mixtape"},
{'name': "Brink Terminal: Trash CD",
'stage': Stages.BT1,
'game_id': "MusicTrack_HairDunNailsDun"},
{'name': "Brink Terminal: Shop roof outfit",
'stage': Stages.BT1,
'game_id': "AngelOutfit4"},
{'name': "Brink Terminal: Underground glass skates",
'stage': Stages.BTO1,
'game_id': "InlineSkates8"},
{'name': "Brink Terminal: Glass roof skates",
'stage': Stages.BT1,
'game_id': "InlineSkates10"},
{'name': "Brink Terminal: Mesh's skateboard",
'stage': Stages.BTO2,
'game_id': "SkateboardDeck10"}, # double check this one
{'name': "Brink Terminal: Underground ramp skates",
'stage': Stages.BTO1,
'game_id': "InlineSkates7"},
{'name': "Brink Terminal: Rooftop halfpipe graffiti",
'stage': Stages.BT3,
'game_id': "UnlockGraffiti_grafTex_M11"},
{'name': "Brink Terminal: Wire grind CD",
'stage': Stages.BT2,
'game_id': "MusicTrack_Watchyaback"},
{'name': "Brink Terminal: Rooftop glass CD",
'stage': Stages.BT3,
'game_id': "MusicTrack_Refuse"},
{'name': "Brink Terminal: Tower core outfit",
'stage': Stages.BT3,
'game_id': "SpacegirlOutfit4"},
{'name': "Brink Terminal: High rooftop outfit",
'stage': Stages.BT3,
'game_id': "WideKidOutfit3"},
{'name': "Brink Terminal: Ocean platform CD",
'stage': Stages.BTO2,
'game_id': "MusicTrack_ScrapedOnTheWayOut"},
{'name': "Brink Terminal: End of dock CD",
'stage': Stages.BTO2,
'game_id': "MusicTrack_Hwbouths"},
{'name': "Brink Terminal: Dock Robo Post outfit",
'stage': Stages.BTO2,
'game_id': "WideKidOutfit4"},
{'name': "Brink Terminal: Control room skates",
'stage': Stages.BTO2,
'game_id': "InlineSkates9"},
{'name': "Brink Terminal: Mesh joins the crew",
'stage': Stages.BTO2,
'game_id': "wideKid"},
{'name': "Brink Terminal: Eclipse joins the crew",
'stage': Stages.BT1,
'game_id': "medusa"},
{'name': "Brink Terminal: Behind glass Polo",
'stage': Stages.BT1,
'game_id': "KingFood (Bear)/Mascot_Polo_street"},
{'name': "Millennium Mall: Warehouse pallet graffiti",
'stage': Stages.MM1,
'game_id': "UnlockGraffiti_grafTex_L5"},
{'name': "Millennium Mall: Wall alcove graffiti",
'stage': Stages.MM1,
'game_id': "UnlockGraffiti_grafTex_XL10"},
{'name': "Millennium Mall: Maintenance shaft CD",
'stage': Stages.MM1,
'game_id': "MusicTrack_MissingBreak"},
{'name': "Millennium Mall: Glass cylinder CD",
'stage': Stages.MM1,
'game_id': "MusicTrack_DAPEOPLE"},
{'name': "Millennium Mall: Lower Robo Post outfit",
'stage': Stages.MM1,
'game_id': "SpacegirlOutfit3"},
{'name': "Millennium Mall: Atrium vending machine graffiti",
'stage': Stages.MM2,
'game_id': "UnlockGraffiti_grafTex_M15"},
{'name': "Millennium Mall: Trick challenge reward",
'stage': Stages.MM2,
'game_id': "UnlockGraffiti_grafTex_XL8"},
{'name': "Millennium Mall: Slide challenge reward",
'stage': Stages.MM2,
'game_id': "UnlockGraffiti_grafTex_L10"},
{'name': "Millennium Mall: Fish challenge reward",
'stage': Stages.MM2,
'game_id': "UnlockGraffiti_grafTex_L12"},
{'name': "Millennium Mall: Score challenge reward",
'stage': Stages.MM2,
'game_id': "UnlockGraffiti_grafTex_XL11"},
{'name': "Millennium Mall: Atrium top floor Robo Post CD",
'stage': Stages.MM2,
'game_id': "MusicTrack_TwoDaysOff"},
{'name': "Millennium Mall: Atrium top floor floating CD",
'stage': Stages.MM2,
'game_id': "MusicTrack_Spectres"},
{'name': "Millennium Mall: Atrium top floor BMX",
'stage': Stages.MM2,
'game_id': "BMXBike2"},
{'name': "Millennium Mall: Theater entrance BMX",
'stage': Stages.MM2,
'game_id': "BMXBike3"},
{'name': "Millennium Mall: Atrium BMX gate BMX",
'stage': Stages.MM2,
'game_id': "BMXBike5"},
{'name': "Millennium Mall: Upside down rail outfit",
'stage': Stages.MM2,
'game_id': "BunGirlOutfit3"},
{'name': "Millennium Mall: Theater stage corner graffiti",
'stage': Stages.MM3,
'game_id': "UnlockGraffiti_grafTex_L15"},
{'name': "Millennium Mall: Theater hanging billboards graffiti",
'stage': Stages.MM3,
'game_id': "UnlockGraffiti_grafTex_XL15"},
{'name': "Millennium Mall: Theater garage graffiti",
'stage': Stages.MM3,
'game_id': "UnlockGraffiti_grafTex_M16"},
{'name': "Millennium Mall: Theater maintenance CD",
'stage': Stages.MM3,
'game_id': "MusicTrack_WannaKno"},
{'name': "Millennium Mall: Race track Robo Post CD",
'stage': Stages.MMO2,
'game_id': "MusicTrack_StateOfMind"},
{'name': "Millennium Mall: Hanging lights CD",
'stage': Stages.MMO1,
'game_id': "MusicTrack_Chapter2Mixtape"},
{'name': "Millennium Mall: Shine joins the crew",
'stage': Stages.MM3,
'game_id': "bunGirl"},
{'name': "Millennium Mall: DOT.EXE joins the crew",
'stage': Stages.MM2,
'game_id': "eightBall"},
{'name': "Pyramid Island: Lower rooftop graffiti",
'stage': Stages.PI1,
'game_id': "UnlockGraffiti_grafTex_L18"},
{'name': "Pyramid Island: Polo graffiti",
'stage': Stages.PI1,
'game_id': "UnlockGraffiti_grafTex_L16"},
{'name': "Pyramid Island: Above entrance graffiti",
'stage': Stages.PI1,
'game_id': "UnlockGraffiti_grafTex_XL16"},
{'name': "Pyramid Island: BMX gate BMX",
'stage': Stages.PI1,
'game_id': "BMXBike6"},
{'name': "Pyramid Island: Quarter pipe rooftop graffiti",
'stage': Stages.PI2,
'game_id': "UnlockGraffiti_grafTex_M17"},
{'name': "Pyramid Island: Supply port Robo Post CD",
'stage': Stages.PI2,
'game_id': "MusicTrack_Trinitron"},
{'name': "Pyramid Island: Above gate ledge CD",
'stage': Stages.PI2,
'game_id': "MusicTrack_Agua"},
{'name': "Pyramid Island: Smoke hole BMX",
'stage': Stages.PI2,
'game_id': "BMXBike8"},
{'name': "Pyramid Island: Above gate rail outfit",
'stage': Stages.PI2,
'game_id': "VinylOutfit3"},
{'name': "Pyramid Island: Rail loop outfit",
'stage': Stages.PI2,
'game_id': "BunGirlOutfit4"},
{'name': "Pyramid Island: Score challenge reward",
'stage': Stages.PI2,
'game_id': "UnlockGraffiti_grafTex_XL2"},
{'name': "Pyramid Island: Score challenge 2 reward",
'stage': Stages.PI2,
'game_id': "UnlockGraffiti_grafTex_L13"},
{'name': "Pyramid Island: Quarter pipe challenge reward",
'stage': Stages.PI2,
'game_id': "UnlockGraffiti_grafTex_XL12"},
{'name': "Pyramid Island: Wind turbines CD",
'stage': Stages.PI3,
'game_id': "MusicTrack_YouCanSayHi"},
{'name': "Pyramid Island: Shortcut glass CD",
'stage': Stages.PI3,
'game_id': "MusicTrack_Chromebies"},
{'name': "Pyramid Island: Turret jump CD",
'stage': Stages.PI3,
'game_id': "MusicTrack_ChuckinUp"},
{'name': "Pyramid Island: Helipad BMX",
'stage': Stages.PI3,
'game_id': "BMXBike7"},
{'name': "Pyramid Island: Pipe outfit",
'stage': Stages.PI3,
'game_id': "PufferGirlOutfit3"},
{'name': "Pyramid Island: Trash outfit",
'stage': Stages.PI3,
'game_id': "PufferGirlOutfit4"},
{'name': "Pyramid Island: Pyramid top CD",
'stage': Stages.PI4,
'game_id': "MusicTrack_BigCityLife"},
{'name': "Pyramid Island: Pyramid top Robo Post CD",
'stage': Stages.PI4,
'game_id': "MusicTrack_Chapter3Mixtape"},
{'name': "Pyramid Island: Maze outfit",
'stage': Stages.PIO,
'game_id': "VinylOutfit4"},
{'name': "Pyramid Island: Rise joins the crew",
'stage': Stages.PI4,
'game_id': "pufferGirl"},
{'name': "Pyramid Island: Devil Theory joins the crew",
'stage': Stages.PI3,
'game_id': "boarder"},
{'name': "Pyramid Island: Polo pile 1",
'stage': Stages.PI1,
'game_id': "Secret01Trash/Mascot_Polo_sit_big_wave"},
{'name': "Pyramid Island: Polo pile 2",
'stage': Stages.PI1,
'game_id': "Secret01Trash/Mascot_Polo_sit_big_wave (1)"},
{'name': "Pyramid Island: Polo pile 3",
'stage': Stages.PI1,
'game_id': "Secret01Trash/Mascot_Polo_sit_big_wave (2)"},
{'name': "Pyramid Island: Polo pile 4",
'stage': Stages.PI1,
'game_id': "Secret01Trash/Mascot_Polo_sit_big_wave (3)"},
{'name': "Pyramid Island: Maze glass Polo",
'stage': Stages.PIO,
'game_id': "Start/Mascot_Polo_sit_big (1)"},
{'name': "Pyramid Island: Maze classroom Polo",
'stage': Stages.PIO,
'game_id': "PeteRoom/Mascot_Polo_sit_big_wave (1)"},
{'name': "Pyramid Island: Maze vent Polo",
'stage': Stages.PIO,
'game_id': "CheckerRoom/Mascot_Polo_street"},
{'name': "Pyramid Island: Big maze Polo",
'stage': Stages.PIO,
'game_id': "YellowPoloRoom/Mascot_Polo_sit_big"},
{'name': "Pyramid Island: Maze desk Polo",
'stage': Stages.PIO,
'game_id': "PoloRoom/Mascot_Polo_sit_big"},
{'name': "Pyramid Island: Maze forklift Polo",
'stage': Stages.PIO,
'game_id': "ForkliftRoom/Mascot_Polo_sit_big_wave"},
{'name': "Mataan: Robo Post graffiti",
'stage': Stages.MA1,
'game_id': "UnlockGraffiti_grafTex_XL17"},
{'name': "Mataan: Secret ledge BMX",
'stage': Stages.MA1,
'game_id': "BMXBike9"},
{'name': "Mataan: Highway rooftop BMX",
'stage': Stages.MA1,
'game_id': "BMXBike10"},
{'name': "Mataan: Trash CD",
'stage': Stages.MA2,
'game_id': "MusicTrack_JackDaFunk"},
{'name': "Mataan: Half pipe CD",
'stage': Stages.MA2,
'game_id': "MusicTrack_FunkExpress"},
{'name': "Mataan: Across bull horns graffiti",
'stage': Stages.MA2,
'game_id': "UnlockGraffiti_grafTex_L17"},
{'name': "Mataan: Small rooftop graffiti",
'stage': Stages.MA2,
'game_id': "UnlockGraffiti_grafTex_M18"},
{'name': "Mataan: Trash graffiti",
'stage': Stages.MA2,
'game_id': "UnlockGraffiti_grafTex_XL5"},
{'name': "Mataan: Deep city Robo Post CD",
'stage': Stages.MA3,
'game_id': "MusicTrack_LastHoorah"},
{'name': "Mataan: Deep city tower CD",
'stage': Stages.MA3,
'game_id': "MusicTrack_Chapter4Mixtape"},
{'name': "Mataan: Race challenge reward",
'stage': Stages.MA3,
'game_id': "UnlockGraffiti_grafTex_M14"},
{'name': "Mataan: Wallrunning challenge reward",
'stage': Stages.MA3,
'game_id': "UnlockGraffiti_grafTex_L14"},
{'name': "Mataan: Score challenge reward",
'stage': Stages.MA3,
'game_id': "UnlockGraffiti_grafTex_XL13"},
{'name': "Mataan: Deep city vent jump BMX",
'stage': Stages.MA3,
'game_id': "BMXBike4"},
{'name': "Mataan: Deep city side wires outfit",
'stage': Stages.MA3,
'game_id': "DummyOutfit3"},
{'name': "Mataan: Deep city center island outfit",
'stage': Stages.MA3,
'game_id': "DummyOutfit4"},
{'name': "Mataan: Red light rail graffiti",
'stage': Stages.MAO,
'game_id': "UnlockGraffiti_grafTex_XL18"},
{'name': "Mataan: Red light side alley outfit",
'stage': Stages.MAO,
'game_id': "RingDudeOutfit3"},
{'name': "Mataan: Statue hand outfit",
'stage': Stages.MA4,
'game_id': "RingDudeOutfit4"},
{'name': "Mataan: Crane CD",
'stage': Stages.MA5,
'game_id': "MusicTrack_InThePocket"},
{'name': "Mataan: Elephant tower glass outfit",
'stage': Stages.MA5,
'game_id': "LegendFaceOutfit3"},
{'name': "Mataan: Helipad outfit",
'stage': Stages.MA5,
'game_id': "LegendFaceOutfit4"},
{'name': "Mataan: Vending machine CD",
'stage': Stages.MA5,
'game_id': "MusicTrack_Iridium"},
{'name': "Mataan: Coil joins the crew",
'stage': Stages.MA5,
'game_id': "ringdude"},
{'name': "Mataan: Flesh Prince joins the crew",
'stage': Stages.MA5,
'game_id': "prince"},
{'name': "Mataan: Futurism joins the crew",
'stage': Stages.MA5,
'game_id': "futureGirl"},
{'name': "Mataan: Trash Polo",
'stage': Stages.MA2,
'game_id': "PropsMallArea/Mascot_Polo_street"},
{'name': "Mataan: Shopping Polo",
'stage': Stages.MA5,
'game_id': "propsMarket/Mascot_Polo_street"},
{'name': "Tagged 5 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf5"},
{'name': "Tagged 10 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf10"},
{'name': "Tagged 15 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf15"},
{'name': "Tagged 20 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf20"},
{'name': "Tagged 25 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf25"},
{'name': "Tagged 30 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf30"},
{'name': "Tagged 35 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf35"},
{'name': "Tagged 40 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf40"},
{'name': "Tagged 45 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf45"},
{'name': "Tagged 50 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf50"},
{'name': "Tagged 55 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf55"},
{'name': "Tagged 60 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf60"},
{'name': "Tagged 65 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf65"},
{'name': "Tagged 70 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf70"},
{'name': "Tagged 75 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf75"},
{'name': "Tagged 80 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf80"},
{'name': "Tagged 85 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf85"},
{'name': "Tagged 90 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf90"},
{'name': "Tagged 95 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf95"},
{'name': "Tagged 100 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf100"},
{'name': "Tagged 105 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf105"},
{'name': "Tagged 110 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf110"},
{'name': "Tagged 115 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf115"},
{'name': "Tagged 120 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf120"},
{'name': "Tagged 125 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf125"},
{'name': "Tagged 130 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf130"},
{'name': "Tagged 135 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf135"},
{'name': "Tagged 140 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf140"},
{'name': "Tagged 145 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf145"},
{'name': "Tagged 150 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf150"},
{'name': "Tagged 155 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf155"},
{'name': "Tagged 160 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf160"},
{'name': "Tagged 165 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf165"},
{'name': "Tagged 170 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf170"},
{'name': "Tagged 175 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf175"},
{'name': "Tagged 180 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf180"},
{'name': "Tagged 185 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf185"},
{'name': "Tagged 190 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf190"},
{'name': "Tagged 195 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf195"},
{'name': "Tagged 200 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf200"},
{'name': "Tagged 205 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf205"},
{'name': "Tagged 210 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf210"},
{'name': "Tagged 215 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf215"},
{'name': "Tagged 220 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf220"},
{'name': "Tagged 225 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf225"},
{'name': "Tagged 230 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf230"},
{'name': "Tagged 235 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf235"},
{'name': "Tagged 240 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf240"},
{'name': "Tagged 245 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf245"},
{'name': "Tagged 250 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf250"},
{'name': "Tagged 255 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf255"},
{'name': "Tagged 260 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf260"},
{'name': "Tagged 265 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf265"},
{'name': "Tagged 270 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf270"},
{'name': "Tagged 275 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf275"},
{'name': "Tagged 280 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf280"},
{'name': "Tagged 285 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf285"},
{'name': "Tagged 290 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf290"},
{'name': "Tagged 295 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf295"},
{'name': "Tagged 300 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf300"},
{'name': "Tagged 305 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf305"},
{'name': "Tagged 310 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf310"},
{'name': "Tagged 315 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf315"},
{'name': "Tagged 320 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf320"},
{'name': "Tagged 325 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf325"},
{'name': "Tagged 330 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf330"},
{'name': "Tagged 335 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf335"},
{'name': "Tagged 340 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf340"},
{'name': "Tagged 345 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf345"},
{'name': "Tagged 350 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf350"},
{'name': "Tagged 355 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf355"},
{'name': "Tagged 360 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf360"},
{'name': "Tagged 365 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf365"},
{'name': "Tagged 370 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf370"},
{'name': "Tagged 375 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf375"},
{'name': "Tagged 380 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf380"},
{'name': "Tagged 385 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf385"},
{'name': "Tagged 389 Graffiti Spots",
'stage': Stages.Misc,
'game_id': "graf379"},
]
event_table: List[EventDict] = [
{'name': "Versum Hill: Complete Chapter 1",
'stage': Stages.VH4,
'item': "Chapter Completed"},
{'name': "Brink Terminal: Complete Chapter 2",
'stage': Stages.BT3,
'item': "Chapter Completed"},
{'name': "Millennium Mall: Complete Chapter 3",
'stage': Stages.MM3,
'item': "Chapter Completed"},
{'name': "Pyramid Island: Complete Chapter 4",
'stage': Stages.PI3,
'item': "Chapter Completed"},
{'name': "Defeat Faux",
'stage': Stages.MA5,
'item': "Victory"},
]

View File

@ -0,0 +1,162 @@
from dataclasses import dataclass
from Options import Choice, Toggle, DefaultOnToggle, Range, DeathLink, PerGameCommonOptions
import typing
if typing.TYPE_CHECKING:
from random import Random
else:
Random = typing.Any
class Logic(Choice):
"""Choose the logic used by the randomizer."""
display_name = "Logic"
option_glitchless = 0
option_glitched = 1
default = 0
class SkipIntro(DefaultOnToggle):
"""Skips escaping the police station.
Graffiti spots tagged during the intro will not unlock items."""
display_name = "Skip Intro"
class SkipDreams(Toggle):
"""Skips the dream sequences at the end of each chapter.
This can be changed later in the options menu inside the Archipelago phone app."""
display_name = "Skip Dreams"
class SkipHands(Toggle):
"""Skips spraying the lion statue hands after the dream in Chapter 5."""
display_name = "Skip Statue Hands"
class TotalRep(Range):
"""Change the total amount of REP in your world.
At least 960 REP is needed to finish the game.
Will be rounded to the nearest number divisible by 8."""
display_name = "Total REP"
range_start = 1000
range_end = 2000
default = 1400
def round_to_nearest_step(self):
rem: int = self.value % 8
if rem >= 5:
self.value = self.value - rem + 8
else:
self.value = self.value - rem
def get_rep_item_counts(self, random_source: Random, location_count: int) -> typing.List[int]:
def increment_item(item: int) -> int:
if item >= 32:
item = 48
else:
item += 8
return item
items = [8]*location_count
while sum(items) < self.value:
index = random_source.randint(0, location_count-1)
while items[index] >= 48:
index = random_source.randint(0, location_count-1)
items[index] = increment_item(items[index])
while sum(items) > self.value:
index = random_source.randint(0, location_count-1)
while not (items[index] == 16 or items[index] == 24 or items[index] == 32):
index = random_source.randint(0, location_count-1)
items[index] -= 8
return [items.count(8), items.count(16), items.count(24), items.count(32), items.count(48)]
class EndingREP(Toggle):
"""Changes the final boss to require 1000 REP instead of 960 REP to start."""
display_name = "Extra REP Required"
class StartStyle(Choice):
"""Choose which movestyle to start with."""
display_name = "Starting Movestyle"
option_skateboard = 2
option_inline_skates = 3
option_bmx = 1
default = 2
class LimitedGraffiti(Toggle):
"""Each graffiti design can only be used a limited number of times before being removed from your inventory.
In some cases, such as completing a dream, using graffiti to defeat enemies, or spraying over your own graffiti,
uses will not be counted.
If enabled, doing graffiti is disabled during crew battles, to prevent softlocking."""
display_name = "Limited Graffiti"
class SGraffiti(Choice):
"""Choose if small graffiti should be separate, meaning that you will need to switch characters every time you run
out, or combined, meaning that unlocking new characters will add 5 uses that any character can use.
Has no effect if Limited Graffiti is disabled."""
display_name = "Small Graffiti Uses"
option_separate = 0
option_combined = 1
default = 0
class JunkPhotos(Toggle):
"""Skip taking pictures of Polo for items."""
display_name = "Skip Polo Photos"
class DontSavePhotos(Toggle):
"""Photos taken with the Camera app will not be saved.
This can be changed later in the options menu inside the Archipelago phone app."""
display_name = "Don't Save Photos"
class ScoreDifficulty(Choice):
"""Alters the score required to win score challenges and crew battles.
This can be changed later in the options menu inside the Archipelago phone app."""
display_name = "Score Difficulty"
option_normal = 0
option_medium = 1
option_hard = 2
option_very_hard = 3
option_extreme = 4
default = 0
class DamageMultiplier(Range):
"""Multiplies all damage received.
At 3x, most damage will OHKO the player, including falling into pits.
At 6x, all damage will OHKO the player.
This can be changed later in the options menu inside the Archipelago phone app."""
display_name = "Damage Multiplier"
range_start = 1
range_end = 6
default = 1
class BRCDeathLink(DeathLink):
"""When you die, everyone dies. The reverse is also true.
This can be changed later in the options menu inside the Archipelago phone app."""
@dataclass
class BombRushCyberfunkOptions(PerGameCommonOptions):
logic: Logic
skip_intro: SkipIntro
skip_dreams: SkipDreams
skip_statue_hands: SkipHands
total_rep: TotalRep
extra_rep_required: EndingREP
starting_movestyle: StartStyle
limited_graffiti: LimitedGraffiti
small_graffiti_uses: SGraffiti
skip_polo_photos: JunkPhotos
dont_save_photos: DontSavePhotos
score_difficulty: ScoreDifficulty
damage_multiplier: DamageMultiplier
death_link: BRCDeathLink

View File

@ -0,0 +1,102 @@
from typing import Dict, List
class Stages:
Misc = "Misc"
H = "Hideout"
VH1 = "Versum Hill"
VH2 = "Versum Hill - After Roadblock"
VHO = "Versum Hill - Underground Mall"
VH3 = "Versum Hill - Side Street"
VH4 = "Versum Hill - Basketball Court"
MS = "Millennium Square"
BT1 = "Brink Terminal"
BTO1 = "Brink Terminal - Underground"
BTO2 = "Brink Terminal - Dock"
BT2 = "Brink Terminal - Planet Plaza"
BT3 = "Brink Terminal - Tower"
MM1 = "Millennium Mall"
MMO1 = "Millennium Mall - Hanging Lights"
MM2 = "Millennium Mall - Atrium"
MMO2 = "Millennium Mall - Race Track"
MM3 = "Millennium Mall - Theater"
PI1 = "Pyramid Island - Base"
PI2 = "Pyramid Island - After Gate"
PIO = "Pyramid Island - Maze"
PI3 = "Pyramid Island - Upper Areas"
PI4 = "Pyramid Island - Top"
MA1 = "Mataan - Streets"
MA2 = "Mataan - After Smoke Wall"
MA3 = "Mataan - Deep City"
MAO = "Mataan - Red Light District"
MA4 = "Mataan - Lion Statue"
MA5 = "Mataan - Skyscrapers"
region_exits: Dict[str, str] = {
Stages.Misc: [Stages.H],
Stages.H: [Stages.Misc,
Stages.VH1,
Stages.MS,
Stages.MA1],
Stages.VH1: [Stages.H,
Stages.VH2],
Stages.VH2: [Stages.H,
Stages.VH1,
Stages.MS,
Stages.VHO,
Stages.VH3,
Stages.VH4],
Stages.VHO: [Stages.VH2],
Stages.VH3: [Stages.VH2],
Stages.VH4: [Stages.VH2,
Stages.VH1],
Stages.MS: [Stages.VH2,
Stages.BT1,
Stages.MM1,
Stages.PI1,
Stages.MA1],
Stages.BT1: [Stages.MS,
Stages.BTO1,
Stages.BTO2,
Stages.BT2],
Stages.BTO1: [Stages.BT1],
Stages.BTO2: [Stages.BT1],
Stages.BT2: [Stages.BT1,
Stages.BT3],
Stages.BT3: [Stages.BT1,
Stages.BT2],
Stages.MM1: [Stages.MS,
Stages.MMO1,
Stages.MM2],
Stages.MMO1: [Stages.MM1],
Stages.MM2: [Stages.MM1,
Stages.MMO2,
Stages.MM3],
Stages.MMO2: [Stages.MM2],
Stages.MM3: [Stages.MM2,
Stages.MM1],
Stages.PI1: [Stages.MS,
Stages.PI2],
Stages.PI2: [Stages.PI1,
Stages.PIO,
Stages.PI3],
Stages.PIO: [Stages.PI2],
Stages.PI3: [Stages.PI1,
Stages.PI2,
Stages.PI4],
Stages.PI4: [Stages.PI1,
Stages.PI2,
Stages.PI3],
Stages.MA1: [Stages.H,
Stages.MS,
Stages.MA2],
Stages.MA2: [Stages.MA1,
Stages.MA3],
Stages.MA3: [Stages.MA2,
Stages.MAO,
Stages.MA4],
Stages.MAO: [Stages.MA3],
Stages.MA4: [Stages.MA3,
Stages.MA5],
Stages.MA5: [Stages.MA1]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
from typing import Any, Dict
from BaseClasses import MultiWorld, Region, Location, Item, Tutorial, ItemClassification, CollectionState
from worlds.AutoWorld import World, WebWorld
from .Items import base_id, item_table, group_table, BRCType
from .Locations import location_table, event_table
from .Regions import region_exits
from .Rules import rules
from .Options import BombRushCyberfunkOptions, StartStyle
class BombRushCyberfunkWeb(WebWorld):
theme = "ocean"
tutorials = [Tutorial(
"Multiworld Setup Guide",
"A guide to setting up Bomb Rush Cyberfunk randomizer and connecting to an Archipelago Multiworld",
"English",
"setup_en.md",
"setup/en",
["TRPG"]
)]
class BombRushCyberfunkWorld(World):
"""Bomb Rush Cyberfunk is 1 second per second of advanced funkstyle. Battle rival crews and dispatch militarized
police to conquer the five boroughs of New Amsterdam. Become All City."""
game = "Bomb Rush Cyberfunk"
web = BombRushCyberfunkWeb()
item_name_to_id = {item["name"]: (base_id + index) for index, item in enumerate(item_table)}
item_name_to_type = {item["name"]: item["type"] for item in item_table}
location_name_to_id = {loc["name"]: (base_id + index) for index, loc in enumerate(location_table)}
item_name_groups = group_table
options_dataclass = BombRushCyberfunkOptions
options: BombRushCyberfunkOptions
def __init__(self, multiworld: MultiWorld, player: int):
super(BombRushCyberfunkWorld, self).__init__(multiworld, player)
self.item_classification: Dict[BRCType, ItemClassification] = {
BRCType.Music: ItemClassification.filler,
BRCType.GraffitiM: ItemClassification.progression,
BRCType.GraffitiL: ItemClassification.progression,
BRCType.GraffitiXL: ItemClassification.progression,
BRCType.Outfit: ItemClassification.filler,
BRCType.Character: ItemClassification.progression,
BRCType.REP: ItemClassification.progression_skip_balancing,
BRCType.Camera: ItemClassification.progression
}
def collect(self, state: "CollectionState", item: "Item") -> bool:
change = super().collect(state, item)
if change and "REP" in item.name:
rep: int = int(item.name[0:len(item.name)-4])
state.prog_items[item.player]["rep"] += rep
return change
def remove(self, state: "CollectionState", item: "Item") -> bool:
change = super().remove(state, item)
if change and "REP" in item.name:
rep: int = int(item.name[0:len(item.name)-4])
state.prog_items[item.player]["rep"] -= rep
return change
def set_rules(self):
rules(self)
def get_item_classification(self, item_type: BRCType) -> ItemClassification:
classification = ItemClassification.filler
if item_type in self.item_classification.keys():
classification = self.item_classification[item_type]
return classification
def create_item(self, name: str) -> "BombRushCyberfunkItem":
item_id: int = self.item_name_to_id[name]
item_type: BRCType = self.item_name_to_type[name]
classification = self.get_item_classification(item_type)
return BombRushCyberfunkItem(name, classification, item_id, self.player)
def create_event(self, event: str) -> "BombRushCyberfunkItem":
return BombRushCyberfunkItem(event, ItemClassification.progression_skip_balancing, None, self.player)
def get_filler_item_name(self) -> str:
item = self.random.choice(item_table)
while self.get_item_classification(item["type"]) == ItemClassification.progression:
item = self.random.choice(item_table)
return item["name"]
def generate_early(self):
if self.options.starting_movestyle == StartStyle.option_skateboard:
self.item_classification[BRCType.Skateboard] = ItemClassification.filler
else:
self.item_classification[BRCType.Skateboard] = ItemClassification.progression
if self.options.starting_movestyle == StartStyle.option_inline_skates:
self.item_classification[BRCType.InlineSkates] = ItemClassification.filler
else:
self.item_classification[BRCType.InlineSkates] = ItemClassification.progression
if self.options.starting_movestyle == StartStyle.option_bmx:
self.item_classification[BRCType.BMX] = ItemClassification.filler
else:
self.item_classification[BRCType.BMX] = ItemClassification.progression
def create_items(self):
rep_locations: int = 87
if self.options.skip_polo_photos:
rep_locations -= 18
self.options.total_rep.round_to_nearest_step()
rep_counts = self.options.total_rep.get_rep_item_counts(self.random, rep_locations)
#print(sum([8*rep_counts[0], 16*rep_counts[1], 24*rep_counts[2], 32*rep_counts[3], 48*rep_counts[4]]), \
# rep_counts)
pool = []
for item in item_table:
if "REP" in item["name"]:
count: int = 0
if item["name"] == "8 REP":
count = rep_counts[0]
elif item["name"] == "16 REP":
count = rep_counts[1]
elif item["name"] == "24 REP":
count = rep_counts[2]
elif item["name"] == "32 REP":
count = rep_counts[3]
elif item["name"] == "48 REP":
count = rep_counts[4]
if count > 0:
for _ in range(count):
pool.append(self.create_item(item["name"]))
else:
pool.append(self.create_item(item["name"]))
self.multiworld.itempool += pool
def create_regions(self):
multiworld = self.multiworld
player = self.player
menu = Region("Menu", player, multiworld)
multiworld.regions.append(menu)
for n in region_exits:
multiworld.regions += [Region(n, player, multiworld)]
menu.add_exits({"Hideout": "New Game"})
for n in region_exits:
self.get_region(n).add_exits(region_exits[n])
for index, loc in enumerate(location_table):
if self.options.skip_polo_photos and "Polo" in loc["name"]:
continue
stage: Region = self.get_region(loc["stage"])
stage.add_locations({loc["name"]: base_id + index})
for e in event_table:
stage: Region = self.get_region(e["stage"])
event = BombRushCyberfunkLocation(player, e["name"], None, stage)
event.show_in_spoiler = False
event.place_locked_item(self.create_event(e["item"]))
stage.locations += [event]
multiworld.completion_condition[player] = lambda state: state.has("Victory", player)
def fill_slot_data(self) -> Dict[str, Any]:
options = self.options
slot_data: Dict[str, Any] = {
"locations": {loc["game_id"]: (base_id + index) for index, loc in enumerate(location_table)},
"logic": options.logic.value,
"skip_intro": bool(options.skip_intro.value),
"skip_dreams": bool(options.skip_dreams.value),
"skip_statue_hands": bool(options.skip_statue_hands.value),
"total_rep": options.total_rep.value,
"extra_rep_required": bool(options.extra_rep_required.value),
"starting_movestyle": options.starting_movestyle.value,
"limited_graffiti": bool(options.limited_graffiti.value),
"small_graffiti_uses": options.small_graffiti_uses.value,
"skip_polo_photos": bool(options.skip_polo_photos.value),
"dont_save_photos": bool(options.dont_save_photos.value),
"score_difficulty": int(options.score_difficulty.value),
"damage_multiplier": options.damage_multiplier.value,
"death_link": bool(options.death_link.value)
}
return slot_data
class BombRushCyberfunkItem(Item):
game: str = "Bomb Rush Cyberfunk"
class BombRushCyberfunkLocation(Location):
game: str = "Bomb Rush Cyberfunk"

View File

@ -0,0 +1,29 @@
# Bomb Rush Cyberfunk
## Where is the options page?
The [player options page for this game](../player-options) contains all the options you need to configure and export
a config file.
## What does randomization do in this game?
The goal of Bomb Rush Cyberfunk randomizer is to defeat all rival crews in each borough of New Amsterdam. REP is no
longer earned from doing graffiti, and is instead earned by finding it randomly in the multiworld.
Items can be found by picking up any type of collectible, unlocking characters, taking pictures of Polo, and for every
5 graffiti spots tagged. The types of items that can be found are Music, Graffiti (M), Graffiti (L), Graffiti (XL),
Skateboards, Inline Skates, BMX, Outifts, Characters, REP, and the Camera.
Several changes have been made to the game for a better experience as a randomizer:
- The prelude in the police station can be skipped.
- The map for each stage is always unlocked.
- The taxi is always unlocked, but you will still need to visit each stage's taxi stop before you can use them.
- No M, L, or XL graffiti is unlocked at the beginning.
- Optionally, graffiti can be depleted after a certain number of uses.
- All characters except Red are locked.
- One single REP count is used throughout the game, instead of having separate totals for each stage. REP requirements
are the same as the original game, but added together in order. At least 960 REP is needed to finish the game.
The mod also adds two new apps to the phone, an "Encounter" app which lets you retry certain events early, and the
"Archipelago" app which lets you view chat messages and change some options while playing.

View File

@ -0,0 +1,41 @@
# Bomb Rush Cyberfunk Multiworld Setup Guide
## Quick Links
- Bomb Rush Cyberfunk: [Steam](https://store.steampowered.com/app/1353230/Bomb_Rush_Cyberfunk/)
- Archipelago Mod: [Thunderstore](https://thunderstore.io/c/bomb-rush-cyberfunk/p/TRPG/Archipelago/),
[GitHub](https://github.com/TRPG0/BRC-Archipelago/releases)
## Setup
To install the Archipelago mod, you can use a mod manager like
[r2modman](https://thunderstore.io/c/bomb-rush-cyberfunk/p/ebkr/r2modman/), or install manually by following these steps:
1. Download and install [BepInEx 5.4.22 x64](https://github.com/BepInEx/BepInEx/releases/tag/v5.4.22) in your Bomb Rush
Cyberfunk root folder. *Do not use any pre-release versions of BepInEx 6.*
2. Start Bomb Rush Cyberfunk once so that BepInEx can create its required configuration files.
3. Download the zip archive from the [releases](https://github.com/TRPG0/BRC-Archipelago/releases) page, and extract its
contents into `BepInEx\plugins`.
After installing Archipelago, there are some additional mods that can also be installed for a better experience:
- [MoreMap](https://thunderstore.io/c/bomb-rush-cyberfunk/p/TRPG/MoreMap/) by TRPG
- Adds pins to the map for every type of collectible.
- [FasterLoadTimes](https://thunderstore.io/c/bomb-rush-cyberfunk/p/cspotcode/FasterLoadTimes/) by cspotcode
- Load stages faster by skipping assets that are already loaded.
- [CutsceneSkip](https://thunderstore.io/c/bomb-rush-cyberfunk/p/Jay/CutsceneSkip/) by Jay
- Makes every cutscene skippable.
- [GimmeMyBoost](https://thunderstore.io/c/bomb-rush-cyberfunk/p/Yuri/GimmeMyBoost/) by Yuri
- Retains boost when loading into a new stage.
- [DisableAnnoyingCutscenes](https://thunderstore.io/c/bomb-rush-cyberfunk/p/viliger/DisableAnnoyingCutscenes/) by viliger
- Disables the police cutscenes when increasing your heat level.
- [FastTravel](https://thunderstore.io/c/bomb-rush-cyberfunk/p/tari/FastTravel/) by tari
- Adds an app to the phone to call for a taxi from anywhere.
## Connecting
To connect to an Archipelago server, click one of the Archipelago buttons next to the save files. If the save file is
blank or already has randomizer save data, it will open a menu where you can enter the server address and port, your
name, and a password if necessary. Then click the check mark to connect to the server.

View File

@ -0,0 +1,5 @@
from test.bases import WorldTestBase
class BombRushCyberfunkTestBase(WorldTestBase):
game = "Bomb Rush Cyberfunk"

View File

@ -0,0 +1,284 @@
from . import BombRushCyberfunkTestBase
from ..Rules import build_access_cache, spots_s_glitchless, spots_s_glitched, spots_m_glitchless, spots_m_glitched, \
spots_l_glitchless, spots_l_glitched, spots_xl_glitched, spots_xl_glitchless
class TestSpotsGlitchless(BombRushCyberfunkTestBase):
@property
def run_default_tests(self) -> bool:
return False
def test_spots_glitchless(self) -> None:
player = self.player
self.collect_by_name([
"Graffiti (M - OVERWHELMME)",
"Graffiti (L - WHOLE SIXER)",
"Graffiti (XL - Gold Rush)"
])
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 1 - hideout
self.assertEqual(10, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(4, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(7, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(3, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.collect_by_name("Inline Skates (Glaciers)")
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
self.assertEqual(8, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 20
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 1 - VH1-2
self.assertEqual(22, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(20, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(23, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(9, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 65
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 1 - VH3
self.assertEqual(23, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(24, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 90
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 1 - VH4
self.assertEqual(10, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["Chapter Completed"] = 1
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - MS + MA1
self.assertEqual(34, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(39, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(38, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(19, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 120
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - VHO
self.assertEqual(35, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(43, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(40, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.collect_by_name("Bel")
self.multiworld.state.prog_items[player]["rep"] = 180
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - BT1
self.assertEqual(44, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(56, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(50, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(22, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 220
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - BT2
self.assertEqual(47, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(60, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(52, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(23, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 250
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - BTO1
self.assertEqual(53, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(24, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 280
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - BT3 / chapter 3 - MS
self.assertEqual(58, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(28, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 320
self.multiworld.state.prog_items[player]["Chapter Completed"] = 2
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 2 - BTO2 / chapter 3 - MS
self.assertEqual(54, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(67, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(62, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(30, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 380
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 3 - MM1-2
self.assertEqual(61, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(78, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(73, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(37, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 491
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 3 - MM3
self.assertEqual(64, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(82, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(77, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(42, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["Chapter Completed"] = 3
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 4 - MS / BT / MMO1 / PI1
self.assertEqual(66, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(85, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(85, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(46, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 620
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 4 - PI2
self.assertEqual(71, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(88, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(89, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 660
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 4 - PI3
self.assertEqual(79, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(96, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(94, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(51, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 730
self.multiworld.state.prog_items[player]["Chapter Completed"] = 4
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 5 - PI4
self.assertEqual(98, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(96, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 780
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 5 - PIO
self.assertEqual(81, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(103, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(98, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(54, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 850
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 5 - MA2
self.assertEqual(84, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(99, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(56, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 864
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 5 - MA3
self.assertEqual(89, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(111, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(102, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(58, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 935
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 5 - MAO
self.assertEqual(92, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(112, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(104, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(60, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["rep"] = 960
access_cache = build_access_cache(self.multiworld.state, player, 2, False, False)
# chapter 5 - MA4-5
self.assertEqual(94, spots_s_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(123, spots_m_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(111, spots_l_glitchless(self.multiworld.state, player, False, access_cache))
self.assertEqual(62, spots_xl_glitchless(self.multiworld.state, player, False, access_cache))
class TestSpotsGlitched(BombRushCyberfunkTestBase):
options = {
"logic": "glitched"
}
@property
def run_default_tests(self) -> bool:
return False
def test_spots_glitched(self) -> None:
player = self.player
self.collect_by_name([
"Graffiti (M - OVERWHELMME)",
"Graffiti (L - WHOLE SIXER)",
"Graffiti (XL - Gold Rush)"
])
access_cache = build_access_cache(self.multiworld.state, player, 2, False, True)
self.assertEqual(75, spots_s_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(99, spots_m_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(88, spots_l_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(51, spots_xl_glitched(self.multiworld.state, player, False, access_cache))
self.collect_by_name("Bel")
self.multiworld.state.prog_items[player]["Chapter Completed"] = 1
self.multiworld.state.prog_items[player]["rep"] = 180
access_cache = build_access_cache(self.multiworld.state, player, 2, False, True)
# brink terminal
self.assertEqual(88, spots_s_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(120, spots_m_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(106, spots_l_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(58, spots_xl_glitched(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["Chapter Completed"] = 2
access_cache = build_access_cache(self.multiworld.state, player, 2, False, True)
# chapter 3
self.assertEqual(94, spots_s_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(123, spots_m_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(110, spots_l_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(61, spots_xl_glitched(self.multiworld.state, player, False, access_cache))
self.multiworld.state.prog_items[player]["Chapter Completed"] = 3
access_cache = build_access_cache(self.multiworld.state, player, 2, False, True)
# chapter 4
self.assertEqual(111, spots_l_glitched(self.multiworld.state, player, False, access_cache))
self.assertEqual(62, spots_xl_glitched(self.multiworld.state, player, False, access_cache))

View File

@ -0,0 +1,29 @@
from . import BombRushCyberfunkTestBase
class TestRegularGraffitiGlitchless(BombRushCyberfunkTestBase):
options = {
"logic": "glitchless",
"limited_graffiti": False
}
class TestLimitedGraffitiGlitchless(BombRushCyberfunkTestBase):
options = {
"logic": "glitchless",
"limited_graffiti": True
}
class TestRegularGraffitiGlitched(BombRushCyberfunkTestBase):
options = {
"logic": "glitched",
"limited_graffiti": False
}
class TestLimitedGraffitiGlitched(BombRushCyberfunkTestBase):
options = {
"logic": "glitched",
"limited_graffiti": True
}

View File

@ -0,0 +1,45 @@
from . import BombRushCyberfunkTestBase
from typing import List
rep_item_names: List[str] = [
"8 REP",
"16 REP",
"24 REP",
"32 REP",
"48 REP"
]
class TestCollectAndRemoveREP(BombRushCyberfunkTestBase):
@property
def run_default_tests(self) -> bool:
return False
def test_default_rep_total(self) -> None:
self.collect_by_name(rep_item_names)
self.assertEqual(1400, self.multiworld.state.prog_items[self.player]["rep"])
new_total = 1400
if self.count("8 REP") > 0:
new_total -= 8
self.remove(self.get_item_by_name("8 REP"))
if self.count("16 REP") > 0:
new_total -= 16
self.remove(self.get_item_by_name("16 REP"))
if self.count("24 REP") > 0:
new_total -= 24
self.remove(self.get_item_by_name("24 REP"))
if self.count("32 REP") > 0:
new_total -= 32
self.remove(self.get_item_by_name("32 REP"))
if self.count("48 REP") > 0:
new_total -= 48
self.remove(self.get_item_by_name("48 REP"))
self.assertEqual(new_total, self.multiworld.state.prog_items[self.player]["rep"])