Skip to content

Commit

Permalink
v0.3.1 (#3)
Browse files Browse the repository at this point in the history
- Fix old box contents carrying over when starting a new game by means other than the New Game option (i.e. Once Again, Restart, Wesker Mode)
- Fix selection sound not playing when scrolling to the next row in the box
- Fix an issue where scrolling up in the right column of the box could result in half of a two-slot item being selected
- Moving the selection left from the first slot or right from the last slot will now scroll to the previous/next row of the box, consistent with the base game's behavior
  • Loading branch information
descawed authored Aug 30, 2023
1 parent 11c12c1 commit c083dc3
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "re0box"
version = "0.3.0"
version = "0.3.1"
authors = ["descawed <[email protected]>"]
edition = "2021"
description = "An item box mod for Resident Evil 0"
Expand Down
13 changes: 12 additions & 1 deletion src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ use super::inventory::{Bag, Item};
pub const GET_CHARACTER_BAG: usize = 0x0050DA80;
pub const GET_PARTNER_BAG: usize = 0x004DC8B0;
pub const DRAW_BAGS: usize = 0x005E6ED0;
pub const PLAY_SOUND: usize = 0x005EE920;
pub const GET_PARTNER_BAG_ORG: usize = 0x004DC625;
pub const ORGANIZE_END1: usize = 0x004DADC7;
pub const ORGANIZE_END2: usize = 0x004DADDA;
pub const SCROLL_UP_CHECK: usize = 0x005E386A;
pub const SCROLL_DOWN_CHECK: usize = 0x005E3935;
pub const SCROLL_LEFT_CHECK: usize = 0x005E39F1;
pub const SCROLL_RIGHT_CHECK: usize = 0x005E3AFD;
pub const GET_PARTNER_CHARACTER: usize = 0x0066DEC0;
pub const SUB_522A20: usize = 0x00522A20;
pub const PTR_DCDF3C: usize = 0x00DCDF3C;
Expand Down Expand Up @@ -50,7 +53,8 @@ pub const MSG_LOAD1: usize = 0x0040864E;
pub const MSG_LOAD2: usize = 0x005D6471;
pub const MSG_LOAD3: usize = 0x005D67E1;
pub const SHAFT_CHECK: usize = 0x005E3D73;
pub const NEW_GAME: usize = 0x00405870;
pub const NEW_GAME: usize = 0x0041249C;
pub const MOVE_SELECTION_SOUND: i32 = 2050;
pub const FAIL_SOUND: i32 = 2053;
pub const NUM_SAVE_SLOTS: usize = 20;
pub const MAGIC: &[u8] = b"IBOX";
Expand Down Expand Up @@ -85,6 +89,7 @@ pub struct Game {
sub_522a20: Option<unsafe extern "fastcall" fn(*const c_void) -> i32>,
prepare_inventory: Option<unsafe extern "fastcall" fn(*const c_void) -> bool>,
sub_4db330: Option<unsafe extern "fastcall" fn(*const c_void) -> i32>,
play_sound: Option<unsafe extern "C" fn(i32) -> i32>,
get_remote_storage: *const unsafe extern "C" fn() -> *const *const usize,
ptr_dcdf3c: *const *const c_void,
ptr_dd0bd0: *const *const c_void,
Expand All @@ -105,6 +110,7 @@ impl Game {
sub_522a20: None,
prepare_inventory: None,
sub_4db330: None,
play_sound: None,
get_remote_storage: std::ptr::null(),
ptr_dd0bd0: std::ptr::null(),
ptr_dcdf3c: std::ptr::null(),
Expand Down Expand Up @@ -141,6 +147,7 @@ impl Game {
self.sub_522a20 = Some(std::mem::transmute(SUB_522A20));
self.prepare_inventory = Some(std::mem::transmute(PREPARE_INVENTORY));
self.sub_4db330 = Some(std::mem::transmute(SUB_4DB330));
self.play_sound = Some(std::mem::transmute(PLAY_SOUND));
self.get_remote_storage =
STEAM_REMOTE_STORAGE as *const unsafe extern "C" fn() -> *const *const usize;
self.ptr_dd0bd0 = PTR_DD0BD0 as *const *const c_void;
Expand Down Expand Up @@ -190,6 +197,10 @@ impl Game {
self.sub_4db330.unwrap()(unknown)
}

pub unsafe fn play_sound(&self, sound_id: i32) -> i32 {
self.play_sound.unwrap()(sound_id)
}

pub unsafe fn get_remote_storage(&self) -> *const *const usize {
(*self.get_remote_storage)()
}
Expand Down
16 changes: 13 additions & 3 deletions src/inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ impl Bag {
.map(|i| i.id == SLOT_TWO)
.unwrap_or(false)
}

pub fn is_slot_two(&self, index: usize) -> bool {
self.items[index].id == SLOT_TWO
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -192,7 +196,7 @@ impl ItemBox {
self.is_open = false;
}

pub fn scroll_view(&mut self, offset: isize) {
pub fn scroll_view(&mut self, offset: isize) -> bool {
// index must be a multiple of 2; round offset up if it was odd
let mut new_index = self.index as isize + (offset + 1) & !1;
if new_index < 0 {
Expand All @@ -206,8 +210,14 @@ impl ItemBox {
}
}

self.index = new_index as usize;
self.update_view();
let new_index = new_index as usize;
if self.index != new_index {
self.index = new_index;
self.update_view();
true
} else {
false
}
}

pub fn is_open(&self) -> bool {
Expand Down
93 changes: 83 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,33 @@ static mut SCROLL_DOWN_TRAMPOLINE: [u8; 20] = [
0xFF, 0xE6, // jmp esi
];

static mut SCROLL_LEFT_TRAMPOLINE: [u8; 22] = [
0x79, 0x0D, // jns done
0x51, // push ecx
0x52, // push edx
0x57, // push edi
0xE8, 0x00, 0x00, 0x00, 0x00, // call <fn>
0x83, 0xC4, 0x04, // add esp,4
0x5A, // pop edx
0x59, // pop ecx
0xBA, 0xF9, 0x39, 0x5E, 0x00, // done: mov edx,0x5e39f9
0xFF, 0xE2, // jmp edx
];

static mut SCROLL_RIGHT_TRAMPOLINE: [u8; 25] = [
0x83, 0xF8, 0x06, // cmp eax,6
0x7C, 0x0D, // jl done
0x51, // push ecx
0x52, // push edx
0x57, // push edi
0xE8, 0x00, 0x00, 0x00, 0x00, // call <fn>
0x83, 0xC4, 0x04, // add esp,4
0x5A, // pop edx
0x59, // pop ecx
0xBA, 0xF9, 0x39, 0x5E, 0x00, // done: mov edx,0x5e39f9
0xFF, 0xE2, // jmp edx
];

static mut PARTNER_BAG_ORG_TRAMPOLINE: [u8; 26] = [
0xE8, 0x00, 0x00, 0x00, 0x00, // call <fn>
0xB9, 0x41, 0xC6, 0x4D, 0x00, // mov ecx,0x4dc641
Expand Down Expand Up @@ -246,11 +273,12 @@ static mut SHAFT_CHECK_TRAMPOLINE: [u8; 31] = [
0xFF, 0xE0, // do_jmp: jmp eax
];

static mut NEW_GAME_TRAMPOLINE: [u8; 17] = [
static mut NEW_GAME_TRAMPOLINE: [u8; 14] = [
0x51, // push ecx
0xE8, 0x00, 0x00, 0x00, 0x00, // call <fn>
0xA1, 0x18, 0xE0, 0xDC, 0x00, // mov eax,[0xdce018]
0xB9, 0x75, 0x58, 0x40, 0x00, // mov ecx,0x405875
0xFF, 0xE1, // jmp ecx
0x59, // pop ecx
0xB8, 0x40, 0x13, 0x41, 0x00, // mov eax,0x411340
0xFF, 0xE0, // jmp eax
];

static mut BOX: ItemBox = ItemBox::new();
Expand Down Expand Up @@ -375,10 +403,41 @@ unsafe extern "C" fn track_typewriter_message(had_ink_ribbon: bool) {
GAME.user_had_ink_ribbon = had_ink_ribbon;
}

unsafe extern "C" fn scroll_left(unknown: *const c_void) -> i32 {
if BOX.is_open() && BOX.scroll_view(-2) {
GAME.draw_bags(unknown);
if BOX.view().is_slot_two(1) {
0
} else {
1
}
} else {
5 // we're already at the top, so wrap around to the last cell in the view
}
}

unsafe extern "C" fn scroll_right(unknown: *const c_void) -> i32 {
if BOX.is_open() && BOX.scroll_view(2) {
GAME.draw_bags(unknown);
4
} else {
0 // we're already at the bottom, so wrap around to the first cell in the view
}
}

unsafe extern "C" fn scroll(unknown: *const c_void, offset: isize) {
BOX.scroll_view(offset);
// by default the inventory display doesn't update at this point, so we have to do it ourselves
GAME.draw_bags(unknown);
if BOX.is_open() && BOX.scroll_view(offset) {
// by default the inventory display doesn't update at this point, so we have to do it ourselves
GAME.draw_bags(unknown);
// if we've ended up on the second slot of a two-slot item, back up one
let selection_index = unknown.offset(0x2bc) as *mut usize;
if BOX.view().is_slot_two(*selection_index) {
*selection_index -= 1;
}
// the sound doesn't normally play when moving the cursor past the edges of the inventory,
// so we have to do that, too
GAME.play_sound(MOVE_SELECTION_SOUND);
}
}

unsafe fn update_box() {
Expand Down Expand Up @@ -473,6 +532,20 @@ fn main(reason: u32) -> Result<()> {
set_trampoline(&mut SCROLL_DOWN_TRAMPOLINE, 4, scroll as usize)?;
patch(SCROLL_DOWN_CHECK, &scroll_down_jump)?;

// when trying to scroll left from the first inventory cell, scroll the box view
let scroll_left_jump =
jmp(SCROLL_LEFT_CHECK, SCROLL_LEFT_TRAMPOLINE.as_ptr() as usize);
set_trampoline(&mut SCROLL_LEFT_TRAMPOLINE, 5, scroll_left as usize)?;
patch(SCROLL_LEFT_CHECK, &scroll_left_jump)?;

// when trying to scroll right from the last inventory cell, scroll the box view
let scroll_right_jump = jmp(
SCROLL_RIGHT_CHECK,
SCROLL_RIGHT_TRAMPOLINE.as_ptr() as usize,
);
set_trampoline(&mut SCROLL_RIGHT_TRAMPOLINE, 8, scroll_right as usize)?;
patch(SCROLL_RIGHT_CHECK, &scroll_right_jump)?;

// after the view is organized, copy its contents back into the box
let organize_jump1 = jmp(ORGANIZE_END1, ORGANIZE_TRAMPOLINE.as_ptr() as usize);
let organize_jump2 = jmp(ORGANIZE_END2, ORGANIZE_TRAMPOLINE.as_ptr() as usize);
Expand Down Expand Up @@ -581,9 +654,9 @@ fn main(reason: u32) -> Result<()> {
patch(SHAFT_CHECK, &shaft_jump)?;

// reset the box when starting a new game
let new_game_jump = jmp(NEW_GAME, NEW_GAME_TRAMPOLINE.as_ptr() as usize);
set_trampoline(&mut NEW_GAME_TRAMPOLINE, 0, new_game as usize)?;
patch(NEW_GAME, &new_game_jump)?;
let new_game_call = call(NEW_GAME, NEW_GAME_TRAMPOLINE.as_ptr() as usize);
set_trampoline(&mut NEW_GAME_TRAMPOLINE, 1, new_game as usize)?;
patch(NEW_GAME, &new_game_call)?;
}

// even if the mod is disabled, we still install our load and save handlers to prevent
Expand Down
5 changes: 5 additions & 0 deletions src/patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ pub const fn addr_offset(
to.overflowing_sub(from + inst_size).0.to_le_bytes()
}

pub fn call(from: usize, to: usize) -> [u8; 5] {
let bytes = addr_offset(from, to, 5);
[0xE8, bytes[0], bytes[1], bytes[2], bytes[3]]
}

pub fn jmp(from: usize, to: usize) -> [u8; 5] {
let bytes = addr_offset(from, to, 5);
[0xE9, bytes[0], bytes[1], bytes[2], bytes[3]]
Expand Down

0 comments on commit c083dc3

Please sign in to comment.