SA2B: v2.0 Content Update (#1294)

Changelog:

Features:
- Completely reworked mission progression system
  - Control of which mission types can be active per-gameplay-style
  - Control of how many missions are active per-gameplay-style
  - Mission order shuffle
- Two new Chaos Emerald Hunt goals
  - `Chaos Emerald Hunt` involves finding the seven Chaos Emeralds and beating Green Hill
  - `FinalHazard Chaos Emerald Hunt` is the same, but with the FinalHazard fight at the end of Green Hill
- New optional Location Checks
  - Keysanity (Chao Containers)
  - Whistlesanity (Animal Pipes and hidden whistle spots)
  - Beetlesanity (Destroying Gold Beetles)
- Option to require clearing all active Cannon's Core Missions for access to the Biolizard fight in `Biolizard` goal
- Hard Logic option
- More Music Options
  - Option to use SADX music
  - New `Singularity` music shuffle option
- Option to choose the Narrator theme 
- New Traps
  - Tiny Trap is now permanent within a level
  - Gravity Trap
  - Exposition Trap
  
Quality of Life:
- Significant revamp to Stage Select screen information conveyance
  - Icons are displayed for:
    - Relevant character's upgrades
    - Which location checks are active/checked
    - Chaos Emeralds found (if relevant)
    - Gate and Cannon's Core emblem costs
  - The above stage-specific info can also be viewed when paused in-level
    - The current mission is also displayed when paused
- Emblem Symbol on Mission Select subscreen now only displays if a high enough rank has been gotten on that mission to send the location check
- Hints including SA2B locations will now specify which Gate that level is located in
- Save file now stores slot name to help prevent false location checks in the case of one player having multiple SA2B slots in the same seed
- Chao Intermediate and Expert race sets are now swapped, per player feedback
  - Intermediate now includes Beginner + Challenge + Hero + Dark
  - Expert now includes Beginner + Challenge + Hero + Dark + Jewel
- New mod config option for the color of the Message Queue text

Bug Fixes:
- Fixed bug where game stops properly tracking items after 127 have been received.
- Several logic fixes
- Game now refers to `Knuckles - Shovel Claws` correctly
- Minor AP World code cleanup
This commit is contained in:
PoryGone
2022-12-07 00:20:02 -05:00
committed by GitHub
parent f5638552cc
commit 449973687b
11 changed files with 3026 additions and 669 deletions

View File

@@ -3,6 +3,27 @@ import typing
from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, OptionList
class Goal(Choice):
"""
Determines the goal of the seed
Biolizard: Finish Cannon's Core and defeat the Biolizard and Finalhazard
Chaos Emerald Hunt: Find the Seven Chaos Emeralds and reach Green Hill Zone
Finalhazard Chaos Emerald Hunt: Find the Seven Chaos Emeralds and reach Green Hill Zone, then defeat Finalhazard
"""
display_name = "Goal"
option_biolizard = 0
option_chaos_emerald_hunt = 1
option_finalhazard_chaos_emerald_hunt = 2
default = 0
class MissionShuffle(Toggle):
"""
Determines whether missions order will be shuffled per level
"""
display_name = "Mission Shuffle"
class BaseTrapWeight(Choice):
"""
Base Class for Trap Weights
@@ -42,6 +63,27 @@ class TinyTrapWeight(BaseTrapWeight):
display_name = "Tiny Trap Weight"
class GravityTrapWeight(BaseTrapWeight):
"""
Likelihood of a receiving a trap which increases gravity
"""
display_name = "Gravity Trap Weight"
class ExpositionTrapWeight(BaseTrapWeight):
"""
Likelihood of a receiving a trap which tells you the story
"""
display_name = "Exposition Trap Weight"
class DarknessTrapWeight(BaseTrapWeight):
"""
Likelihood of a receiving a trap which makes the world dark
"""
display_name = "Darkness Trap Weight"
class JunkFillPercentage(Range):
"""
Replace a percentage of non-required emblems in the item pool with random junk items
@@ -78,11 +120,41 @@ class IncludeMissions(Range):
default = 2
class Keysanity(Toggle):
"""
Determines whether picking up Chao Keys grants checks
"""
display_name = "Keysanity"
class Whistlesanity(Choice):
"""
Determines whether whistling at various spots grants checks
None: No Whistle Spots grant checks
Pipes: Whistling at Pipes grants checks
Hidden: Whistling at Hidden Whistle Spots grants checks
Both: Whistling at both Pipes and Hidden Whistle Spots grants checks
"""
display_name = "Whistlesanity"
option_none = 0
option_pipes = 1
option_hidden = 2
option_both = 3
default = 0
class Beetlesanity(Toggle):
"""
Determines whether destroying Gold Beetles grants checks
"""
display_name = "Beetlesanity"
class EmblemPercentageForCannonsCore(Range):
"""
Allows logic to gate the final mission behind a number of Emblems
"""
display_name = "Emblem Percentage for Cannons Core"
display_name = "Emblem Percentage for Cannon's Core"
range_start = 0
range_end = 75
default = 50
@@ -172,24 +244,280 @@ class ChaoRaceChecks(Choice):
default = 0
class RequiredCannonsCoreMissions(Choice):
"""
Determines how many Cannon's Core missions must be completed to unlock the Biolizard (for the "Biolizard" goal)
First: Only the first mission must be completed
All Active: All active Cannon's Core missions must be completed
"""
display_name = "Required Cannon's Core Missions"
option_first = 0
option_all_active = 1
default = 0
class BaseMissionCount(Range):
"""
Base class for mission count options
"""
range_start = 1
range_end = 5
default = 2
class SpeedMissionCount(BaseMissionCount):
"""
The number of active missions to include for Sonic and Shadow stages
"""
display_name = "Speed Mission Count"
class SpeedMission2(DefaultOnToggle):
"""
Determines if the Sonic and Shadow 100 rings missions should be included
"""
display_name = "Speed Mission 2"
class SpeedMission3(DefaultOnToggle):
"""
Determines if the Sonic and Shadow lost chao missions should be included
"""
display_name = "Speed Mission 3"
class SpeedMission4(DefaultOnToggle):
"""
Determines if the Sonic and Shadow time trial missions should be included
"""
display_name = "Speed Mission 4"
class SpeedMission5(DefaultOnToggle):
"""
Determines if the Sonic and Shadow hard missions should be included
"""
display_name = "Speed Mission 5"
class MechMissionCount(BaseMissionCount):
"""
The number of active missions to include for Tails and Eggman stages
"""
display_name = "Mech Mission Count"
class MechMission2(DefaultOnToggle):
"""
Determines if the Tails and Eggman 100 rings missions should be included
"""
display_name = "Mech Mission 2"
class MechMission3(DefaultOnToggle):
"""
Determines if the Tails and Eggman lost chao missions should be included
"""
display_name = "Mech Mission 3"
class MechMission4(DefaultOnToggle):
"""
Determines if the Tails and Eggman time trial missions should be included
"""
display_name = "Mech Mission 4"
class MechMission5(DefaultOnToggle):
"""
Determines if the Tails and Eggman hard missions should be included
"""
display_name = "Mech Mission 5"
class HuntMissionCount(BaseMissionCount):
"""
The number of active missions to include for Knuckles and Rouge stages
"""
display_name = "Hunt Mission Count"
class HuntMission2(DefaultOnToggle):
"""
Determines if the Knuckles and Rouge 100 rings missions should be included
"""
display_name = "Hunt Mission 2"
class HuntMission3(DefaultOnToggle):
"""
Determines if the Knuckles and Rouge lost chao missions should be included
"""
display_name = "Hunt Mission 3"
class HuntMission4(DefaultOnToggle):
"""
Determines if the Knuckles and Rouge time trial missions should be included
"""
display_name = "Hunt Mission 4"
class HuntMission5(DefaultOnToggle):
"""
Determines if the Knuckles and Rouge hard missions should be included
"""
display_name = "Hunt Mission 5"
class KartMissionCount(BaseMissionCount):
"""
The number of active missions to include for Route 101 and 280
"""
display_name = "Kart Mission Count"
class KartMission2(DefaultOnToggle):
"""
Determines if the Route 101 and 280 100 rings missions should be included
"""
display_name = "Kart Mission 2"
class KartMission3(DefaultOnToggle):
"""
Determines if the Route 101 and 280 avoid cars missions should be included
"""
display_name = "Kart Mission 3"
class KartMission4(DefaultOnToggle):
"""
Determines if the Route 101 and 280 avoid walls missions should be included
"""
display_name = "Kart Mission 4"
class KartMission5(DefaultOnToggle):
"""
Determines if the Route 101 and 280 hard missions should be included
"""
display_name = "Kart Mission 5"
class CannonsCoreMissionCount(BaseMissionCount):
"""
The number of active missions to include for Cannon's Core
"""
display_name = "Cannon's Core Mission Count"
class CannonsCoreMission2(DefaultOnToggle):
"""
Determines if the Cannon's Core 100 rings mission should be included
"""
display_name = "Cannon's Core Mission 2"
class CannonsCoreMission3(DefaultOnToggle):
"""
Determines if the Cannon's Core lost chao mission should be included
"""
display_name = "Cannon's Core Mission 3"
class CannonsCoreMission4(DefaultOnToggle):
"""
Determines if the Cannon's Core time trial mission should be included
"""
display_name = "Cannon's Core Mission 4"
class CannonsCoreMission5(DefaultOnToggle):
"""
Determines if the Cannon's Core hard mission should be included
"""
display_name = "Cannon's Core Mission 5"
class SADXMusic(Choice):
"""
Whether the randomizer will include Sonic Adventure DX Music in the music pool
SA2B: Only SA2B music will be played
SADX: Only SADX music will be played
Both: Both SA2B and SADX music will be played
NOTE: This option requires the player to own a PC copy of SADX and to follow the addition steps in the setup guide.
"""
display_name = "SADX Music"
option_sa2b = 0
option_sadx = 1
option_both = 2
default = 0
@classmethod
def get_option_name(cls, value) -> str:
if cls.auto_display_name and value != 2:
return cls.name_lookup[value].upper()
else:
return cls.name_lookup[value]
class MusicShuffle(Choice):
"""
What type of Music Shuffle is used
Off: No music is shuffled.
Levels: Level music is shuffled.
Full: Level, Menu, and Additional music is shuffled.
Singularity: Level, Menu, and Additional music is all replaced with a single random song.
"""
display_name = "Music Shuffle Type"
option_none = 0
option_levels = 1
option_full = 2
option_singularity = 3
default = 0
class Narrator(Choice):
"""
Which menu narrator is used
"""
display_name = "Narrator"
option_default = 0
option_shadow = 1
option_rouge = 2
option_eggman = 3
option_maria = 4
option_secretary = 5
option_omochao = 6
option_amy = 7
option_tails = 8
option_knuckles = 9
option_sonic = 10
default = 0
class LogicDifficulty(Choice):
"""
What set of Upgrade Requirement logic to use
Standard: The logic assumes the "intended" usage of Upgrades to progress through levels
Hard: Some simple skips or sequence breaks may be required
"""
display_name = "Logic Difficulty"
option_standard = 0
option_hard = 1
default = 0
sa2b_options: typing.Dict[str, type(Option)] = {
"include_missions": IncludeMissions,
"goal": Goal,
"mission_shuffle": MissionShuffle,
"keysanity": Keysanity,
"whistlesanity": Whistlesanity,
"beetlesanity": Beetlesanity,
"required_rank": RequiredRank,
"emblem_percentage_for_cannons_core": EmblemPercentageForCannonsCore,
"required_cannons_core_missions": RequiredCannonsCoreMissions,
"number_of_level_gates": NumberOfLevelGates,
"level_gate_distribution": LevelGateDistribution,
"level_gate_costs": LevelGateCosts,
@@ -202,6 +530,37 @@ sa2b_options: typing.Dict[str, type(Option)] = {
"timestop_trap_weight": TimestopTrapWeight,
"confusion_trap_weight": ConfusionTrapWeight,
"tiny_trap_weight": TinyTrapWeight,
"gravity_trap_weight": GravityTrapWeight,
"exposition_trap_weight": ExpositionTrapWeight,
#"darkness_trap_weight": DarknessTrapWeight,
"sadx_music": SADXMusic,
"music_shuffle": MusicShuffle,
"narrator": Narrator,
"logic_difficulty": LogicDifficulty,
"speed_mission_count": SpeedMissionCount,
"speed_mission_2": SpeedMission2,
"speed_mission_3": SpeedMission3,
"speed_mission_4": SpeedMission4,
"speed_mission_5": SpeedMission5,
"mech_mission_count": MechMissionCount,
"mech_mission_2": MechMission2,
"mech_mission_3": MechMission3,
"mech_mission_4": MechMission4,
"mech_mission_5": MechMission5,
"hunt_mission_count": HuntMissionCount,
"hunt_mission_2": HuntMission2,
"hunt_mission_3": HuntMission3,
"hunt_mission_4": HuntMission4,
"hunt_mission_5": HuntMission5,
"kart_mission_count": KartMissionCount,
"kart_mission_2": KartMission2,
"kart_mission_3": KartMission3,
"kart_mission_4": KartMission4,
"kart_mission_5": KartMission5,
"cannons_core_mission_count": CannonsCoreMissionCount,
"cannons_core_mission_2": CannonsCoreMission2,
"cannons_core_mission_3": CannonsCoreMission3,
"cannons_core_mission_4": CannonsCoreMission4,
"cannons_core_mission_5": CannonsCoreMission5,
"death_link": DeathLink,
}