diff --git a/ppcasm/ppcasm_macro/src/lib.rs b/ppcasm/ppcasm_macro/src/lib.rs index b4b0ad2c..35176e40 100644 --- a/ppcasm/ppcasm_macro/src/lib.rs +++ b/ppcasm/ppcasm_macro/src/lib.rs @@ -372,6 +372,7 @@ decl_instrs! { addc[o][.], (r:d), (r:a), (r:b) => (6;31) | d | a | b | (?o) | (9;10) | (?.); addi, (r:d), (r:a), (i:imm) => (6;14) | d | a | (16;imm); addic[.], (r:d), (r:a), (i:imm) => (5;6) | (?.) | d | a | (16;imm); + and[.], (r:d), (r:a), (r:b) => (6;31) | d | a | b | (10;28) | (?.); andi, (r:d), (r:a), (i:imm) => (6;28) | d | a | (16;imm); andis, (r:d), (r:a), (i:imm) => (6;29) | d | a | (16;imm); b[l][a], (l:li) => (6;18) | (24;li) | (?a) | (?l); @@ -409,11 +410,16 @@ decl_instrs! { mr, (r:a), (r:s) => (6;31) | s | a | s | (10;444) | (1;0); 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) | (?.); + neg, (r:d), (r:a) => (6;31) | d | a | (16;208); nop => (32;0x60000000); + nor[.], (r:d), (r:a), (r:b) => (6;31) | d | a | b | (10;124) | (?.); + not, (r:a), (r:s) => (6;31) | s | a | s | (10;124) | (1;0); 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); + slw[.], (r:d), (r:a), (r:b) => (6;31) | d | a | b | (10;24) | (?.); slwi, (r:a), (r:s), (i:n) => (6;21) | s | a | (5;{#n}) | (5;0) |(5;{31 - #n}) | (1;0); + srw[.], (r:d), (r:a), (r:b) => (6;31) | d | a | b | (10;536) | (?.); srwi, (r:a), (r:s), (i:n) => (6;21) | s | a | (5;{32 - #n}) | (5;n) |(5;31) | (1;0); rlwimi[.], (r:a), (r:s), (i:sh), (i:mb), (i:me) => (6;20) | s | a | (5;sh) | (5;mb) |(5;me) | (?.); diff --git a/schema/randomprime.schema.json b/schema/randomprime.schema.json index 27eebd13..6fa54ccd 100644 --- a/schema/randomprime.schema.json +++ b/schema/randomprime.schema.json @@ -327,9 +327,22 @@ "type": "string" }, "springBall": { - "description": "Restores the Spring Ball feature from Metroid Prime Trilogy. Use C-Stick Up while being morphed to use Spring Ball. NOTE: You need Morph Ball Bombs to use Spring Ball just like in Metroid Prime Trilogy.", + "description": "[Deprecated] Restores the Spring Ball feature from Metroid Prime Trilogy. Use C-Stick Up while being morphed to use Spring Ball. NOTE: You need Morph Ball Bombs to use Spring Ball just like in Metroid Prime Trilogy.", "type": "boolean", - "default": false + "default": false, + "deprecated": true + }, + "springBallItem": { + "description": "Spring Ball will require this item to be obtained before being able to use it.", + "$ref": "#/$defs/pickupType", + "not": { + "enum": [ + "Nothing", + "Floaty Jump", + "Ice Trap" + ] + }, + "default": "Spring Ball" }, "warpToStart": { "description": "Refusing to save at any Save Station while holding L + R will warp you to the starting location (by default, Samus' Ship in Tallon Overworld: Landing Site)", @@ -470,9 +483,10 @@ "default": false }, "enableIceTraps": { - "description": "Set to true if Ice Traps items are used in this layout.", + "description": "[Deprecated] Does not do anything anymore", "type": "boolean", - "default": false + "default": false, + "deprecated": true }, "missileStationPbRefill": { "description": "If enabled, Missile Stations also refill Power Bomb ammunition.", @@ -2492,6 +2506,12 @@ "type": "boolean", "default": false }, + "powerSuit": { + "type": "integer", + "minimum": 0, + "maximum": 4294967295, + "default": 0 + }, "variaSuit": { "type": "boolean", "default": false @@ -2535,6 +2555,32 @@ "flamethrower": { "type": "boolean", "default": false + }, + "unknownItem1": { + "type": "integer", + "minimum": 0, + "maximum": 4294967295, + "default": 0 + }, + "unlimitedMissiles": { + "type": "boolean", + "default": false + }, + "unlimitedPowerBombs": { + "type": "boolean", + "default": false + }, + "missileLauncher": { + "type": "boolean", + "default": true + }, + "powerBombLauncher": { + "type": "boolean", + "default": true + }, + "springBall": { + "type": "boolean", + "default": false } }, "required": [ @@ -2552,6 +2598,7 @@ "bombs", "spiderBall", "boostBall", + "powerSuit", "variaSuit", "gravitySuit", "phazonSuit", @@ -2562,7 +2609,13 @@ "superMissile", "wavebuster", "iceSpreader", - "flamethrower" + "flamethrower", + "unknownItem1", + "unlimitedMissiles", + "unlimitedPowerBombs", + "missileLauncher", + "powerBombLauncher", + "springBall" ], "default": { "combatVisor": true, @@ -2579,6 +2632,7 @@ "bombs": false, "spiderBall": false, "boostBall": false, + "powerSuit": 0, "variaSuit": false, "gravitySuit": false, "phazonSuit": false, @@ -2589,7 +2643,13 @@ "superMissile": false, "wavebuster": false, "iceSpreader": false, - "flamethrower": false + "flamethrower": false, + "unknownItem1": 0, + "unlimitedMissiles": false, + "unlimitedPowerBombs": false, + "missileLauncher": true, + "powerBombLauncher": true, + "springBall": false }, "additionalProperties": false }, @@ -2693,53 +2753,7 @@ }, "type": { "description": "Defines what is acquired when the pickup is obtained.", - "type": "string", - "enum": [ - "Power Beam", - "Ice Beam", - "Wave Beam", - "Plasma Beam", - "Missile", - "Scan Visor", - "Morph Ball Bomb", - "Power Bomb", - "Flamethrower", - "Thermal Visor", - "Charge Beam", - "Super Missile", - "Grapple Beam", - "X-Ray Visor", - "Ice Spreader", - "Space Jump Boots", - "Morph Ball", - "Combat Visor", - "Boost Ball", - "Spider Ball", - "Power Suit", - "Gravity Suit", - "Varia Suit", - "Phazon Suit", - "Energy Tank", - "Unknown Item 1", - "Health Refill", - "Unknown Item 2", - "Wavebuster", - "Artifact of Truth", - "Artifact of Strength", - "Artifact of Elder", - "Artifact of Wild", - "Artifact of Lifegiver", - "Artifact of Warrior", - "Artifact of Chozo", - "Artifact of Nature", - "Artifact of Sun", - "Artifact of World", - "Artifact of Spirit", - "Artifact of Newborn", - "Nothing", - "Floaty Jump", - "Ice Trap" - ], + "$ref": "#/$defs/pickupType", "default": "Nothing" }, "scanText": { @@ -3918,51 +3932,16 @@ "default": 0 }, "itemId": { - "type": "string", - "enum": [ - "PowerBeam", - "IceBeam", - "WaveBeam", - "PlasmaBeam", - "Missile", - "ScanVisor", - "MorphBallBomb", - "PowerBomb", - "Flamethrower", - "ThermalVisor", - "ChargeBeam", - "SuperMissile", - "GrappleBeam", - "XRayVisor", - "IceSpreader", - "SpaceJumpBoots", - "MorphBall", - "CombatVisor", - "BoostBall", - "SpiderBall", - "PowerSuit", - "GravitySuit", - "VariaSuit", - "PhazonSuit", - "EnergyTank", - "UnknownItem1", - "HealthRefill", - "UnknownItem2", - "Wavebuster", - "ArtifactOfTruth", - "ArtifactOfStrength", - "ArtifactOfElder", - "ArtifactOfWild", - "ArtifactOfLifegiver", - "ArtifactOfWarrior", - "ArtifactOfChozo", - "ArtifactOfNature", - "ArtifactOfSun", - "ArtifactOfWorld", - "ArtifactOfSpirit", - "ArtifactOfNewborn" - ], - "default": "PowerBeam" + "description": "Any custom items will be stored in UnknownItem2", + "$ref": "#/$defs/pickupType", + "not": { + "enum": [ + "Nothing", + "Floaty Jump", + "Ice Trap" + ] + }, + "default": "Power Beam" }, "active": { "type": "boolean", @@ -5820,6 +5799,60 @@ "Disabled", "Enemy" ] + }, + "pickupType": { + "type": "string", + "enum": [ + "Power Beam", + "Ice Beam", + "Wave Beam", + "Plasma Beam", + "Missile", + "Scan Visor", + "Morph Ball Bomb", + "Power Bomb", + "Flamethrower", + "Thermal Visor", + "Charge Beam", + "Super Missile", + "Grapple Beam", + "X-Ray Visor", + "Ice Spreader", + "Space Jump Boots", + "Morph Ball", + "Combat Visor", + "Boost Ball", + "Spider Ball", + "Power Suit", + "Gravity Suit", + "Varia Suit", + "Phazon Suit", + "Energy Tank", + "Unknown Item 1", + "Health Refill", + "Unknown Item 2", + "Wavebuster", + "Artifact of Truth", + "Artifact of Strength", + "Artifact of Elder", + "Artifact of Wild", + "Artifact of Lifegiver", + "Artifact of Warrior", + "Artifact of Chozo", + "Artifact of Nature", + "Artifact of Sun", + "Artifact of World", + "Artifact of Spirit", + "Artifact of Newborn", + "Unlimited Missiles", + "Unlimited Power Bombs", + "Missile Launcher", + "Main Power Bomb", + "Spring Ball", + "Nothing", + "Floaty Jump", + "Ice Trap" + ] } } } \ No newline at end of file diff --git a/src/add_modify_obj_patches.rs b/src/add_modify_obj_patches.rs index 1558b605..80528e43 100644 --- a/src/add_modify_obj_patches.rs +++ b/src/add_modify_obj_patches.rs @@ -492,9 +492,9 @@ pub fn patch_add_spawn_point( varia_suit: 0, phazon_suit: 0, energy_tanks: 0, - unknown0: 0, + unknown_item_1: 0, health_refill: 0, - unknown1: 0, + unknown_item_2: 0, wavebuster: 0, default_spawn: config.default_spawn.unwrap_or(false) as u8, active: config.active.unwrap_or(true) as u8, @@ -613,9 +613,12 @@ pub fn patch_add_special_fn( area: &mut mlvl_wrapper::MlvlArea, config: SpecialFunctionConfig, ) -> Result<(), String> { - let default = "".to_string(); - let unknown0 = config.unknown1.as_ref().unwrap_or(&default); + let default_unknown0 = "".to_string(); + let unknown0 = config.unknown1.as_ref().unwrap_or(&default_unknown0); let unknown0 = string_to_cstr(unknown0.clone()); + let default_item_id = "Power Beam".to_string(); + let item_id = config.item_id.as_ref().unwrap_or(&default_item_id); + let item_id = PickupType::from_str(&item_id[..]) as u32; macro_rules! new { () => { @@ -630,7 +633,7 @@ pub fn patch_add_special_fn( unknown3: config.unknown4.unwrap_or_default(), layer_change_room_id: config.layer_change_room_id.unwrap_or(0xFFFFFFFF), layer_change_layer_id: config.layer_change_layer_id.unwrap_or(0xFFFFFFFF), - item_id: config.item_id.unwrap_or(PickupType::PowerBeam) as u32, + item_id, unknown4: config.active.unwrap_or(true) as u8, // active unknown5: config.unknown6.unwrap_or_default(), unknown6: config.spinner1.unwrap_or(0xFFFFFFFF), @@ -668,8 +671,8 @@ pub fn patch_add_special_fn( property_data.layer_change_layer_id = layer_change_layer_id } if let Some(item_id) = config.item_id { - property_data.item_id = item_id as u32 - } + property_data.item_id = PickupType::from_str(&item_id) as u32; + }; if let Some(active) = config.active { property_data.unknown4 = active as u8 } diff --git a/src/custom_assets.rs b/src/custom_assets.rs index ba8fc84a..e007112b 100644 --- a/src/custom_assets.rs +++ b/src/custom_assets.rs @@ -1367,16 +1367,14 @@ pub fn collect_game_resources<'r>( ]; looking_for.extend(custom_scan_point_deps); - if config.enable_ice_traps { - let player_freeze_deps: Vec<(u32, FourCC)> = vec![ - resource_info!("breakFreezeVisor.PART").into(), - resource_info!("Frost1TXTR.TXTR").into(), - resource_info!("75DAC95C.PART").into(), - resource_info!("zorch1_snow3.TXTR").into(), - resource_info!("C28C7348.PART").into(), - ]; - looking_for.extend(player_freeze_deps); - } + let player_freeze_deps: Vec<(u32, FourCC)> = vec![ + resource_info!("breakFreezeVisor.PART").into(), + resource_info!("Frost1TXTR.TXTR").into(), + resource_info!("75DAC95C.PART").into(), + resource_info!("zorch1_snow3.TXTR").into(), + resource_info!("C28C7348.PART").into(), + ]; + looking_for.extend(player_freeze_deps); // Dependencies read from paks and custom assets will go here // let mut found = HashMap::with_capacity(looking_for.len()); diff --git a/src/patch_config.rs b/src/patch_config.rs index 08e762ed..74ba023f 100644 --- a/src/patch_config.rs +++ b/src/patch_config.rs @@ -460,7 +460,7 @@ pub struct SpecialFunctionConfig { pub layer_change_room_id: Option, pub layer_change_layer_id: Option, - pub item_id: Option, + pub item_id: Option, pub active: Option, pub unknown6: Option, @@ -1439,7 +1439,7 @@ pub struct PatchConfig { pub starting_visor: Visor, pub starting_beam: Beam, pub escape_sequence_counts_up: bool, - pub enable_ice_traps: bool, + pub enable_ice_traps: bool, // deprecated pub missile_station_pb_refill: bool, pub door_open_mode: DoorOpenMode, @@ -2335,8 +2335,16 @@ impl PatchConfigPrivate { if !item_max_capacity.contains_key(&PickupType::EnergyTank) && !force_vanilla_layout { item_max_capacity.insert(PickupType::EnergyTank, 200); } + if !item_max_capacity.contains_key(&PickupType::UnknownItem2) { + item_max_capacity.insert(PickupType::UnknownItem2, 2147483647); + } - if item_max_capacity.contains_key(&PickupType::Nothing) + if item_max_capacity.contains_key(&PickupType::UnlimitedMissiles) + || item_max_capacity.contains_key(&PickupType::UnlimitedPowerBombs) + || item_max_capacity.contains_key(&PickupType::MissileLauncher) + || item_max_capacity.contains_key(&PickupType::PowerBombLauncher) + || item_max_capacity.contains_key(&PickupType::SpringBall) + || item_max_capacity.contains_key(&PickupType::Nothing) || item_max_capacity.contains_key(&PickupType::FloatyJump) || item_max_capacity.contains_key(&PickupType::IceTrap) { @@ -2400,9 +2408,43 @@ impl PatchConfigPrivate { Some(items) => items.clone(), None => { if force_vanilla_layout { - StartingItems::from_u64(2188378143) + // from u64 2188378143 + StartingItems { + power_beam: true, + combat_visor: true, + scan_visor: true, + missiles: 15, + energy_tanks: 0, + power_bombs: 0, + wave: false, + ice: false, + plasma: false, + charge: true, + morph_ball: true, + bombs: true, + spider_ball: false, + boost_ball: false, + power_suit: 0, + varia_suit: true, + gravity_suit: false, + phazon_suit: false, + thermal_visor: false, + xray: false, + space_jump: false, + grapple: true, + super_missile: false, + wavebuster: false, + ice_spreader: false, + flamethrower: false, + unknown_item_1: 0, + unlimited_missiles: false, + unlimited_power_bombs: false, + missile_launcher: true, + power_bomb_launcher: true, + spring_ball: false, + } } else { - StartingItems::from_u64(1) + StartingItems::default() } } } @@ -2535,7 +2577,12 @@ impl PatchConfigPrivate { let spring_ball_item = { match self.game_config.spring_ball_item.as_deref() { Some(s) => PickupType::from_str(s), - None => PickupType::MorphBallBomb, + None => PickupType::from_str({ + match spring_ball { + false => "Spring Ball", + true => "Morph Ball Bomb", + } + }), } }; @@ -2674,7 +2721,7 @@ impl PatchConfigPrivate { .unwrap_or_else(|| StartingItems::from_u64(1)), disable_item_loss: self.game_config.disable_item_loss.unwrap_or(true), escape_sequence_counts_up: self.game_config.escape_sequence_counts_up.unwrap_or(false), - enable_ice_traps: self.game_config.enable_ice_traps.unwrap_or(false), + enable_ice_traps: self.game_config.enable_ice_traps.unwrap_or(true), missile_station_pb_refill: self.game_config.missile_station_pb_refill.unwrap_or(false), door_open_mode: self .game_config diff --git a/src/patches.rs b/src/patches.rs index 9a721206..27a7c1ff 100644 --- a/src/patches.rs +++ b/src/patches.rs @@ -4173,7 +4173,6 @@ fn modify_pickups_in_mrea<'r>( let mut special_fn_artifact_layer_change_id = 0; let mut trigger_id = 0; let mut floaty_contraption_id = [0, 0, 0, 0]; - let mut special_fn_ice_trap_id = 0; let pickup_kind = pickup_type.kind(); if (29..=40).contains(&pickup_kind) { @@ -4194,10 +4193,6 @@ fn modify_pickups_in_mrea<'r>( ]; } - if pickup_type == PickupType::IceTrap { - special_fn_ice_trap_id = area.new_object_id_from_layer_id(0); - } - let four_ids = [ area.new_object_id_from_layer_id(0), area.new_object_id_from_layer_id(0), @@ -4353,27 +4348,6 @@ fn modify_pickups_in_mrea<'r>( }); } - // If this is an ice trap, insert a special function to freeze the player on picking up - // Extra dependencies for the freeze effect - // steamTxtr -> "Frost1TXTR.TXTR" - // iceTxtr -> "breakFreezeVisor.PART" - if pickup_type == PickupType::IceTrap { - let function = structs::SclyObject { - instance_id: special_fn_ice_trap_id, - property_data: structs::SpecialFunction::ice_trap_fn( - b"Ice Trap Special Function\0".as_cstr(), - ) - .into(), - connections: vec![].into(), - }; - layers[0].objects.as_mut_vec().push(function); - additional_connections.push(structs::Connection { - state: structs::ConnectionState::ARRIVED, - message: structs::ConnectionMsg::ACTION, - target_object_id: special_fn_ice_trap_id, - }); - } - if respawn || mrea_id == 0x40C548E9 { if auto_respawn_timer_id != 0 { let timer = structs::SclyObject { @@ -9807,7 +9781,6 @@ fn patch_dol( smoother_teleports: bool, skip_splash_screens: bool, escape_sequence_counts_up: bool, - enable_ice_traps: bool, uuid: Option<[u8; 16]>, shoot_in_grapple: bool, ) -> Result<(), String> { @@ -11145,8 +11118,9 @@ fn patch_dol( } // TO-DO : - // Disable spring ball on Trilogy if config.spring_ball is set to false - if config.spring_ball { + // Set spring ball item on Trilogy + if [Version::NtscJTrilogy, Version::NtscUTrilogy, Version::PalTrilogy].contains(&version) { + } else { // call compute spring ball movement #[rustfmt::skip] let call_compute_spring_ball_movement_patch = ppcasm!( @@ -11443,120 +11417,347 @@ fn patch_dol( new_text_section.extend(spring_ball_cooldown_reset_on_morph_patch.encoded_bytes()); } - if enable_ice_traps { - let switch_case_ice_trap_patch = ppcasm!(symbol_addr!("Case0_Switch_AcceptScriptMsg_CScriptSpecialFunction", version) + 33 * 4, { - .long new_text_section_end; + // custom item support + let first_custom_item_idx = -1 * (PickupType::ArtifactOfNewborn.kind() + 1) as i32; + let custom_item_initialize_power_up_hook = ppcasm!(symbol_addr!("InitializePowerUp__12CPlayerStateFQ212CPlayerState9EItemTypei", version) + 0x1c, { + b { new_text_section_end }; + }); + dol_patcher.ppcasm_patch(&custom_item_initialize_power_up_hook)?; + + let custom_item_initialize_power_up_patch = ppcasm!(new_text_section_end, { + mr r29, r4; + mr r14, r5; + lis r15, { symbol_addr!("CPlayerState_PowerUpMaxValues", version) }@h; + addi r15, r15, { symbol_addr!("CPlayerState_PowerUpMaxValues", version) }@l; + + // add to item total if pickup isn't disappearing + lwz r3, 0x14(r1); + lwz r3, 0x26c(r3); + cmpwi r3, 0; + bne check_custom_item; + li r3, { PickupType::PowerSuit.kind() }; + rlwinm r0, r3, 0x3, 0x0, 0x1c; + add r3, r31, r0; + addi r3, r3, 0x28; + lwz r4, 0x4(r3); + addi r4, r4, 1; + stw r4, 0x4(r3); + + // add/remove custom item to unknown item 2 + check_custom_item: + cmpwi r29, { PickupType::ArtifactOfNewborn.kind() }; + ble continue_init_power_up; + li r3, { PickupType::UnknownItem2.kind() }; + rlwinm r0, r3, 0x3, 0x0, 0x1c; + add r3, r31, r0; + addi r3, r3, 0x2c; + li r4, { first_custom_item_idx }; + add r4, r4, r29; + li r0, 1; + slw r0, r4, r4; + lwz r0, 0x0(r3); + cmpwi r14, 0; + blt remove_custom_item; + or r0, r4, r4; + b set_custom_item; + remove_custom_item: + not r4, r4; + and r0, r4, r4; + set_custom_item: + stw r4, 0x0(r3); + + // check if it is missile launcher + cmpwi r29, { PickupType::MissileLauncher.kind() }; + bne check_power_bomb; + li r3, { PickupType::Missile.kind() }; + lwz r0, { PickupType::Missile.kind() * 4 }(r15); + b incr_capacity; + + // check if it is power bomb launcher + check_power_bomb: + cmpwi r29, { PickupType::PowerBombLauncher.kind() }; + bne check_ice_trap; + li r3, { PickupType::PowerBomb.kind() }; + lwz r0, { PickupType::PowerBomb.kind() * 4 }(r15); + b incr_capacity; + + // check if it is ice trap + check_ice_trap: + cmpwi r29, { PickupType::IceTrap.kind() }; + bne continue_init_power_up; + mr r16, r5; + lwz r3, 0x84c(r25); + mr r4, r25; + lis r5, 0x6FC0; + ori r5, r5, 0x3D46; + li r6, 0xC34; + lis r7, 0x2B75; + ori r7, r7, 0x7945; + bl { symbol_addr!("Freeze__7CPlayerFR13CStateManagerUiUsUi", version) }; + lis r5, data@h; + addi r5, r5, data@l; + lfs f14, 0x0(r5); + lwz r5, 0x8b8(r25); + lwz r5, 0x0(r5); + lfs f15, 0x0c(r5); + fsubs f15, f15, f14; + stfs f15, 0x0c(r5); + fcmpu cr0, f15, f28; + bgt not_dead_from_ice_trap; + lwz r4, 0x0(r5); + andis r4, r4, 0x7fff; + stw r4, 0x0(r5); + not_dead_from_ice_trap: + b end_init_power_up; + + // check for max capacity + incr_capacity: + rlwinm r0, r3, 0x3, 0x0, 0x1c; + add r3, r31, r0; + addi r3, r3, 0x28; + lwz r4, 0x4(r3); + add r4, r4, r14; + cmpw r4, r0; + ble incr_capacity_check_for_negative; + mr r4, r0; + b incr_capacity_set_capacity; + incr_capacity_check_for_negative: + cmpwi r4, 0; + bge incr_capacity_set_capacity; + li r4, 0; + incr_capacity_set_capacity: + stw r4, 0x4(r3); + + // check for max amount + lwz r4, 0x0(r3); + add r4, r4, r14; + lwz r0, 0x4(r3); + cmpw r4, r0; + ble incr_amount_check_for_negative; + mr r4, r0; + b incr_amount_set_amount; + incr_amount_check_for_negative: + cmpwi r4, 0; + bge incr_amount_set_amount; + li r4, 0; + incr_amount_set_amount: + stw r4, 0x0(r3); + + end_init_power_up: + mr r5, r14; + andi r14, r14, 0; + andi r15, r15, 0; + andi r16, r16, 0; + fmr f14, f28; + fmr f15, f28; + b { symbol_addr!("InitializePowerUp__12CPlayerStateFQ212CPlayerState9EItemTypei", version) + 0x108 }; + + // restore previous context + continue_init_power_up: + mr r5, r14; + andi r14, r14, 0; + andi r15, r15, 0; + andi r16, r16, 0; + fmr f14, f28; + fmr f15, f28; + cmpwi r29, 0; + b { symbol_addr!("InitializePowerUp__12CPlayerStateFQ212CPlayerState9EItemTypei", version) + 0x20 }; + data: + .float 75.0; }); - dol_patcher.ppcasm_patch(&switch_case_ice_trap_patch)?; - - if version == Version::NtscJ || version == Version::Pal { - let ice_trap_special_func_patch = ppcasm!(new_text_section_end, { - // backup return to case 0 - lwz r16, 0x0(r3); - // if message not Action then return - cmpwi r29, 19; - bne { new_text_section_end + 0x8c }; - // backup "this" pointer - mr r14, r3; - mr r15, r5; - - // function body - lwz r3, 0x84c(r25); - mr r4, r25; - lis r5, 0x6FC0; - ori r5, r5, 0x3D46; - li r6, 0xC34; - lis r7, 0x2B75; - ori r7, r7, 0x7945; - bl { symbol_addr!("Freeze__7CPlayerFR13CStateManagerUiUsUi", version) }; - lis r5, data@h; - addi r5, r5, data@l; - lfs f14, 0x0(r5); - lwz r5, 0x8b8(r25); - lwz r5, 0x0(r5); - lfs f15, 0x0c(r5); - fsubs f15, f15, f14; - stfs f15, 0x0c(r5); - fcmpu cr0, f15, f28; - bgt { new_text_section_end + 0x68 }; - lwz r4, 0x0(r5); - andis r4, r4, 0x7fff; - stw r4, 0x0(r5); - - // restore registers - fmr f14, f28; - fmr f15, f28; - mr r3, r14; - andi r14, r14, 0; - mr r4, r28; - mr r5, r15; - andi r15, r15, 0; - mr r6, r25; - mr r7, r25; - mtlr r16; - andi r16, r16, 0; - blr; - data: - .float 75.0; - }); - new_text_section_end += ice_trap_special_func_patch.encoded_bytes().len() as u32; - new_text_section.extend(ice_trap_special_func_patch.encoded_bytes()); - } else { - let ice_trap_special_func_patch = ppcasm!(new_text_section_end, { - // backup return to case 0 - lwz r16, 0x0(r3); - // if message not Action then return - cmpwi r28, 19; - bne { new_text_section_end + 0x8c }; - // backup "this" pointer - mr r14, r3; - mr r15, r5; - - // function body - lwz r3, 0x84c(r25); - mr r4, r25; - lis r5, 0x6FC0; - ori r5, r5, 0x3D46; - li r6, 0xC34; - lis r7, 0x2B75; - ori r7, r7, 0x7945; - bl { symbol_addr!("Freeze__7CPlayerFR13CStateManagerUiUsUi", version) }; - lis r5, data@h; - addi r5, r5, data@l; - lfs f14, 0x0(r5); - lwz r5, 0x8b8(r25); - lwz r5, 0x0(r5); - lfs f15, 0x0c(r5); - fsubs f15, f15, f14; - stfs f15, 0x0c(r5); - fcmpu cr0, f15, f28; - bgt { new_text_section_end + 0x68 }; - lwz r4, 0x0(r5); - andis r4, r4, 0x7fff; - stw r4, 0x0(r5); - - // restore registers - fmr f14, f28; - fmr f15, f28; - mr r3, r14; - andi r14, r14, 0; - mr r4, r28; - mr r5, r15; - andi r15, r15, 0; - mr r6, r25; - mr r7, r25; - mtlr r16; - andi r16, r16, 0; - blr; - data: - .float 75.0; - }); + new_text_section_end += custom_item_initialize_power_up_patch.encoded_bytes().len() as u32; + new_text_section.extend(custom_item_initialize_power_up_patch.encoded_bytes()); - new_text_section_end += ice_trap_special_func_patch.encoded_bytes().len() as u32; - new_text_section.extend(ice_trap_special_func_patch.encoded_bytes()); - } - } + let custom_item_has_power_up_hook = ppcasm!(symbol_addr!("HasPowerUp__12CPlayerStateCFQ212CPlayerState9EItemType", version), { + b { new_text_section_end }; + }); + dol_patcher.ppcasm_patch(&custom_item_has_power_up_hook)?; + let custom_item_has_power_up_patch = ppcasm!(new_text_section_end, { + // check custom item in unknown item 2 + cmpwi r4, { PickupType::ArtifactOfNewborn.kind() }; + ble { new_text_section_end + 0x30 }; + li r15, { PickupType::UnknownItem2.kind() }; + rlwinm r0, r15, 0x3, 0x0, 0x1c; + add r15, r3, r0; + addi r15, r15, 0x2c; + li r3, { first_custom_item_idx }; + add r3, r3, r4; + lwz r0, 0x0(r15); + srw r0, r3, r3; + andi r15, r15, 0; + blr; + + // restore previous context + andi r15, r15, 0; + cmpwi r4, 0; + b { symbol_addr!("HasPowerUp__12CPlayerStateCFQ212CPlayerState9EItemType", version) + 0x4 }; + }); + + new_text_section_end += custom_item_has_power_up_patch.encoded_bytes().len() as u32; + new_text_section.extend(custom_item_has_power_up_patch.encoded_bytes()); + + let custom_item_get_item_amount_hook = ppcasm!(symbol_addr!("GetItemAmount__12CPlayerStateCFQ212CPlayerState9EItemType", version), { + b { new_text_section_end }; + }); + dol_patcher.ppcasm_patch(&custom_item_get_item_amount_hook)?; + let custom_item_get_item_amount_patch = ppcasm!(new_text_section_end, { + // backup arguments + mr r14, r3; + + // preload unknown item 2 for future checks in the function + li r15, { PickupType::UnknownItem2.kind() }; + rlwinm r0, r15, 0x3, 0x0, 0x1c; + add r15, r3, r0; + addi r15, r15, 0x2c; + lwz r15, 0x0(r15); + + cmpwi r4, { PickupType::Missile.kind() }; + bne { new_text_section_end + 0x40 }; + // check for missile launcher + andi r15, r3, { PickupType::MissileLauncher.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x68 }; + // check for unlimited missiles + andi r15, r3, { PickupType::UnlimitedMissiles.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x78 }; + li r3, 255; + b { new_text_section_end + 0x6c }; + + cmpwi r4, { PickupType::PowerBomb.kind() }; + bne { new_text_section_end + 0x78 }; + // check for power bomb launcher + andi r15, r3, { PickupType::PowerBombLauncher.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x68 }; + // check for unlimited power bombs + andi r15, r3, { PickupType::UnlimitedPowerBombs.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x78 }; + li r3, 8; + b { new_text_section_end + 0x6c }; + + li r3, 0; + + andi r14, r14, 0; + andi r15, r15, 0; + blr; + + // restore previous context + mr r3, r14; + andi r14, r14, 0; + andi r15, r15, 0; + cmpwi r4, 0; + b { symbol_addr!("GetItemAmount__12CPlayerStateCFQ212CPlayerState9EItemType", version) + 0x4 }; + }); + + new_text_section_end += custom_item_get_item_amount_patch.encoded_bytes().len() as u32; + new_text_section.extend(custom_item_get_item_amount_patch.encoded_bytes()); + + let custom_item_get_item_capacity_hook = ppcasm!(symbol_addr!("GetItemCapacity__12CPlayerStateCFQ212CPlayerState9EItemType", version), { + b { new_text_section_end }; + }); + dol_patcher.ppcasm_patch(&custom_item_get_item_capacity_hook)?; + let custom_item_get_item_capacity_patch = ppcasm!(new_text_section_end, { + // backup arguments + mr r14, r3; + + // preload unknown item 2 for future checks in the function + li r15, { PickupType::UnknownItem2.kind() }; + rlwinm r0, r15, 0x3, 0x0, 0x1c; + add r15, r3, r0; + addi r15, r15, 0x2c; + lwz r15, 0x0(r15); + + cmpwi r4, { PickupType::Missile.kind() }; + bne { new_text_section_end + 0x40 }; + // check for missile launcher + andi r15, r3, { PickupType::MissileLauncher.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x68 }; + // check for unlimited missiles + andi r15, r3, { PickupType::UnlimitedMissiles.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x78 }; + li r3, 255; + b { new_text_section_end + 0x6c }; + + cmpwi r4, { PickupType::PowerBomb.kind() }; + bne { new_text_section_end + 0x78 }; + // check for power bomb launcher + andi r15, r3, { PickupType::PowerBombLauncher.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x68 }; + // check for unlimited power bombs + andi r15, r3, { PickupType::UnlimitedPowerBombs.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x78 }; + li r3, 8; + b { new_text_section_end + 0x6c }; + + li r3, 0; + + andi r14, r14, 0; + andi r15, r15, 0; + blr; + + // restore previous context + mr r3, r14; + andi r14, r14, 0; + andi r15, r15, 0; + cmpwi r4, 0; + b { symbol_addr!("GetItemCapacity__12CPlayerStateCFQ212CPlayerState9EItemType", version) + 0x4 }; + }); + + new_text_section_end += custom_item_get_item_capacity_patch.encoded_bytes().len() as u32; + new_text_section.extend(custom_item_get_item_capacity_patch.encoded_bytes()); + + let custom_item_decr_pickup_hook = ppcasm!(symbol_addr!("DecrPickUp__12CPlayerStateFQ212CPlayerState9EItemTypei", version), { + b { new_text_section_end }; + }); + dol_patcher.ppcasm_patch(&custom_item_decr_pickup_hook)?; + let custom_item_decr_pickup_patch = ppcasm!(new_text_section_end, { + // backup arguments + mr r14, r3; + + // preload unknown item 2 for future checks in the function + li r15, { PickupType::UnknownItem2.kind() }; + rlwinm r0, r15, 0x3, 0x0, 0x1c; + add r15, r3, r0; + addi r15, r15, 0x2c; + lwz r15, 0x0(r15); + + cmpwi r4, { PickupType::Missile.kind() }; + bne { new_text_section_end + 0x30 }; + // check for unlimited missiles + andi r15, r3, { PickupType::UnlimitedMissiles.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x54 }; + b { new_text_section_end + 0x48 }; + + cmpwi r4, { PickupType::PowerBomb.kind() }; + bne { new_text_section_end + 0x54 }; + // check for unlimited power bombs + andi r15, r3, { PickupType::UnlimitedPowerBombs.custom_item_value() }; + cmpwi r3, 0; + beq { new_text_section_end + 0x54 }; + b { new_text_section_end + 0x48 }; + + andi r14, r14, 0; + andi r15, r15, 0; + blr; + + // restore previous context + mr r3, r14; + andi r14, r14, 0; + andi r15, r15, 0; + cmpwi r4, 0; + b { symbol_addr!("DecrPickUp__12CPlayerStateFQ212CPlayerState9EItemTypei", version) + 0x4 }; + }); + + new_text_section_end += custom_item_decr_pickup_patch.encoded_bytes().len() as u32; + new_text_section.extend(custom_item_decr_pickup_patch.encoded_bytes()); // restore chest vulnerability to missile and charged shot, also wavebuster cheese works too if [Version::Pal, Version::NtscJ].contains(&version) { @@ -12451,9 +12652,9 @@ fn patch_final_boss_permadeath<'r>( varia_suit: 0, phazon_suit: 0, energy_tanks: 0, - unknown0: 0, + unknown_item_1: 0, health_refill: 0, - unknown1: 0, + unknown_item_2: 0, wavebuster: 0, default_spawn: 0, active: 1, @@ -13377,9 +13578,9 @@ fn patch_add_dock_teleport<'r>( varia_suit: 0, phazon_suit: 0, energy_tanks: 0, - unknown0: 0, + unknown_item_1: 0, health_refill: 0, - unknown1: 0, + unknown_item_2: 0, wavebuster: 0, default_spawn: 0, active: 1, @@ -16146,11 +16347,9 @@ fn build_and_run_patches<'r>( let mut patcher = PrimePatcher::new(); // Add the freeze effect assets required by CPlayer::Freeze() - if config.enable_ice_traps { - patcher.add_file_patch(b"GGuiSys.pak", |file| { - add_player_freeze_assets(file, game_resources) - }); - } + patcher.add_file_patch(b"GGuiSys.pak", |file| { + add_player_freeze_assets(file, game_resources) + }); // Add the pickup icon patcher.add_file_patch(b"GGuiSys.pak", |file| add_map_pickup_icon_txtr(file)); @@ -17082,6 +17281,11 @@ fn build_and_run_patches<'r>( pickups[idx].clone() // TODO: cloning is suboptimal } }; + + if pickup.pickup_type == "Unknown Item 2" { + panic!("Unknown Item 2 is no more possible to be used directly. If you wish to use custom items then specify their type instead!"); + } + let show_icon = pickup.show_icon.unwrap_or(false); let key = PickupHashKey { @@ -17109,12 +17313,6 @@ fn build_and_run_patches<'r>( } }; - if !config.enable_ice_traps - && PickupType::from_str(&pickup.pickup_type) == PickupType::IceTrap - { - panic!("EnableIceTraps must be true if you are placing Ice Trap pickups"); - } - // modify pickup, connections, hudmemo etc. patcher.add_scly_patch( (pak_name.as_bytes(), room_info.room_id.to_u32()), @@ -17193,12 +17391,6 @@ fn build_and_run_patches<'r>( } }; - if !config.enable_ice_traps - && PickupType::from_str(&pickup.pickup_type) == PickupType::IceTrap - { - panic!("EnableIceTraps must be true if you are placing Ice Trap pickups"); - } - patcher.add_scly_patch( (pak_name.as_bytes(), room_info.room_id.to_u32()), move |_ps, area| { @@ -17675,7 +17867,6 @@ fn build_and_run_patches<'r>( true, config.skip_splash_screens, config.escape_sequence_counts_up, - config.enable_ice_traps, config.uuid, config.shoot_in_grapple, ) @@ -17696,7 +17887,6 @@ fn build_and_run_patches<'r>( false, config.skip_splash_screens, config.escape_sequence_counts_up, - config.enable_ice_traps, config.uuid, config.shoot_in_grapple, ) diff --git a/src/pickup_meta.rs b/src/pickup_meta.rs index 27046717..1f39df84 100644 --- a/src/pickup_meta.rs +++ b/src/pickup_meta.rs @@ -38,7 +38,7 @@ pub enum PickupType { EnergyTank, UnknownItem1, HealthRefill, - UnknownItem2, + UnknownItem2, // now used for custom items Wavebuster, ArtifactOfTruth, ArtifactOfStrength, @@ -52,6 +52,11 @@ pub enum PickupType { ArtifactOfWorld, ArtifactOfSpirit, ArtifactOfNewborn, + UnlimitedMissiles, + UnlimitedPowerBombs, + MissileLauncher, + PowerBombLauncher, + SpringBall, Nothing, FloatyJump, IceTrap, @@ -101,6 +106,11 @@ impl PickupType { PickupType::ArtifactOfWorld => "Artifact Of World", PickupType::ArtifactOfSpirit => "Artifact Of Spirit", PickupType::ArtifactOfNewborn => "Artifact Of Newborn", + PickupType::UnlimitedMissiles => "Unlimited Missiles", + PickupType::UnlimitedPowerBombs => "Unlimited Power Bombs", + PickupType::MissileLauncher => "Missile Launcher", + PickupType::PowerBombLauncher => "Main Power Bomb", + PickupType::SpringBall => "Spring Ball", PickupType::Nothing => "Nothing", PickupType::FloatyJump => "Floaty Jump", PickupType::IceTrap => "Ice Trap", @@ -150,6 +160,11 @@ impl PickupType { PickupType::ArtifactOfWorld, PickupType::ArtifactOfSpirit, PickupType::ArtifactOfNewborn, + PickupType::UnlimitedMissiles, + PickupType::UnlimitedPowerBombs, + PickupType::MissileLauncher, + PickupType::PowerBombLauncher, + PickupType::SpringBall, PickupType::Nothing, PickupType::FloatyJump, PickupType::IceTrap, @@ -161,11 +176,19 @@ impl PickupType { pub fn kind(&self) -> u32 { match self { PickupType::FloatyJump => PickupType::Nothing.kind(), - PickupType::IceTrap => PickupType::Nothing.kind(), _ => *self as u32, } } + pub fn custom_item_value(&self) -> i32 + { + if self.kind() <= PickupType::ArtifactOfNewborn.kind() || self.kind() >= PickupType::Nothing.kind() { + panic!("PickupType needs to be a custom item to return a custom item value"); + } + + 2_i32.pow(self.kind() - PickupType::ArtifactOfNewborn.kind() - 1) as i32 + } + #[allow(clippy::should_implement_trait)] pub fn from_str(string: &str) -> Self { let string = string.to_lowercase(); @@ -261,6 +284,11 @@ pub fn pickup_type_for_pickup(pickup: &structs::Pickup) -> Option { 36 => Some(PickupType::ArtifactOfNature), 30 => Some(PickupType::ArtifactOfStrength), 26 if pickup.curr_increase == 20 => Some(PickupType::HealthRefill), + 41 => Some(PickupType::UnlimitedMissiles), + 42 => Some(PickupType::UnlimitedPowerBombs), + 43 => Some(PickupType::MissileLauncher), + 44 => Some(PickupType::PowerBombLauncher), + 47 => Some(PickupType::IceTrap), _ => None, } } @@ -306,6 +334,11 @@ pub fn pickup_model_for_pickup(pickup: &structs::Pickup) -> Option 36 => Some(PickupModel::ArtifactOfNature), 30 => Some(PickupModel::ArtifactOfStrength), 26 if pickup.curr_increase == 20 => Some(PickupModel::HealthRefill), + 41 => Some(PickupModel::MissileRefill), + 42 => Some(PickupModel::PowerBombRefill), + 43 => Some(PickupModel::Missile), + 44 => Some(PickupModel::PowerBomb), + 47 => Some(PickupModel::IceTrap), _ => None, } } @@ -569,6 +602,11 @@ impl PickupModel { PickupType::ArtifactOfWorld => PickupModel::ArtifactOfWorld, PickupType::ArtifactOfSpirit => PickupModel::ArtifactOfSpirit, PickupType::ArtifactOfNewborn => PickupModel::ArtifactOfNewborn, + PickupType::UnlimitedMissiles => PickupModel::MissileRefill, + PickupType::UnlimitedPowerBombs => PickupModel::PowerBombRefill, + PickupType::MissileLauncher => PickupModel::Missile, + PickupType::PowerBombLauncher => PickupModel::PowerBomb, + PickupType::SpringBall => PickupModel::RandovaniaGamecube, PickupType::Nothing => PickupModel::Nothing, PickupType::FloatyJump => PickupModel::RandovaniaGamecube, PickupType::IceTrap => PickupModel::IceTrap, diff --git a/src/pickup_meta.rs.in b/src/pickup_meta.rs.in index 4c1adef0..adc7e9ff 100644 --- a/src/pickup_meta.rs.in +++ b/src/pickup_meta.rs.in @@ -10359,6 +10359,11 @@ impl PickupType PickupType::ArtifactOfWorld => "audio/jin_artifact.dsp\0", PickupType::ArtifactOfSpirit => "audio/jin_artifact.dsp\0", PickupType::ArtifactOfNewborn => "audio/jin_artifact.dsp\0", + PickupType::UnlimitedMissiles => "/audio/itm_x_short_02.dsp\0", + PickupType::UnlimitedPowerBombs => "/audio/itm_x_short_02.dsp\0", + PickupType::MissileLauncher => "audio/jin_itemattain.dsp\0", + PickupType::PowerBombLauncher => "audio/jin_itemattain.dsp\0", + PickupType::SpringBall => "audio/jin_itemattain.dsp\0", PickupType::Nothing => "/audio/itm_x_short_02.dsp\0", PickupType::FloatyJump => "/audio/itm_x_short_02.dsp\0", PickupType::IceTrap => "/audio/evt_x_event_00.dsp\0", // being a bit trolly here diff --git a/src/starting_items.rs b/src/starting_items.rs index a15f6c7d..a9176f93 100644 --- a/src/starting_items.rs +++ b/src/starting_items.rs @@ -1,3 +1,5 @@ +use crate::pickup_meta::PickupType; + use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -17,6 +19,7 @@ pub struct StartingItems { pub bombs: bool, pub spider_ball: bool, pub boost_ball: bool, + pub power_suit: u32, pub varia_suit: bool, pub gravity_suit: bool, pub phazon_suit: bool, @@ -28,6 +31,12 @@ pub struct StartingItems { pub wavebuster: bool, pub ice_spreader: bool, pub flamethrower: bool, + pub unknown_item_1: u32, + pub unlimited_missiles: bool, + pub unlimited_power_bombs: bool, + pub missile_launcher: bool, + pub power_bomb_launcher: bool, + pub spring_ball: bool, } impl StartingItems { @@ -53,6 +62,7 @@ impl StartingItems { bombs: fetch_bits(1) == 1, spider_ball: fetch_bits(1) == 1, boost_ball: fetch_bits(1) == 1, + power_suit: 0, varia_suit: fetch_bits(1) == 1, gravity_suit: fetch_bits(1) == 1, phazon_suit: fetch_bits(1) == 1, @@ -64,6 +74,12 @@ impl StartingItems { wavebuster: fetch_bits(1) == 1, ice_spreader: fetch_bits(1) == 1, flamethrower: fetch_bits(1) == 1, + unknown_item_1: 0, + unlimited_missiles: false, + unlimited_power_bombs: false, + missile_launcher: true, + power_bomb_launcher: true, + spring_ball: false, } } @@ -82,6 +98,7 @@ impl StartingItems { spawn_point.bombs = self.bombs as u32; spawn_point.spider_ball = self.spider_ball as u32; spawn_point.boost_ball = self.boost_ball as u32; + spawn_point.power_suit = 0; spawn_point.varia_suit = self.varia_suit as u32; spawn_point.gravity_suit = self.gravity_suit as u32; spawn_point.phazon_suit = self.phazon_suit as u32; @@ -93,6 +110,24 @@ impl StartingItems { spawn_point.wavebuster = self.wavebuster as u32; spawn_point.ice_spreader = self.ice_spreader as u32; spawn_point.flamethrower = self.flamethrower as u32; + spawn_point.unknown_item_1 = self.unknown_item_1 as u32; + let mut unknown_item_2 = 0; + if self.unlimited_missiles { + unknown_item_2 |= PickupType::UnlimitedMissiles.custom_item_value(); + } + if self.unlimited_power_bombs { + unknown_item_2 |= PickupType::UnlimitedPowerBombs.custom_item_value(); + } + if self.missile_launcher { + unknown_item_2 |= PickupType::MissileLauncher.custom_item_value(); + } + if self.power_bomb_launcher { + unknown_item_2 |= PickupType::PowerBombLauncher.custom_item_value(); + } + if self.spring_ball { + unknown_item_2 |= PickupType::SpringBall.custom_item_value(); + } + spawn_point.unknown_item_2 = unknown_item_2 as u32; } /// Custom deserializataion function that accepts an int as well as the usual struct/object @@ -140,6 +175,11 @@ impl StartingItems { && !self.wavebuster && !self.ice_spreader && !self.flamethrower + && !self.unlimited_missiles + && !self.unlimited_power_bombs + && !self.missile_launcher + && !self.power_bomb_launcher + && !self.spring_ball } } @@ -160,6 +200,7 @@ impl Default for StartingItems { bombs: false, spider_ball: false, boost_ball: false, + power_suit: 0, varia_suit: false, gravity_suit: false, phazon_suit: false, @@ -171,6 +212,12 @@ impl Default for StartingItems { wavebuster: false, ice_spreader: false, flamethrower: false, + unknown_item_1: 0, + unlimited_missiles: false, + unlimited_power_bombs: false, + missile_launcher: true, + power_bomb_launcher: true, + spring_ball: false } } } diff --git a/structs/src/scly_props/spawn_point.rs b/structs/src/scly_props/spawn_point.rs index b52df7b6..d14d8ded 100644 --- a/structs/src/scly_props/spawn_point.rs +++ b/structs/src/scly_props/spawn_point.rs @@ -40,9 +40,9 @@ pub struct SpawnPoint<'r> { pub varia_suit: u32, pub phazon_suit: u32, pub energy_tanks: u32, - pub unknown0: u32, + pub unknown_item_1: u32, pub health_refill: u32, - pub unknown1: u32, + pub unknown_item_2: u32, pub wavebuster: u32, pub default_spawn: u8,