refactor: use own EXTENDED_OPTIONS_DEFAULTS constant instead of ROM
Browse filesThe constant is now verified correct (runtime-dumped from ROM). Use it
directly rather than reading from WA.exe memory — we're replacing the
executable, not depending on it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-wormkit/src/replacements/scheme.rs
CHANGED
|
@@ -18,7 +18,7 @@ use crate::log_line;
|
|
| 18 |
use openwa_core::rebase::rb;
|
| 19 |
use openwa_core::address::va;
|
| 20 |
use openwa_core::game::scheme::{
|
| 21 |
-
ExtendedOptions, SchemeFile, SchemeVersion, EXTENDED_OPTIONS_SIZE,
|
| 22 |
SCHEME_PAYLOAD_V1, SCHEME_PAYLOAD_V2, SCHEME_PAYLOAD_V3,
|
| 23 |
};
|
| 24 |
|
|
@@ -52,68 +52,55 @@ const SCHEME_WEAPON_CHECK_COUNT: usize = 39;
|
|
| 52 |
/// MFC string resource ID for default scheme name.
|
| 53 |
const STRING_RES_DEFAULT_NAME: u32 = 0x0E;
|
| 54 |
|
| 55 |
-
/// Read the V3 extended options defaults from WA.exe ROM (110 bytes at 0x649AB8).
|
| 56 |
-
unsafe fn rom_ext_defaults() -> *const u8 {
|
| 57 |
-
rb(va::SCHEME_V3_DEFAULTS) as *const u8
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
/// Write a parsed SchemeFile into the WA dest struct at the correct offsets.
|
| 61 |
///
|
| 62 |
/// Replicates the memory writes from Scheme__ReadFile:
|
| 63 |
-
/// - V1: payload(0xD8) + zero super weapons(0x4C) +
|
| 64 |
-
/// - V2: payload(0x124) +
|
| 65 |
-
/// - V3: payload(0x192), with validation fallback to
|
| 66 |
unsafe fn write_scheme_to_dest(scheme: &SchemeFile, dest: u32) {
|
| 67 |
let payload_ptr = (dest as usize + DEST_PAYLOAD) as *mut u8;
|
| 68 |
-
let rom_defaults = rom_ext_defaults();
|
| 69 |
|
| 70 |
match scheme.version {
|
| 71 |
SchemeVersion::V1 => {
|
| 72 |
-
// Copy V1 payload (216 bytes)
|
| 73 |
core::ptr::copy_nonoverlapping(
|
| 74 |
scheme.payload.as_ptr(),
|
| 75 |
payload_ptr,
|
| 76 |
SCHEME_PAYLOAD_V1,
|
| 77 |
);
|
| 78 |
-
// Zero the super weapons region (76 bytes)
|
| 79 |
core::ptr::write_bytes(
|
| 80 |
payload_ptr.add(PAYLOAD_SUPER_WEAPONS),
|
| 81 |
0,
|
| 82 |
SUPER_WEAPONS_SIZE,
|
| 83 |
);
|
| 84 |
-
// Copy V3 defaults from ROM for extended options (110 bytes)
|
| 85 |
core::ptr::copy_nonoverlapping(
|
| 86 |
-
|
| 87 |
payload_ptr.add(PAYLOAD_EXTENDED),
|
| 88 |
EXTENDED_OPTIONS_SIZE,
|
| 89 |
);
|
| 90 |
}
|
| 91 |
SchemeVersion::V2 => {
|
| 92 |
-
// Copy V2 payload (292 bytes)
|
| 93 |
core::ptr::copy_nonoverlapping(
|
| 94 |
scheme.payload.as_ptr(),
|
| 95 |
payload_ptr,
|
| 96 |
SCHEME_PAYLOAD_V2,
|
| 97 |
);
|
| 98 |
-
// Copy V3 defaults from ROM for extended options (110 bytes)
|
| 99 |
core::ptr::copy_nonoverlapping(
|
| 100 |
-
|
| 101 |
payload_ptr.add(PAYLOAD_EXTENDED),
|
| 102 |
EXTENDED_OPTIONS_SIZE,
|
| 103 |
);
|
| 104 |
}
|
| 105 |
SchemeVersion::V3 => {
|
| 106 |
-
// Copy full V3 payload (402 bytes)
|
| 107 |
core::ptr::copy_nonoverlapping(
|
| 108 |
scheme.payload.as_ptr(),
|
| 109 |
payload_ptr,
|
| 110 |
SCHEME_PAYLOAD_V3,
|
| 111 |
);
|
| 112 |
-
// Validate extended options; if invalid, replace with ROM defaults
|
| 113 |
let ext_bytes = &scheme.payload[PAYLOAD_EXTENDED..];
|
| 114 |
if !ExtendedOptions::validate_bytes(ext_bytes) {
|
| 115 |
core::ptr::copy_nonoverlapping(
|
| 116 |
-
|
| 117 |
payload_ptr.add(PAYLOAD_EXTENDED),
|
| 118 |
EXTENDED_OPTIONS_SIZE,
|
| 119 |
);
|
|
|
|
| 18 |
use openwa_core::rebase::rb;
|
| 19 |
use openwa_core::address::va;
|
| 20 |
use openwa_core::game::scheme::{
|
| 21 |
+
ExtendedOptions, SchemeFile, SchemeVersion, EXTENDED_OPTIONS_DEFAULTS, EXTENDED_OPTIONS_SIZE,
|
| 22 |
SCHEME_PAYLOAD_V1, SCHEME_PAYLOAD_V2, SCHEME_PAYLOAD_V3,
|
| 23 |
};
|
| 24 |
|
|
|
|
| 52 |
/// MFC string resource ID for default scheme name.
|
| 53 |
const STRING_RES_DEFAULT_NAME: u32 = 0x0E;
|
| 54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
/// Write a parsed SchemeFile into the WA dest struct at the correct offsets.
|
| 56 |
///
|
| 57 |
/// Replicates the memory writes from Scheme__ReadFile:
|
| 58 |
+
/// - V1: payload(0xD8) + zero super weapons(0x4C) + defaults(0x6E)
|
| 59 |
+
/// - V2: payload(0x124) + defaults(0x6E)
|
| 60 |
+
/// - V3: payload(0x192), with validation fallback to defaults
|
| 61 |
unsafe fn write_scheme_to_dest(scheme: &SchemeFile, dest: u32) {
|
| 62 |
let payload_ptr = (dest as usize + DEST_PAYLOAD) as *mut u8;
|
|
|
|
| 63 |
|
| 64 |
match scheme.version {
|
| 65 |
SchemeVersion::V1 => {
|
|
|
|
| 66 |
core::ptr::copy_nonoverlapping(
|
| 67 |
scheme.payload.as_ptr(),
|
| 68 |
payload_ptr,
|
| 69 |
SCHEME_PAYLOAD_V1,
|
| 70 |
);
|
|
|
|
| 71 |
core::ptr::write_bytes(
|
| 72 |
payload_ptr.add(PAYLOAD_SUPER_WEAPONS),
|
| 73 |
0,
|
| 74 |
SUPER_WEAPONS_SIZE,
|
| 75 |
);
|
|
|
|
| 76 |
core::ptr::copy_nonoverlapping(
|
| 77 |
+
EXTENDED_OPTIONS_DEFAULTS.as_ptr(),
|
| 78 |
payload_ptr.add(PAYLOAD_EXTENDED),
|
| 79 |
EXTENDED_OPTIONS_SIZE,
|
| 80 |
);
|
| 81 |
}
|
| 82 |
SchemeVersion::V2 => {
|
|
|
|
| 83 |
core::ptr::copy_nonoverlapping(
|
| 84 |
scheme.payload.as_ptr(),
|
| 85 |
payload_ptr,
|
| 86 |
SCHEME_PAYLOAD_V2,
|
| 87 |
);
|
|
|
|
| 88 |
core::ptr::copy_nonoverlapping(
|
| 89 |
+
EXTENDED_OPTIONS_DEFAULTS.as_ptr(),
|
| 90 |
payload_ptr.add(PAYLOAD_EXTENDED),
|
| 91 |
EXTENDED_OPTIONS_SIZE,
|
| 92 |
);
|
| 93 |
}
|
| 94 |
SchemeVersion::V3 => {
|
|
|
|
| 95 |
core::ptr::copy_nonoverlapping(
|
| 96 |
scheme.payload.as_ptr(),
|
| 97 |
payload_ptr,
|
| 98 |
SCHEME_PAYLOAD_V3,
|
| 99 |
);
|
|
|
|
| 100 |
let ext_bytes = &scheme.payload[PAYLOAD_EXTENDED..];
|
| 101 |
if !ExtendedOptions::validate_bytes(ext_bytes) {
|
| 102 |
core::ptr::copy_nonoverlapping(
|
| 103 |
+
EXTENDED_OPTIONS_DEFAULTS.as_ptr(),
|
| 104 |
payload_ptr.add(PAYLOAD_EXTENDED),
|
| 105 |
EXTENDED_OPTIONS_SIZE,
|
| 106 |
);
|