diff --git a/patches/ips/remove_bluesuit.ips b/patches/ips/remove_bluesuit.ips new file mode 100644 index 000000000..3de77089f Binary files /dev/null and b/patches/ips/remove_bluesuit.ips differ diff --git a/patches/ips/remove_spikesuit.ips b/patches/ips/remove_spikesuit.ips new file mode 100644 index 000000000..dbaa20580 Binary files /dev/null and b/patches/ips/remove_spikesuit.ips differ diff --git a/patches/rom_map/Bank 90.txt b/patches/rom_map/Bank 90.txt index a5a383881..100fb758b 100644 --- a/patches/rom_map/Bank 90.txt +++ b/patches/rom_map/Bank 90.txt @@ -8,3 +8,4 @@ $F980 - $FA00: respin.asm $FA00 - $FC00: map_progress_maintain.asm (list of cross-area tiles to reveal) $FC00 - $FC10: Fake Lava.asm $FC10 - $FC20: vanilla_bugfixes.asm +$FC20 - $FC40: remove_spikesuit.asm \ No newline at end of file diff --git a/patches/src/remove_bluesuit.asm b/patches/src/remove_bluesuit.asm new file mode 100644 index 000000000..c6db907cc --- /dev/null +++ b/patches/src/remove_bluesuit.asm @@ -0,0 +1,15 @@ +; Removes bluesuit ability + +arch snes.cpu +lorom + +; Patch "cancel speedboosting" routine to unconditionally zero out Samus' dash counter +; (compared to vanilla game, which only does this if Samus was running). +org $91DE59 ; replace branch check of samus running momentum flag + STZ $0B3E ; zero out Samus' dash counter first + LDA $0B3C ; then check Samus running flag + BEQ merge + STZ $0B3C + +org $91DE8D +merge: \ No newline at end of file diff --git a/patches/src/remove_spikesuit.asm b/patches/src/remove_spikesuit.asm new file mode 100644 index 000000000..57693ce33 --- /dev/null +++ b/patches/src/remove_spikesuit.asm @@ -0,0 +1,30 @@ +; Removes a spikesuit state from samus + +arch snes.cpu +lorom + +!bank_90_free_space_start = $90FC20 +!bank_90_free_space_end = $90FC40 + +org $90D4B9 ; hook end of shinespark crash + jsl check_ss + nop + nop + +org !bank_90_free_space_start +check_ss: + LDA $0ACC ; Samus palette type normal? [regular shinecharge] + BNE .skip + LDA $0A68 ; special timer non zero? [can spark] + BEQ .skip + STZ $0A68 ; goodbye spikesuit + LDA #$0019 + JSL $8090CB ; play a sound effect + .skip: + + ; Run hi-jacked instructions: + LDA #$0002 + STA $0A32 + RTL + +assert pc() <= !bank_90_free_space_end \ No newline at end of file diff --git a/rust/data/presets/full-settings/Community Race Season 4.json b/rust/data/presets/full-settings/Community Race Season 4.json index f428b8cd8..a28a2b298 100644 --- a/rust/data/presets/full-settings/Community Race Season 4.json +++ b/rust/data/presets/full-settings/Community Race Season 4.json @@ -4564,6 +4564,8 @@ "map_station_reveal": "Full", "energy_free_shinesparks": false, "ultra_low_qol": false, + "disable_spikesuit": false, + "disable_bluesuit": false, "race_mode": true, "random_seed": null }, diff --git a/rust/data/presets/full-settings/Default.json b/rust/data/presets/full-settings/Default.json index a675caf91..36fe9fcd0 100644 --- a/rust/data/presets/full-settings/Default.json +++ b/rust/data/presets/full-settings/Default.json @@ -4564,6 +4564,8 @@ "door_locks_size": "Large", "map_station_reveal": "Full", "energy_free_shinesparks": false, + "disable_spikesuit": false, + "disable_bluesuit": false, "ultra_low_qol": false, "race_mode": false, "random_seed": null diff --git a/rust/maprando-game/src/lib.rs b/rust/maprando-game/src/lib.rs index bf98fb0ea..d3eee932e 100644 --- a/rust/maprando-game/src/lib.rs +++ b/rust/maprando-game/src/lib.rs @@ -66,10 +66,13 @@ pub const TECH_ID_CAN_EXTENDED_MOONDANCE: TechId = 27; pub const TECH_ID_CAN_ENEMY_STUCK_MOONFALL: TechId = 28; pub const TECH_ID_CAN_SIDE_PLATFORM_CROSS_ROOM_JUMP: TechId = 197; pub const TECH_ID_CAN_SPIKE_SUIT: TechId = 141; +pub const TECH_ID_CAN_SLOPE_SPARK: TechId = 210; +pub const TECH_ID_CAN_R_MODE_KNOCKBACK_SPARK: TechId = 213; pub const TECH_ID_CAN_ELEVATOR_CRYSTAL_FLASH: TechId = 178; pub const TECH_ID_CAN_CARRY_FLASH_SUIT: TechId = 207; pub const TECH_ID_CAN_TRICKY_CARRY_FLASH_SUIT: TechId = 142; pub const TECH_ID_CAN_HYPER_GATE_SHOT: TechId = 10001; +pub const TECH_ID_CAN_CARRY_BLUE_SUIT: TechId = 215; #[allow(clippy::type_complexity)] #[derive(Deserialize, Serialize, Clone, Debug)] diff --git a/rust/maprando-web/src/web/randomize.rs b/rust/maprando-web/src/web/randomize.rs index 1359a157e..abb5d80b5 100644 --- a/rust/maprando-web/src/web/randomize.rs +++ b/rust/maprando-web/src/web/randomize.rs @@ -95,7 +95,6 @@ fn handle_randomize_request( settings: RandomizerSettings, app_data: web::Data, ) -> Result { - let skill_settings = &settings.skill_assumption_settings; let race_mode = settings.other_settings.race_mode; let random_seed = if settings.other_settings.random_seed.is_none() || race_mode { get_random_seed() @@ -111,14 +110,6 @@ fn handle_randomize_request( rng_seed[..8].copy_from_slice(&random_seed.to_le_bytes()); let mut rng = rand::rngs::StdRng::from_seed(rng_seed); - let implicit_tech = &app_data.preset_data.tech_by_difficulty["Implicit"]; - let implicit_notables = &app_data.preset_data.notables_by_difficulty["Implicit"]; - let difficulty = DifficultyConfig::new( - skill_settings, - &app_data.game_data, - implicit_tech, - implicit_notables, - ); let difficulty_tiers = get_difficulty_tiers( &settings, &app_data.preset_data.difficulty_tiers, @@ -127,8 +118,11 @@ fn handle_randomize_request( &app_data.preset_data.notables_by_difficulty["Implicit"], ); - let filtered_base_links = - filter_links(&app_data.game_data.links, &app_data.game_data, &difficulty); + let filtered_base_links = filter_links( + &app_data.game_data.links, + &app_data.game_data, + &difficulty_tiers[0], + ); let filtered_base_links_data = LinksDataGroup::new( filtered_base_links, app_data.game_data.vertex_isv.keys.len(), diff --git a/rust/maprando-web/templates/generate/game_variations.html b/rust/maprando-web/templates/generate/game_variations.html index 8c3a44fd7..722947e34 100644 --- a/rust/maprando-web/templates/generate/game_variations.html +++ b/rust/maprando-web/templates/generate/game_variations.html @@ -67,6 +67,30 @@ +
+
+ {% include "help/variations/disable_spikesuit.html" %} + +
+
+ + + + +
+
+
+
+ {% include "help/variations/disable_bluesuit.html" %} + +
+
+ + + + +
+
{% include "help/variations/ultra_low_qol.html" %} diff --git a/rust/maprando-web/templates/generate/help/variations/disable_bluesuit.html b/rust/maprando-web/templates/generate/help/variations/disable_bluesuit.html new file mode 100644 index 000000000..9035d0a96 --- /dev/null +++ b/rust/maprando-web/templates/generate/help/variations/disable_bluesuit.html @@ -0,0 +1,25 @@ + + + + \ No newline at end of file diff --git a/rust/maprando-web/templates/generate/help/variations/disable_spikesuit.html b/rust/maprando-web/templates/generate/help/variations/disable_spikesuit.html new file mode 100644 index 000000000..1f6fdc74a --- /dev/null +++ b/rust/maprando-web/templates/generate/help/variations/disable_spikesuit.html @@ -0,0 +1,28 @@ + + + + \ No newline at end of file diff --git a/rust/maprando-web/templates/generate/scripts.html b/rust/maprando-web/templates/generate/scripts.html index 0efb93681..f6c6f8b29 100644 --- a/rust/maprando-web/templates/generate/scripts.html +++ b/rust/maprando-web/templates/generate/scripts.html @@ -301,6 +301,8 @@ "ultra_low_qol": formData.get("ultra_low_qol") == "true", "race_mode": formData.get("race_mode") == "true", "random_seed": tryParseInt(formData.get("random_seed")), + "disable_spikesuit": formData.get("disable_spike_suit") == "true", + "disable_bluesuit": formData.get("disable_blue_suit") == "true", } }; return settings; @@ -545,6 +547,8 @@ applyRadioValue("mapStationReveal", other.map_station_reveal); applyRadioValue("energyFreeShinesparks", other.energy_free_shinesparks); applyRadioValue("ultraLowQoL", other.ultra_low_qol); + applyRadioValue("disableSpikesuit", other.disable_spikesuit); + applyRadioValue("disableBluesuit", other.disable_bluesuit); applyRadioValue("raceMode", other.race_mode); document.getElementById("randomSeed").value = other.random_seed; } diff --git a/rust/maprando/src/patch.rs b/rust/maprando/src/patch.rs index 38e49856f..6b0e5333a 100644 --- a/rust/maprando/src/patch.rs +++ b/rust/maprando/src/patch.rs @@ -579,6 +579,14 @@ impl Patcher<'_> { patches.push("energy_free_shinesparks"); } + if self.settings.other_settings.disable_spikesuit { + patches.push("remove_spikesuit") + } + + if self.settings.other_settings.disable_bluesuit { + patches.push("remove_bluesuit") + } + if self.settings.quality_of_life_settings.respin { patches.push("respin"); // patches.push("spinjumprestart"); diff --git a/rust/maprando/src/randomize.rs b/rust/maprando/src/randomize.rs index 0e6d1c193..b70a7e379 100644 --- a/rust/maprando/src/randomize.rs +++ b/rust/maprando/src/randomize.rs @@ -27,15 +27,16 @@ use maprando_game::{ GameData, GrappleJumpPosition, GrappleSwingBlock, HubLocation, Item, ItemId, ItemLocationId, Link, LinksDataGroup, MainEntranceCondition, Map, NodeId, NotableId, Physics, Requirement, RoomGeometryRoomIdx, RoomId, SidePlatformEntrance, SidePlatformEnvironment, SparkPosition, - StartLocation, TECH_ID_CAN_ARTIFICIAL_MORPH, TECH_ID_CAN_CARRY_FLASH_SUIT, - TECH_ID_CAN_DISABLE_EQUIPMENT, TECH_ID_CAN_ENTER_G_MODE, TECH_ID_CAN_ENTER_G_MODE_IMMOBILE, - TECH_ID_CAN_ENTER_R_MODE, TECH_ID_CAN_GRAPPLE_JUMP, TECH_ID_CAN_GRAPPLE_TELEPORT, - TECH_ID_CAN_HEATED_G_MODE, TECH_ID_CAN_HORIZONTAL_SHINESPARK, TECH_ID_CAN_MIDAIR_SHINESPARK, - TECH_ID_CAN_MOCKBALL, TECH_ID_CAN_MOONFALL, TECH_ID_CAN_PRECISE_GRAPPLE, + StartLocation, TECH_ID_CAN_ARTIFICIAL_MORPH, TECH_ID_CAN_CARRY_BLUE_SUIT, + TECH_ID_CAN_CARRY_FLASH_SUIT, TECH_ID_CAN_DISABLE_EQUIPMENT, TECH_ID_CAN_ENTER_G_MODE, + TECH_ID_CAN_ENTER_G_MODE_IMMOBILE, TECH_ID_CAN_ENTER_R_MODE, TECH_ID_CAN_GRAPPLE_JUMP, + TECH_ID_CAN_GRAPPLE_TELEPORT, TECH_ID_CAN_HEATED_G_MODE, TECH_ID_CAN_HORIZONTAL_SHINESPARK, + TECH_ID_CAN_MIDAIR_SHINESPARK, TECH_ID_CAN_MOCKBALL, TECH_ID_CAN_MOONFALL, + TECH_ID_CAN_PRECISE_GRAPPLE, TECH_ID_CAN_R_MODE_KNOCKBACK_SPARK, TECH_ID_CAN_RIGHT_SIDE_DOOR_STUCK, TECH_ID_CAN_RIGHT_SIDE_DOOR_STUCK_FROM_WATER, TECH_ID_CAN_SAMUS_EATER_TELEPORT, TECH_ID_CAN_SHINECHARGE_MOVEMENT, - TECH_ID_CAN_SIDE_PLATFORM_CROSS_ROOM_JUMP, TECH_ID_CAN_SPEEDBALL, - TECH_ID_CAN_SPRING_BALL_BOUNCE, TECH_ID_CAN_STATIONARY_SPIN_JUMP, + TECH_ID_CAN_SIDE_PLATFORM_CROSS_ROOM_JUMP, TECH_ID_CAN_SLOPE_SPARK, TECH_ID_CAN_SPEEDBALL, + TECH_ID_CAN_SPIKE_SUIT, TECH_ID_CAN_SPRING_BALL_BOUNCE, TECH_ID_CAN_STATIONARY_SPIN_JUMP, TECH_ID_CAN_STUTTER_WATER_SHINECHARGE, TECH_ID_CAN_SUPER_SINK, TECH_ID_CAN_TEMPORARY_BLUE, TECH_ID_CAN_TRICKY_CARRY_FLASH_SUIT, TechId, TemporaryBlueDirection, TraversalId, VertexId, VertexKey, @@ -3191,12 +3192,24 @@ pub fn get_difficulty_tiers( implicit_tech: &[TechId], implicit_notables: &[(RoomId, NotableId)], ) -> Vec { - let main_tier = DifficultyConfig::new( + let mut main_tier = DifficultyConfig::new( &settings.skill_assumption_settings, game_data, implicit_tech, implicit_notables, ); + + if settings.other_settings.disable_spikesuit { + main_tier.tech[game_data.tech_isv.index_by_key[&TECH_ID_CAN_SPIKE_SUIT]] = false; + main_tier.tech[game_data.tech_isv.index_by_key[&TECH_ID_CAN_SLOPE_SPARK]] = false; + main_tier.tech[game_data.tech_isv.index_by_key[&TECH_ID_CAN_R_MODE_KNOCKBACK_SPARK]] = + false; + } + + if settings.other_settings.disable_bluesuit { + main_tier.tech[game_data.tech_isv.index_by_key[&TECH_ID_CAN_CARRY_BLUE_SUIT]] = false; + } + let mut difficulty_tiers = vec![]; difficulty_tiers.push(main_tier.clone()); diff --git a/rust/maprando/src/settings.rs b/rust/maprando/src/settings.rs index c493c7d69..a247a70c8 100644 --- a/rust/maprando/src/settings.rs +++ b/rust/maprando/src/settings.rs @@ -348,6 +348,8 @@ pub struct OtherSettings { pub map_station_reveal: MapStationReveal, pub energy_free_shinesparks: bool, pub ultra_low_qol: bool, + pub disable_spikesuit: bool, + pub disable_bluesuit: bool, pub race_mode: bool, pub random_seed: Option, } @@ -909,6 +911,14 @@ fn upgrade_other_settings(settings: &mut serde_json::Value) -> Result<()> { *area_assignment = serde_json::to_value(AreaAssignment::from_preset(preset))?; } + if other_settings.get("disable_spikesuit").is_none() { + other_settings.insert("disable_spikesuit".to_string(), false.into()); + } + + if other_settings.get("disable_bluesuit").is_none() { + other_settings.insert("disable_bluesuit".to_string(), false.into()); + } + Ok(()) } diff --git a/rust/maprando/tests/logic_scenarios.rs b/rust/maprando/tests/logic_scenarios.rs index 7472c0cf6..8f17e9fc3 100644 --- a/rust/maprando/tests/logic_scenarios.rs +++ b/rust/maprando/tests/logic_scenarios.rs @@ -252,6 +252,8 @@ fn get_settings(scenario: &Scenario) -> Result { door_locks_size: maprando::settings::DoorLocksSize::Large, map_station_reveal: maprando::settings::MapStationReveal::Full, energy_free_shinesparks: false, + disable_bluesuit: false, + disable_spikesuit: false, ultra_low_qol: false, race_mode: false, random_seed: None,