Skip to content

Commit 36b5b12

Browse files
FelicitusNekoZach Parks
and
Zach Parks
authored
Add Bumper Stickers (#811)
* bumpstik: initial commit * bumpstik: fix game name in location obj * bumpstik: specified offset * bumpstik: forgot to call create_regions * bumpstik: fix entrance generation * bumpstik: fix completion definition * bumpstik: treasure bumper, LttP text * bumpstik: add more score-based locations * bumpstik: adjust regions * bumpstik: fill with Treasure Bumpers * bumpstik: force Treasure Bumper on last location * bumpstik: don't require Hazard Bumpers for level 4 * bumpstik: treasure bumper locations * bumpstik: formatting * bumpstik: refactor to 0.3.5 * bumpstik: Treasure bumpers are now progression * bumpstik: complete reimplementation of locations * bumpstik: implement Nothing as item * bumpstik: level 3 and 4 locations * bumpstik: correct a goal value * bumpstik: region defs need one extra treasure * bumpstik: add more starting paint cans * bumpstik: toned down final score goal * bumpstik: changing items, Hazards no longer traps * bumpstik: remove item groups * bumpstik: update self.world to self.multiworld * bumpstik: clean up item types and classes * bumpstik: add options also add traps to item pool * bumpstik: update docs * bumpstik: oops * bumpstik: add to master game list on readme * bumpstik: renaming Task Skip to Task Advance because "Task Skip" is surprisingly hard to say * bumpstik: fill with score on item gen instead of nothing (nothing is still the default filler) * bumpstik: add 18 checks * bumpstik: bump ap ver * bumpstik: add item groups * bumpstik: make helper items and traps configurable * bumpstik: make Hazard Bumper progression * bumpstik: tone final score goal down to 50K * bumpstik: 0.4.0 region update * bumpstik: clean up docs also final goal is now 50K or your score + 5000, whichever is higher * bumpstik: take datapackage out of testing mode * bumpstik: Apply suggestions from code review code changes for .apworld support Co-authored-by: Zach Parks <[email protected]> --------- Co-authored-by: Zach Parks <[email protected]>
1 parent a4e485e commit 36b5b12

File tree

8 files changed

+530
-0
lines changed

8 files changed

+530
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Currently, the following games are supported:
4646
* DLC Quest
4747
* Noita
4848
* Undertale
49+
* Bumper Stickers
4950

5051
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
5152
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled

worlds/bumpstik/Items.py

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright (c) 2022 FelicitusNeko
2+
#
3+
# This software is released under the MIT License.
4+
# https://opensource.org/licenses/MIT
5+
6+
import typing
7+
8+
from BaseClasses import Item, ItemClassification
9+
from worlds.alttp import ALTTPWorld
10+
11+
12+
class BumpStikLttPText(typing.NamedTuple):
13+
pedestal: typing.Optional[str]
14+
sickkid: typing.Optional[str]
15+
magicshop: typing.Optional[str]
16+
zora: typing.Optional[str]
17+
fluteboy: typing.Optional[str]
18+
19+
20+
LttPCreditsText = {
21+
"Nothing": BumpStikLttPText("blank space",
22+
"Forgot it at home again",
23+
"Hallucinating again",
24+
"Bucket o' Nothing for 9999.99",
25+
"King Nothing"),
26+
"Score Bonus": BumpStikLttPText("helpful hand",
27+
"Busy kid gets the point...s",
28+
"Variable conversion rate",
29+
"Stonks",
30+
"Catchy ad jingle"),
31+
"Task Advance": BumpStikLttPText("hall pass",
32+
"Faker kid skips again",
33+
"I know a way around it",
34+
"Money can fix it",
35+
"Quick! A distraction"),
36+
"Starting Turner": BumpStikLttPText("fidget spinner",
37+
"Spinning kid turns heads",
38+
"This turns things around",
39+
"Your turn to turn",
40+
"Turn turn turn"),
41+
"Reserved": BumpStikLttPText("... wuh?",
42+
"Why's this here?",
43+
"Why's this here?",
44+
"Why's this here?",
45+
"Why's this here?"),
46+
"Starting Paint Can": BumpStikLttPText("paint bucket",
47+
"Artsy kid paints again",
48+
"Your rainbow destiny",
49+
"Rainbow for sale",
50+
"Let me paint a picture"),
51+
"Booster Bumper": BumpStikLttPText("multiplier",
52+
"Math kid multiplies again",
53+
"Growing shrooms",
54+
"Investment opportunity",
55+
"In harmony with themself"),
56+
"Hazard Bumper": BumpStikLttPText("dull stone",
57+
"...I got better",
58+
"Mischief Maker",
59+
"Whoops for sale",
60+
"Stuck in a moment"),
61+
"Treasure Bumper": BumpStikLttPText("odd treasure box",
62+
"Interdimensional treasure",
63+
"Shrooms for ???",
64+
"Who knows what this is",
65+
"You get what you give"),
66+
"Rainbow Trap": BumpStikLttPText("chaos prism",
67+
"Roy G Biv in disguise",
68+
"The colors Duke! The colors",
69+
"Paint overstock",
70+
"Raise a little hell"),
71+
"Spinner Trap": BumpStikLttPText("whirlwind",
72+
"Vertigo kid gets dizzy",
73+
"The room is spinning Dave",
74+
"International sabotage",
75+
"You spin me right round"),
76+
"Killer Trap": BumpStikLttPText("broken board",
77+
"Thank you Mr Coffey",
78+
"Lethal dosage",
79+
"Assassin for hire",
80+
"Killer Queen"),
81+
}
82+
83+
84+
item_groups = {
85+
"Helpers": ["Task Advance", "Starting Turner", "Starting Paint Can"],
86+
"Targets": ["Treasure Bumper", "Booster Bumper", "Hazard Bumper"],
87+
"Traps": ["Rainbow Trap", "Spinner Trap", "Killer Trap"]
88+
}
89+
90+
91+
class BumpStikItem(Item):
92+
game = "Bumper Stickers"
93+
type: str
94+
95+
def __init__(self, name, classification, code, player):
96+
super(BumpStikItem, self).__init__(
97+
name, classification, code, player)
98+
99+
if code is None:
100+
self.type = "Event"
101+
elif name in item_groups["Traps"]:
102+
self.type = "Trap"
103+
self.classification = ItemClassification.trap
104+
elif name in item_groups["Targets"]:
105+
self.type = "Target"
106+
self.classification = ItemClassification.progression
107+
elif name in item_groups["Helpers"]:
108+
self.type = "Helper"
109+
self.classification = ItemClassification.useful
110+
else:
111+
self.type = "Other"
112+
113+
114+
offset = 595_000
115+
116+
item_table = {
117+
item: offset + x for x, item in enumerate(LttPCreditsText.keys())
118+
}
119+
120+
ALTTPWorld.pedestal_credit_texts.update({item_table[name]: f"and the {texts.pedestal}"
121+
for name, texts in LttPCreditsText.items()})
122+
ALTTPWorld.sickkid_credit_texts.update(
123+
{item_table[name]: texts.sickkid for name, texts in LttPCreditsText.items()})
124+
ALTTPWorld.magicshop_credit_texts.update(
125+
{item_table[name]: texts.magicshop for name, texts in LttPCreditsText.items()})
126+
ALTTPWorld.zora_credit_texts.update(
127+
{item_table[name]: texts.zora for name, texts in LttPCreditsText.items()})
128+
ALTTPWorld.fluteboy_credit_texts.update(
129+
{item_table[name]: texts.fluteboy for name, texts in LttPCreditsText.items()})

worlds/bumpstik/Locations.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright (c) 2022 FelicitusNeko
2+
#
3+
# This software is released under the MIT License.
4+
# https://opensource.org/licenses/MIT
5+
6+
from BaseClasses import Location
7+
8+
9+
class BumpStikLocation(Location):
10+
game = "Bumper Stickers"
11+
12+
13+
offset = 595_000
14+
15+
level1_locs = [f"{(i + 1) * 250} Points" for i in range(4)] + \
16+
[f"{(i + 1) * 500} Level Points" for i in range(4)] + \
17+
[f"{(i + 1) * 25} Level Bumpers" for i in range(3)] + \
18+
["Combo 5"]
19+
20+
level2_locs = [f"{(i + 1) * 500} Points" for i in range(4)] + \
21+
[f"{(i + 1) * 1000} Level Points" for i in range(4)] + \
22+
[f"{(i + 1) * 25} Level Bumpers" for i in range(4)] + \
23+
["Combo 5"] + ["Chain x2"]
24+
25+
level3_locs = [f"{(i + 1) * 800} Points" for i in range(4)] + \
26+
[f"{(i + 1) * 2000} Level Points" for i in range(4)] + \
27+
[f"{(i + 1) * 25} Level Bumpers" for i in range(5)] + \
28+
["Combo 5", "Combo 7"] + ["Chain x2"] + \
29+
["All Clear, 3 colors"]
30+
31+
level4_locs = [f"{(i + 1) * 1500} Points" for i in range(4)] + \
32+
[f"{(i + 1) * 3000} Level Points" for i in range(4)] + \
33+
[f"{(i + 1) * 25} Level Bumpers" for i in range(6)] + \
34+
["Combo 5", "Combo 7"] + ["Chain x2", "Chain x3"]
35+
36+
level5_locs = ["50,000+ Total Points", "Cleared all Hazards"]
37+
38+
for x, loc_list in enumerate([level1_locs, level2_locs, level3_locs, level4_locs, level5_locs]):
39+
for y, loc in enumerate(loc_list):
40+
loc_list[y] = f"Level {x + 1} - {loc}"
41+
42+
extra_locs = [f"Bonus Booster {i+1}" for i in range(5)] + \
43+
[f"Treasure Bumper {i+1}" for i in range(32)]
44+
45+
all_locs = level1_locs + level2_locs + level3_locs + level4_locs + level5_locs + extra_locs
46+
47+
location_table = {
48+
loc: offset + i for i, loc in enumerate(all_locs)
49+
}

worlds/bumpstik/Options.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (c) 2022 FelicitusNeko
2+
#
3+
# This software is released under the MIT License.
4+
# https://opensource.org/licenses/MIT
5+
6+
import typing
7+
from Options import Option, Range
8+
9+
10+
class TaskAdvances(Range):
11+
"""Task Advances allow you to skip one step of a level task. They do not restock, so use them sparingly."""
12+
display_name = "Task Advances"
13+
range_start = 0
14+
range_end = 5
15+
default = 4
16+
17+
18+
class Turners(Range):
19+
"""Turners allow you to change the direction of a Bumper. These restock when the board resets."""
20+
display_name = "Turners"
21+
range_start = 0
22+
range_end = 5
23+
default = 3
24+
25+
26+
class PaintCans(Range):
27+
"""
28+
Paint Cans allow you to change the color of a Bumper.
29+
The ones you get from the multiworld restock when the board resets; you also get one-time ones from score.
30+
"""
31+
display_name = "Paint Cans"
32+
range_start = 0
33+
range_end = 5
34+
default = 3
35+
36+
37+
class Traps(Range):
38+
"""
39+
Traps affect the board in various ways.
40+
This number indicates how many total traps will be added to the item pool.
41+
"""
42+
display_name = "Trap Count"
43+
range_start = 0
44+
range_end = 15
45+
default = 5
46+
47+
48+
class RainbowTrapWeight(Range):
49+
"""Rainbow Traps change the color of every bumper on the field."""
50+
display_name = "Rainbow Trap weight"
51+
range_start = 0
52+
range_end = 100
53+
default = 50
54+
55+
56+
class SpinnerTrapWeight(Range):
57+
"""Spinner Traps change the direction of every bumper on the field."""
58+
display_name = "Spinner Trap weight"
59+
range_start = 0
60+
range_end = 100
61+
default = 50
62+
63+
64+
class KillerTrapWeight(Range):
65+
"""Killer Traps end the current board immediately."""
66+
display_name = "Killer Trap weight"
67+
range_start = 0
68+
range_end = 100
69+
default = 0
70+
71+
72+
bumpstik_options: typing.Dict[str, type(Option)] = {
73+
"task_advances": TaskAdvances,
74+
"turners": Turners,
75+
"paint_cans": PaintCans,
76+
"trap_count": Traps,
77+
"rainbow_trap_weight": RainbowTrapWeight,
78+
"spinner_trap_weight": SpinnerTrapWeight,
79+
"killer_trap_weight": KillerTrapWeight
80+
}

worlds/bumpstik/Regions.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Copyright (c) 2022 FelicitusNeko
2+
#
3+
# This software is released under the MIT License.
4+
# https://opensource.org/licenses/MIT
5+
6+
from BaseClasses import MultiWorld, Region, Entrance
7+
from .Locations import BumpStikLocation, level1_locs, level2_locs, level3_locs, level4_locs, level5_locs, location_table
8+
9+
10+
def _generate_entrances(player: int, entrance_list: [str], parent: Region):
11+
return [Entrance(player, entrance, parent) for entrance in entrance_list]
12+
13+
14+
def create_regions(world: MultiWorld, player: int):
15+
region_map = {
16+
"Menu": level1_locs + ["Bonus Booster 1"] + [f"Treasure Bumper {i + 1}" for i in range(8)],
17+
"Level 1": level2_locs + ["Bonus Booster 2"] + [f"Treasure Bumper {i + 9}" for i in range(8)],
18+
"Level 2": level3_locs + ["Bonus Booster 3"] + [f"Treasure Bumper {i + 17}" for i in range(8)],
19+
"Level 3": level4_locs + [f"Bonus Booster {i + 4}" for i in range(2)] +
20+
[f"Treasure Bumper {i + 25}" for i in range(8)],
21+
"Level 4": level5_locs
22+
}
23+
24+
entrance_map = {
25+
"Level 1": lambda state:
26+
state.has("Booster Bumper", player, 2) and state.has("Treasure Bumper", player, 9),
27+
"Level 2": lambda state:
28+
state.has("Booster Bumper", player, 3) and state.has("Treasure Bumper", player, 17),
29+
"Level 3": lambda state:
30+
state.has("Booster Bumper", player, 4) and state.has("Treasure Bumper", player, 25),
31+
"Level 4": lambda state:
32+
state.has("Booster Bumper", player, 5) and state.has("Treasure Bumper", player, 33)
33+
}
34+
35+
for x, region_name in enumerate(region_map):
36+
region_list = region_map[region_name]
37+
region = Region(region_name, player, world)
38+
for location_name in region_list:
39+
region.locations += [BumpStikLocation(
40+
player, location_name, location_table[location_name], region)]
41+
if x < 4:
42+
region.exits += _generate_entrances(player,
43+
[f"To Level {x + 1}"], region)
44+
45+
world.regions += [region]
46+
47+
for entrance in entrance_map:
48+
connection = world.get_entrance(f"To {entrance}", player)
49+
connection.access_rule = entrance_map[entrance]
50+
connection.connect(world.get_region(entrance, player))

0 commit comments

Comments
 (0)