Skip to content

Commit

Permalink
Additive suit damage reduction (#39)
Browse files Browse the repository at this point in the history
Adds an alternative option for suit damage reduction, "Additive", where
each suit gets a specific damage reduction value, and each value is
added together to determine total damage reduction. Varia and Gravity
Suits each provide +10% damage reduction, and Phazon Suit provides +30%
damage reduction.

Examples:
- Varia or Gravity Suit alone provide 10% total damage reduction
- Both Varia and Gravity Suit provide 20% total damage reduction
- Phazon Suit and one additional suit provide 40% total damage reduction

`staggeredSuitDamage` property is changed to allow "Default",
"Progressive", or "Additive" while maintaining backwards compatibility
with boolean values.
  • Loading branch information
marsolk authored May 21, 2024
1 parent 012743e commit bbf56c3
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 36 deletions.
1 change: 1 addition & 0 deletions ppcasm/ppcasm_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ decl_instrs! {
mtlr, (r:d) => (6;31) | d | (10;0x100) | (10;467) | (1;0);
mullw[o][.],(r:d), (r:a), (r:b) => (6;31) | d | a | b | (?o) | (9;235) | (?.);
nop => (32;0x60000000);
or[.], (r:d), (r:a), (r:b) => (6;31) | d | a | b | (10;444) | (?.);
ori, (r:d), (r:a), (i:imm) => (6;24) | d | a | (16;imm);
oris, (r:d), (r:a), (i:imm) => (6;25) | d | a | (16;imm);
slwi, (r:a), (r:s), (i:n) => (6;21) | s | a | (5;{#n}) | (5;0) |(5;{31 - #n}) | (1;0);
Expand Down
14 changes: 11 additions & 3 deletions schema/randomprime.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,17 @@
"default": false
},
"staggeredSuitDamage": {
"description": "Damage reduction depends on how many suits you have, not which.",
"type": "boolean",
"default": false
"description": "Configure how suit damage reduction is calculated.\n- `Default` or `false`: Based on strongest suit.\n- `Progressive` or `true`: Based on number of suits.\n- `Additive`: Individual suits provide added damage reduction.\nNOTE: boolean values are deprecated.",
"type": [
"string",
"boolean"
],
"enum": [
"Default",
"Progressive",
"Additive"
],
"default": "Default"
},
"heatDamagePerSec": {
"description": "Configure how much damage per second you take in heated rooms when you don't have the proper protection.",
Expand Down
75 changes: 70 additions & 5 deletions src/patch_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use clap::{crate_version, App, Arg};
use json_data::*;
use json_strip::strip_jsonc_comments;
use reader_writer::{FourCC, Reader};
use serde::{Deserialize, Serialize};
use serde::{
de::{Error, Visitor},
Deserialize, Deserializer, Serialize,
};
use structs::{res_id, MapaObjectVisibilityMode, ResId};

use crate::{
Expand Down Expand Up @@ -1111,6 +1114,66 @@ pub enum DifficultyBehavior {
HardOnly,
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
pub enum SuitDamageReduction {
#[default]
Default,
Progressive,
Additive,
}

impl<'de> Deserialize<'de> for SuitDamageReduction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SuitDamageReductionVisitor;

impl<'de> Visitor<'de> for SuitDamageReductionVisitor {
type Value = SuitDamageReduction;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
r#""Default", "Progressive", "Additive", true, or false"#
)
}

fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: Error,
{
if v {
Ok(SuitDamageReduction::Progressive)
} else {
Ok(SuitDamageReduction::Default)
}
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
match v {
"Default" => Ok(SuitDamageReduction::Default),
"Progressive" => Ok(SuitDamageReduction::Progressive),
"Additive" => Ok(SuitDamageReduction::Additive),
variant => Err(E::unknown_variant(
variant,
&["Default", "Progressive", "Additive"],
)),
}
}
}

deserializer.deserialize_enum(
"SuitDamageReduction",
&["Default", "Progressive", "Additive"],
SuitDamageReductionVisitor,
)
}
}

impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
Expand Down Expand Up @@ -1190,7 +1253,7 @@ pub struct PatchConfig {
pub poison_damage_per_sec: f32,
pub phazon_damage_per_sec: f32,
pub phazon_damage_modifier: PhazonDamageModifier,
pub staggered_suit_damage: bool,
pub staggered_suit_damage: SuitDamageReduction,
pub item_max_capacity: HashMap<PickupType, u32>,
pub map_default_state: MapaObjectVisibilityMode,
pub auto_enabled_elevators: bool,
Expand Down Expand Up @@ -1283,7 +1346,7 @@ struct GameConfig {
shuffle_pickup_pos_all_rooms: Option<bool>,
remove_vanilla_blast_shields: Option<bool>,
nonvaria_heat_damage: Option<bool>,
staggered_suit_damage: Option<bool>,
staggered_suit_damage: Option<SuitDamageReduction>,
heat_damage_per_sec: Option<f32>,
poison_damage_per_sec: Option<f32>,
phazon_damage_per_sec: Option<f32>,
Expand Down Expand Up @@ -1577,11 +1640,13 @@ impl PatchConfig {
"quickpatch" => patch_config.preferences.quickpatch,
"quiet" => patch_config.preferences.quiet,
"nonvaria heat damage" => patch_config.game_config.nonvaria_heat_damage,
"staggered suit damage" => patch_config.game_config.staggered_suit_damage,
"auto enabled elevators" => patch_config.game_config.auto_enabled_elevators,
"spring ball" => patch_config.game_config.spring_ball,
"warp to start" => patch_config.game_config.warp_to_start,
);
if matches.is_present("staggered suit damage") {
patch_config.game_config.staggered_suit_damage = Some(SuitDamageReduction::Default);
}

// string
if let Some(input_iso_path) = matches.value_of("input iso path") {
Expand Down Expand Up @@ -2362,7 +2427,7 @@ impl PatchConfigPrivate {
.remove_vanilla_blast_shields
.unwrap_or(false),
nonvaria_heat_damage: self.game_config.nonvaria_heat_damage.unwrap_or(false),
staggered_suit_damage: self.game_config.staggered_suit_damage.unwrap_or(false),
staggered_suit_damage: self.game_config.staggered_suit_damage.unwrap_or_default(),
heat_damage_per_sec: self.game_config.heat_damage_per_sec.unwrap_or(10.0),
poison_damage_per_sec: self.game_config.poison_damage_per_sec.unwrap_or(0.11),
phazon_damage_per_sec: self.game_config.phazon_damage_per_sec.unwrap_or(0.964),
Expand Down
93 changes: 65 additions & 28 deletions src/patches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use crate::{
CtwkConfig, CutsceneMode, DifficultyBehavior, DoorConfig, DoorOpenMode, FogConfig,
GameBanner, GenericTexture, HallOfTheEldersBombSlotCoversConfig, IsoFormat, LevelConfig,
PatchConfig, PhazonDamageModifier, PickupConfig, PlatformConfig, PlatformType, RoomConfig,
RunMode, SpecialFunctionType, Version, Visor,
RunMode, SpecialFunctionType, SuitDamageReduction, Version, Visor,
},
patcher::{PatcherState, PrimePatcher},
pickup_meta::{
Expand Down Expand Up @@ -10546,33 +10546,70 @@ fn patch_dol(
dol_patcher.ppcasm_patch(&heat_damage_patch)?;
}

if config.staggered_suit_damage {
let (patch_offset, jump_offset) = if version == Version::Pal || version == Version::NtscJ {
(0x11c, 0x1b8)
} else {
(0x128, 0x1c4)
};

let staggered_suit_damage_patch = ppcasm!(symbol_addr!("ApplyLocalDamage__13CStateManagerFRC9CVector3fRC9CVector3fR6CActorfRC11CWeaponMode", version) + patch_offset, {
lwz r3, 0x8b8(r25);
lwz r3, 0(r3);
lwz r4, 220(r3);
lwz r5, 212(r3);
addc r4, r4, r5;
lwz r5, 228(r3);
addc r4, r4, r5;
rlwinm r4, r4, 2, 0, 29;
lis r6, data@h;
addi r6, r6, data@l;
lfsx f0, r4, r6;
b { symbol_addr!("ApplyLocalDamage__13CStateManagerFRC9CVector3fRC9CVector3fR6CActorfRC11CWeaponMode", version) + jump_offset };
data:
.float 0.0;
.float 0.1;
.float 0.2;
.float 0.5;
});
dol_patcher.ppcasm_patch(&staggered_suit_damage_patch)?;
match config.staggered_suit_damage {
SuitDamageReduction::Progressive => {
let (patch_offset, jump_offset) =
if version == Version::Pal || version == Version::NtscJ {
(0x11c, 0x1b8)
} else {
(0x128, 0x1c4)
};
let staggered_suit_damage_patch = ppcasm!(symbol_addr!("ApplyLocalDamage__13CStateManagerFRC9CVector3fRC9CVector3fR6CActorfRC11CWeaponMode", version) + patch_offset, {
lwz r3, 0x8b8(r25);
lwz r3, 0(r3);
lwz r4, 220(r3);
lwz r5, 212(r3);
addc r4, r4, r5;
lwz r5, 228(r3);
addc r4, r4, r5;
rlwinm r4, r4, 2, 0, 29;
lis r6, data@h;
addi r6, r6, data@l;
lfsx f0, r4, r6;
b { symbol_addr!("ApplyLocalDamage__13CStateManagerFRC9CVector3fRC9CVector3fR6CActorfRC11CWeaponMode", version) + jump_offset };
data:
.float 0.0;
.float 0.1;
.float 0.2;
.float 0.5;
});
dol_patcher.ppcasm_patch(&staggered_suit_damage_patch)?;
}
SuitDamageReduction::Additive => {
let (patch_offset, jump_offset) =
if version == Version::Pal || version == Version::NtscJ {
(0x11c, 0x1b8)
} else {
(0x128, 0x1c4)
};
let staggered_suit_damage_patch = ppcasm!(symbol_addr!("ApplyLocalDamage__13CStateManagerFRC9CVector3fRC9CVector3fR6CActorfRC11CWeaponMode", version) + patch_offset, {
lwz r3, 0x8b8(r25);
lwz r3, 0(r3);
lwz r4, 220(r3);
lwz r5, 212(r3);
slwi r5, r5, 1;
or r4, r4, r5;
lwz r5, 228(r3);
slwi r5, r5, 2;
or r4, r4, r5;
rlwinm r4, r4, 2, 0, 29;
lis r6, data@h;
addi r6, r6, data@l;
lfsx f0, r4, r6;
b { symbol_addr!("ApplyLocalDamage__13CStateManagerFRC9CVector3fRC9CVector3fR6CActorfRC11CWeaponMode", version) + jump_offset };
data:
.float 0.0; // 000 - Power Suit
.float 0.1; // 001 - Varia Suit
.float 0.1; // 010 - Gravity Suit
.float 0.2; // 011 - Varia + Gravity Suit
.float 0.3; // 100 - Phazon Suit
.float 0.4; // 101 - Phazon + Varia Suit
.float 0.4; // 110 - Phazon + Gravity Suit
.float 0.5; // 111 - All Suits
});
dol_patcher.ppcasm_patch(&staggered_suit_damage_patch)?;
}
SuitDamageReduction::Default => {}
}

for (pickup_type, value) in &config.item_max_capacity {
Expand Down

0 comments on commit bbf56c3

Please sign in to comment.