Skip to content

Commit

Permalink
SMW: v2.0 Content Update (ArchipelagoMW#2762)
Browse files Browse the repository at this point in the history
Changelog:

Features:
- New optional Location Checks
  - 3-Up Moons
  - Hidden 1-Ups
  - Bonus Blocks
  - Blocksanity
    - All blocks that contain coins or items are included, with the exception of:
      - Blocks in Top Secret Area & Front Door/Bowser Castle
      - Blocks that are unreachable without glitches/unreasonable movement
- New Items
  - Special Zone Clear
  - New Filler Items
    - 1 Coin
    - 5 Coins
    - 10 Coins
    - 50 Coins
  - New Trap Items
    - Reverse Trap
    - Thwimp Trap
- SFX Shuffle
- Palette Shuffle Overhaul
  - New Curated Palette can now be used for the Overworld and Level Palette Shuffle options
  - Foreground and Background Shuffle options have been merged into a single setting
- Max possible Yoshi Egg value is 255
  - UI in-game is updated to handle 3-digits
  - New `Display Received Item Popups` option: `progression_minus_yoshi_eggs`

Quality of Life:
- In-Game Indicators are now displayed on the map screen for location checks and received items
- In-level sprites are displayed upon receiving certain items
- The Camera Scroll unlocking is now only enabled on levels where it needs to be
- SMW can now handle receiving more than 255 items
- Significant World Code cleanup
  - New Options API
  - Removal of `world: MultiWorld` across the world
- The PopTracker pack now has tabs for every level/sublevel, and can automatically swap tabs while playing if connected to the server

Bug Fixes:
- Several logic tweaks/fixes

"Major credit to @TheLX5 for being the driving force for almost all of this update. We've been collaborating on design and polish of the features for the last few months, but all of the heavy lifting was all @TheLX5."
  • Loading branch information
PoryGone authored and EmilyV99 committed Apr 15, 2024
1 parent e8f2ee6 commit 13ffe97
Show file tree
Hide file tree
Showing 395 changed files with 8,444 additions and 786 deletions.
907 changes: 882 additions & 25 deletions worlds/smw/Aesthetics.py

Large diffs are not rendered by default.

268 changes: 238 additions & 30 deletions worlds/smw/Client.py

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions worlds/smw/Items.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class SMWItem(Item):

# Separate tables for each type of item.
junk_table = {
ItemName.one_coin: ItemData(0xBC0017, False),
ItemName.five_coins: ItemData(0xBC0018, False),
ItemName.ten_coins: ItemData(0xBC0019, False),
ItemName.fifty_coins: ItemData(0xBC001A, False),
ItemName.one_up_mushroom: ItemData(0xBC0001, False),
}

Expand All @@ -36,6 +40,7 @@ class SMWItem(Item):
ItemName.progressive_powerup: ItemData(0xBC000A, True),
ItemName.p_balloon: ItemData(0xBC000B, True),
ItemName.super_star_active: ItemData(0xBC000D, True),
ItemName.special_world_clear: ItemData(0xBC001B, True),
}

switch_palace_table = {
Expand All @@ -46,10 +51,12 @@ class SMWItem(Item):
}

trap_table = {
ItemName.ice_trap: ItemData(0xBC0013, False, True),
ItemName.stun_trap: ItemData(0xBC0014, False, True),
ItemName.literature_trap: ItemData(0xBC0015, False, True),
ItemName.timer_trap: ItemData(0xBC0016, False, True),
ItemName.ice_trap: ItemData(0xBC0013, False, True),
ItemName.stun_trap: ItemData(0xBC0014, False, True),
ItemName.literature_trap: ItemData(0xBC0015, False, True),
ItemName.timer_trap: ItemData(0xBC0016, False, True),
ItemName.reverse_controls_trap: ItemData(0xBC001C, False, True),
ItemName.thwimp_trap: ItemData(0xBC001D, False, True),
}

event_table = {
Expand Down
722 changes: 714 additions & 8 deletions worlds/smw/Levels.py

Large diffs are not rendered by default.

767 changes: 759 additions & 8 deletions worlds/smw/Locations.py

Large diffs are not rendered by default.

17 changes: 13 additions & 4 deletions worlds/smw/Names/ItemName.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Junk Definitions
one_up_mushroom = "1-Up Mushroom"
one_coin = "1 coin"
five_coins = "5 coins"
ten_coins = "10 coins"
fifty_coins = "50 coins"

# Collectable Definitions
yoshi_egg = "Yoshi Egg"
Expand All @@ -22,11 +26,16 @@
red_switch_palace = "Red Switch Palace"
blue_switch_palace = "Blue Switch Palace"

# Special Zone clear flag definition
special_world_clear = "Special Zone Clear"

# Trap Definitions
ice_trap = "Ice Trap"
stun_trap = "Stun Trap"
literature_trap = "Literature Trap"
timer_trap = "Timer Trap"
ice_trap = "Ice Trap"
stun_trap = "Stun Trap"
literature_trap = "Literature Trap"
timer_trap = "Timer Trap"
reverse_controls_trap = "Reverse Trap"
thwimp_trap = "Thwimp Trap"

# Other Definitions
victory = "The Princess"
Expand Down
608 changes: 608 additions & 0 deletions worlds/smw/Names/LocationName.py

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions worlds/smw/Names/TextBox.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

from BaseClasses import MultiWorld
from worlds.AutoWorld import World

import math

Expand Down Expand Up @@ -63,21 +63,23 @@ def generate_text_box(input_string):
return out_bytes


def generate_goal_text(world: MultiWorld, player: int):
def generate_goal_text(world: World):
out_array = bytearray()
if world.goal[player] == "yoshi_egg_hunt":
required_yoshi_eggs = max(math.floor(
world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1)
if world.options.goal == "yoshi_egg_hunt":
required_yoshi_eggs = world.required_egg_count
actual_yoshi_eggs = world.actual_egg_count
out_array += bytearray([0x9F, 0x9F])
out_array += string_to_bytes(" You must acquire")
out_array[-1] += 0x80
out_array += string_to_bytes(f' {required_yoshi_eggs:02} Yoshi Eggs,')
out_array += string_to_bytes(f' {required_yoshi_eggs:03} of {actual_yoshi_eggs:03}')
out_array[-1] += 0x80
out_array += string_to_bytes(f' Yoshi Eggs,')
out_array[-1] += 0x80
out_array += string_to_bytes("then return here.")
out_array[-1] += 0x80
out_array += bytearray([0x9F, 0x9F, 0x9F])
out_array += bytearray([0x9F, 0x9F])
else:
bosses_required = world.bosses_required[player].value
bosses_required = world.options.bosses_required.value
out_array += bytearray([0x9F, 0x9F])
out_array += string_to_bytes(" You must defeat")
out_array[-1] += 0x80
Expand Down
194 changes: 136 additions & 58 deletions worlds/smw/Options.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import typing
from dataclasses import dataclass

from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, OptionList
from Options import Choice, Range, Toggle, DeathLink, DefaultOnToggle, PerGameCommonOptions


class Goal(Choice):
Expand All @@ -27,11 +27,13 @@ class BossesRequired(Range):

class NumberOfYoshiEggs(Range):
"""
How many Yoshi Eggs are in the pool for Yoshi Egg Hunt
Maximum possible number of Yoshi Eggs that will be in the item pool
If fewer available locations exist in the pool than this number, the number of available locations will be used instead.
Required Percentage of Yoshi Eggs will be calculated based off of that number.
"""
display_name = "Total Number of Yoshi Eggs"
display_name = "Max Number of Yoshi Eggs"
range_start = 1
range_end = 80
range_end = 255
default = 50


Expand All @@ -52,6 +54,40 @@ class DragonCoinChecks(Toggle):
display_name = "Dragon Coin Checks"


class MoonChecks(Toggle):
"""
Whether collecting a 3-Up Moon in a level will grant a check
"""
display_name = "3up Moon Checks"


class Hidden1UpChecks(Toggle):
"""
Whether collecting a hidden 1-Up mushroom in a level will grant a check
These checks are considered cryptic as there's no actual indicator that they're in their respective places
Enable this option at your own risk
"""
display_name = "Hidden 1-Up Checks"


class BonusBlockChecks(Toggle):
"""
Whether collecting a 1-Up mushroom from a Bonus Block in a level will grant a check
"""
display_name = "Bonus Block Checks"


class Blocksanity(Toggle):
"""
Whether hitting a block with an item or coin inside will grant a check
Note that some blocks are excluded due to how the option and the game works!
Exclusion list:
* Blocks in Top Secret Area & Front Door/Bowser Castle
* Blocks that are unreachable unless you glitch your way in
"""
display_name = "Blocksanity"


class BowserCastleDoors(Choice):
"""
How the doors of Bowser's Castle behave
Expand Down Expand Up @@ -127,16 +163,6 @@ class SwapDonutGhostHouseExits(Toggle):
display_name = "Swap Donut GH Exits"


class DisplaySentItemPopups(Choice):
"""
What messages to display in-game for items sent
"""
display_name = "Display Sent Item Popups"
option_none = 0
option_all = 1
default = 1


class DisplayReceivedItemPopups(Choice):
"""
What messages to display in-game for items received
Expand All @@ -145,7 +171,18 @@ class DisplayReceivedItemPopups(Choice):
option_none = 0
option_all = 1
option_progression = 2
default = 2
option_progression_minus_yoshi_eggs = 3
default = 3


class JunkFillPercentage(Range):
"""
Replace a percentage of non-required Yoshi Eggs in the item pool with random junk items (only applicable on Yoshi Egg Hunt goal)
"""
display_name = "Junk Fill Percentage"
range_start = 0
range_end = 100
default = 0


class TrapFillPercentage(Range):
Expand Down Expand Up @@ -197,6 +234,20 @@ class TimerTrapWeight(BaseTrapWeight):
display_name = "Timer Trap Weight"


class ReverseTrapWeight(BaseTrapWeight):
"""
Likelihood of a receiving a trap which causes the controls to be reversed in the current level
"""
display_name = "Reverse Trap Weight"


class ThwimpTrapWeight(BaseTrapWeight):
"""
Likelihood of a receiving a trap which causes a Thwimp to spawn above the player
"""
display_name = "Thwimp Trap Weight"


class Autosave(DefaultOnToggle):
"""
Whether a save prompt will appear after every level
Expand Down Expand Up @@ -239,6 +290,21 @@ class MusicShuffle(Choice):
default = 0


class SFXShuffle(Choice):
"""
Shuffles almost every instance of sound effect playback
Archipelago elements that play sound effects aren't randomized
None: No SFX are shuffled
Full: Each individual SFX call has a random SFX
Singularity: The entire game uses one SFX for every SFX call
"""
display_name = "Sound Effect Shuffle"
option_none = 0
option_full = 1
option_singularity = 2
default = 0


class MarioPalette(Choice):
"""
Mario palette color
Expand All @@ -255,25 +321,32 @@ class MarioPalette(Choice):
default = 0


class ForegroundPaletteShuffle(Toggle):
"""
Whether to shuffle level foreground palettes
"""
display_name = "Foreground Palette Shuffle"


class BackgroundPaletteShuffle(Toggle):
class LevelPaletteShuffle(Choice):
"""
Whether to shuffle level background palettes
Whether to shuffle level palettes
Off: Do not shuffle palettes
On Legacy: Uses only the palette sets from the original game
On Curated: Uses custom, hand-crafted palette sets
"""
display_name = "Background Palette Shuffle"
display_name = "Level Palette Shuffle"
option_off = 0
option_on_legacy = 1
option_on_curated = 2
default = 0


class OverworldPaletteShuffle(Toggle):
class OverworldPaletteShuffle(Choice):
"""
Whether to shuffle overworld palettes
Off: Do not shuffle palettes
On Legacy: Uses only the palette sets from the original game
On Curated: Uses custom, hand-crafted palette sets
"""
display_name = "Overworld Palette Shuffle"
option_off = 0
option_on_legacy = 1
option_on_curated = 2
default = 0


class StartingLifeCount(Range):
Expand All @@ -286,34 +359,39 @@ class StartingLifeCount(Range):
default = 5



smw_options: typing.Dict[str, type(Option)] = {
"death_link": DeathLink,
"goal": Goal,
"bosses_required": BossesRequired,
"number_of_yoshi_eggs": NumberOfYoshiEggs,
"percentage_of_yoshi_eggs": PercentageOfYoshiEggs,
"dragon_coin_checks": DragonCoinChecks,
"bowser_castle_doors": BowserCastleDoors,
"bowser_castle_rooms": BowserCastleRooms,
"level_shuffle": LevelShuffle,
"exclude_special_zone": ExcludeSpecialZone,
"boss_shuffle": BossShuffle,
"swap_donut_gh_exits": SwapDonutGhostHouseExits,
#"display_sent_item_popups": DisplaySentItemPopups,
"display_received_item_popups": DisplayReceivedItemPopups,
"trap_fill_percentage": TrapFillPercentage,
"ice_trap_weight": IceTrapWeight,
"stun_trap_weight": StunTrapWeight,
"literature_trap_weight": LiteratureTrapWeight,
"timer_trap_weight": TimerTrapWeight,
"autosave": Autosave,
"early_climb": EarlyClimb,
"overworld_speed": OverworldSpeed,
"music_shuffle": MusicShuffle,
"mario_palette": MarioPalette,
"foreground_palette_shuffle": ForegroundPaletteShuffle,
"background_palette_shuffle": BackgroundPaletteShuffle,
"overworld_palette_shuffle": OverworldPaletteShuffle,
"starting_life_count": StartingLifeCount,
}
@dataclass
class SMWOptions(PerGameCommonOptions):
death_link: DeathLink
goal: Goal
bosses_required: BossesRequired
max_yoshi_egg_cap: NumberOfYoshiEggs
percentage_of_yoshi_eggs: PercentageOfYoshiEggs
dragon_coin_checks: DragonCoinChecks
moon_checks: MoonChecks
hidden_1up_checks: Hidden1UpChecks
bonus_block_checks: BonusBlockChecks
blocksanity: Blocksanity
bowser_castle_doors: BowserCastleDoors
bowser_castle_rooms: BowserCastleRooms
level_shuffle: LevelShuffle
exclude_special_zone: ExcludeSpecialZone
boss_shuffle: BossShuffle
swap_donut_gh_exits: SwapDonutGhostHouseExits
display_received_item_popups: DisplayReceivedItemPopups
junk_fill_percentage: JunkFillPercentage
trap_fill_percentage: TrapFillPercentage
ice_trap_weight: IceTrapWeight
stun_trap_weight: StunTrapWeight
literature_trap_weight: LiteratureTrapWeight
timer_trap_weight: TimerTrapWeight
reverse_trap_weight: ReverseTrapWeight
thwimp_trap_weight: ThwimpTrapWeight
autosave: Autosave
early_climb: EarlyClimb
overworld_speed: OverworldSpeed
music_shuffle: MusicShuffle
sfx_shuffle: SFXShuffle
mario_palette: MarioPalette
level_palette_shuffle: LevelPaletteShuffle
overworld_palette_shuffle: OverworldPaletteShuffle
starting_life_count: StartingLifeCount
Loading

0 comments on commit 13ffe97

Please sign in to comment.