Skip to content

Commit c0571b7

Browse files
committed
sync price if stock % 2 == 1
1 parent 19cf0ef commit c0571b7

File tree

13 files changed

+200
-27
lines changed

13 files changed

+200
-27
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ members = [
1515
"mod-shipyard-details",
1616
"mod-tavern-show-all-sailors",
1717
"mod-town-hall-details",
18+
"mod-trading-office-prices-synchronization",
1819
#"p3-agent",
1920
"p3-agent-loader",
2021
"p3-aim",
@@ -30,7 +31,7 @@ exclude = [
3031
version = "0.1.9"
3132

3233
[workspace.dependencies]
33-
hooklet = "^0.1.6"
34+
hooklet = "^0.1.7"
3435
clap = { version = "4.3.0", features = ["derive"] }
3536
simple_logger = "4.1"
3637
log = "0.4"

mod-high-res/Cargo.toml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,3 @@ log = { workspace = true }
1212
win_dbg_logger = { workspace = true }
1313
p3-api = { path = "../p3-api" }
1414
hooklet = { workspace = true }
15-
16-
[dependencies.windows]
17-
version = "0.48"
18-
features = [
19-
"Win32_Foundation",
20-
"Win32_System_Memory",
21-
]

mod-high-res/src/ffi.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
use std::{
22
arch::global_asm,
33
ffi::{c_void, CStr},
4-
mem, ptr,
4+
mem,
55
sync::atomic::{AtomicPtr, Ordering},
66
};
77

8-
use hooklet::windows::x86::{deploy_rel32_raw, hook_call_rel32, CallRel32Hook, X86Rel32Type};
8+
use hooklet::windows::x86::{deploy_rel32_raw, hook_call_rel32, hook_call_rel32_with_module, CallRel32Hook, X86Rel32Type};
99
use log::debug;
1010
use p3_api::{
1111
data::{class27::Class27Ptr, ddraw_fill_solid_rect, ddraw_set_constant_color, ddraw_set_render_dest, get_resolution_height, get_resolution_width},
1212
latin1_ptr_to_string,
1313
ui::class73::Class73Ptr,
1414
};
15-
use windows::core::PCSTR;
1615

1716
const FULLHD_STRING: &CStr = c"1920 x 1080";
1817

@@ -103,7 +102,7 @@ pub unsafe extern "C" fn start() -> u32 {
103102

104103
// Fix empty bottom right corner
105104
debug!("Deploying render_all_objects_hook");
106-
match hook_call_rel32(PCSTR::from_raw(ptr::null()), 0x28649, maybe_render_all_objects_hook as usize as u32) {
105+
match hook_call_rel32(0x28649, maybe_render_all_objects_hook as usize as u32) {
107106
Ok(hook) => {
108107
HOOK_PTR.store(Box::into_raw(Box::new(hook)), Ordering::SeqCst);
109108
}
@@ -112,11 +111,7 @@ pub unsafe extern "C" fn start() -> u32 {
112111

113112
// Fix acceleration map
114113
debug!("Deploying dddraw_dll.dll decode_supported_files hook to replace the background image");
115-
match hook_call_rel32(
116-
PCSTR::from_raw(c"aim.dll".as_ptr() as _),
117-
0x2984,
118-
ddraw_dll_decode_supported_files_hook as usize as u32,
119-
) {
114+
match hook_call_rel32_with_module("aim.dll", 0x2984, ddraw_dll_decode_supported_files_hook as usize as u32) {
120115
Ok(hook) => {
121116
debug!("Hook {hook:?} set");
122117
DECODE_SUPPORTED_FILES_HOOK_PTR.store(Box::into_raw(Box::new(hook)), Ordering::SeqCst);
@@ -126,7 +121,7 @@ pub unsafe extern "C" fn start() -> u32 {
126121

127122
// Fix acceleration map
128123
debug!("Deploying load screen settings from accelMap.ini");
129-
match hook_call_rel32(PCSTR::from_raw(ptr::null()), 0x12C5, class73_place_ui_element_hook as usize as u32) {
124+
match hook_call_rel32(0x12C5, class73_place_ui_element_hook as usize as u32) {
130125
Ok(hook) => {
131126
debug!("Hook {hook:?} set");
132127
LOAD_ACCEL_MAP_INI_HOOK_PTR.store(Box::into_raw(Box::new(hook)), Ordering::SeqCst);

mod-town-hall-details/src/ffi.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{
55
sync::atomic::{AtomicPtr, Ordering},
66
};
77

8-
use hooklet::windows::x86::hook_function_pointer;
9-
use hooklet::windows::x86::{deploy_rel32_raw, hook_call_rel32, CallRel32Hook, FunctionPointerHook, X86Rel32Type};
8+
use hooklet::windows::x86::{deploy_rel32_raw, CallRel32Hook, FunctionPointerHook, X86Rel32Type};
9+
use hooklet::windows::x86::{hook_call_rel32, hook_function_pointer_width_module};
1010
use log::debug;
1111
use p3_api::ui::ui_town_hall_window::UITownHallWindowPtr;
1212
use windows::core::PCSTR;
@@ -26,7 +26,7 @@ pub unsafe extern "C" fn start() -> u32 {
2626
log::set_max_level(log::LevelFilter::Trace);
2727

2828
debug!("Hooking town hall window's open function through vtable");
29-
match hook_function_pointer(
29+
match hook_function_pointer_width_module(
3030
PCSTR::from_raw(ptr::null()),
3131
TOWN_HALL_WINDOW_OPEN_POINTER_OFFSET,
3232
town_hall_window_open_hook as usize as u32,
@@ -42,7 +42,6 @@ pub unsafe extern "C" fn start() -> u32 {
4242

4343
debug!("Hooking sidepanel's call to ui_town_hall_window_set_selected_page");
4444
match hook_call_rel32(
45-
PCSTR::from_raw(ptr::null()),
4645
TOWN_HALL_SIDEPANEL_SET_SELECTED_PAGE_PATCH_OFFSET,
4746
town_hall_window_set_selected_page_hook as usize as u32,
4847
) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "mod-trading-office-prices-synchronization"
3+
edition = "2021"
4+
version.workspace = true
5+
6+
[lib]
7+
crate-type = ["cdylib"]
8+
name="trading_office_prices_synchronization"
9+
10+
[dependencies]
11+
log = { workspace = true }
12+
win_dbg_logger = { workspace = true }
13+
p3-api = { path = "../p3-api" }
14+
hooklet = { workspace = true }
15+
num-traits = { workspace = true }
16+
num-derive = { workspace = true }
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use std::{
2+
mem::{self},
3+
panic::{self},
4+
sync::atomic::{AtomicPtr, Ordering},
5+
};
6+
7+
use hooklet::windows::x86::{hook_function_pointer, FunctionPointerHook};
8+
use log::error;
9+
use p3_api::ui::ui_trading_office_window::UITradingOfficeWindowPtr;
10+
11+
const TOWN_TRADING_OFFICE_CLOSE_POINTER_OFFSET: u32 = UITradingOfficeWindowPtr::VTABLE_OFFSET + 0x118;
12+
static WINDOW_CLOSE_HOOK_PTR: AtomicPtr<FunctionPointerHook> = AtomicPtr::new(std::ptr::null_mut());
13+
14+
#[no_mangle]
15+
unsafe extern "C" fn start() -> u32 {
16+
let _ = log::set_logger(&win_dbg_logger::DEBUGGER_LOGGER);
17+
log::set_max_level(log::LevelFilter::Trace);
18+
19+
panic::set_hook(Box::new(|p| {
20+
error!("{p}");
21+
}));
22+
23+
match hook_function_pointer(TOWN_TRADING_OFFICE_CLOSE_POINTER_OFFSET, window_close_hook as usize as u32) {
24+
Ok(hook) => {
25+
WINDOW_CLOSE_HOOK_PTR.store(Box::into_raw(Box::new(hook)), Ordering::SeqCst);
26+
}
27+
Err(_) => return 1,
28+
}
29+
30+
0
31+
}
32+
33+
#[no_mangle]
34+
unsafe extern "thiscall" fn window_close_hook(window_address: u32) {
35+
crate::synchronize_autotrade_settings();
36+
let orig_address = (*WINDOW_CLOSE_HOOK_PTR.load(Ordering::SeqCst)).old_absolute;
37+
let orig: extern "thiscall" fn(window_address: u32) = unsafe { mem::transmute(orig_address) };
38+
orig(window_address)
39+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use log::{debug, warn};
2+
use num_traits::cast::FromPrimitive;
3+
use p3_api::{
4+
data::enums::WareId, game_world::GAME_WORLD_PTR, operation::Operation, operations::OPERATIONS_PTR, town::get_town_name,
5+
ui::ui_trading_office_window::UITradingOfficeWindowPtr,
6+
};
7+
8+
mod ffi;
9+
10+
pub(crate) unsafe fn synchronize_autotrade_settings() {
11+
// Pull merchant index from operatons.field_924?
12+
let merchant_index = OPERATIONS_PTR.get_player_merchant_index();
13+
let window = UITradingOfficeWindowPtr::default();
14+
let town_index = window.get_town_index();
15+
let town_name = get_town_name(town_index as _).unwrap();
16+
debug!("synchronize_autotrade_settings from {town_name}");
17+
let setting_office = GAME_WORLD_PTR.get_office_in_of(town_index as _, merchant_index as _);
18+
let setting_office = match setting_office {
19+
Some(office) => office,
20+
None => {
21+
warn!("Could not find office in {town_name} of merchant {merchant_index:#x}");
22+
return;
23+
}
24+
};
25+
26+
let setting_prices = setting_office.get_administrator_trade_prices();
27+
let setting_stock = setting_office.get_administrator_trade_stock();
28+
let merchant = GAME_WORLD_PTR.get_merchant(merchant_index as _);
29+
let mut office_index = merchant.get_first_office_index();
30+
while office_index < GAME_WORLD_PTR.get_offices_count() {
31+
let office = GAME_WORLD_PTR.get_office(office_index);
32+
if office.address == setting_office.address {
33+
office_index = office.get_next_office_of_merchant_index();
34+
continue;
35+
}
36+
let stock = office.get_administrator_trade_stock();
37+
38+
for i in 0..20 {
39+
let ware_id = WareId::from_usize(i).unwrap();
40+
if setting_stock[i] / ware_id.get_scaling() % 2 == 0 {
41+
continue;
42+
}
43+
let stock = stock[i];
44+
let price = setting_prices[i];
45+
46+
OPERATIONS_PTR.enqueue_operation(Operation::OfficeAutotradeSettingChange {
47+
stock,
48+
price,
49+
office_index: office_index as _,
50+
ware_id,
51+
});
52+
}
53+
54+
office_index = office.get_next_office_of_merchant_index();
55+
}
56+
}

p3-api/src/data/office.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,25 @@ impl OfficePtr {
2828
unsafe { self.get(0x2ca) }
2929
}
3030

31+
pub unsafe fn get_administrator_trade_prices(&self) -> [i32; 20] {
32+
self.get(0x2f4)
33+
}
34+
3135
pub unsafe fn set_administrator_trade_prices(&self, prices: [i32; 20]) {
3236
self.set(0x2f4, &prices)
3337
}
3438

3539
pub unsafe fn set_administrator_trade_actions(&self, actions: [i32; 20]) {
3640
self.set(0x2f4, &actions)
3741
}
42+
43+
pub unsafe fn get_administrator_trade_stock(&self) -> [i32; 20] {
44+
self.get(0x354)
45+
}
46+
47+
pub unsafe fn get_administrator_trade_lock_bitmap(&self) -> u32 {
48+
self.get(0x3b4)
49+
}
3850
}
3951

4052
impl P3Pointer for OfficePtr {

p3-api/src/operation.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ pub enum Operation {
4040
RepairConvoy {
4141
convoy_index: u32,
4242
},
43+
OfficeAutotradeSettingChange {
44+
stock: i32,
45+
price: i32,
46+
office_index: u32,
47+
ware_id: WareId,
48+
},
4349
}
4450

4551
impl Operation {
@@ -126,6 +132,20 @@ impl Operation {
126132
op[0..4].copy_from_slice(&opcode.to_le_bytes());
127133
op[0x04..0x08].copy_from_slice(&convoy_id.to_le_bytes());
128134
}
135+
Operation::OfficeAutotradeSettingChange {
136+
stock,
137+
price,
138+
office_index,
139+
ware_id,
140+
} => {
141+
let opcode: u32 = 0x5b;
142+
let ware_id: u32 = *ware_id as _;
143+
op[0..4].copy_from_slice(&opcode.to_le_bytes());
144+
op[4..8].copy_from_slice(&stock.to_le_bytes());
145+
op[8..0x0c].copy_from_slice(&price.to_le_bytes());
146+
op[0x0c..0x10].copy_from_slice(&office_index.to_le_bytes());
147+
op[0x10..0x14].copy_from_slice(&ware_id.to_le_bytes());
148+
}
129149
}
130150
op
131151
}

p3-api/src/operations.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
use std::mem::transmute;
1+
use std::{ffi::c_void, mem::transmute};
22

33
use log::debug;
44

55
use crate::{data::p3_ptr::P3Pointer, operation::Operation};
66

7-
const OPERATIONS_ADDRESS: u32 = 0x006DF2F0;
87
pub const OPERATIONS_PTR: OperationsPtr = OperationsPtr::new();
9-
const EXECUTE_OPERATION_ADDRESS: u32 = 0x00535760;
8+
const OPERATIONS_ADDRESS: u32 = 0x006DF2F0;
9+
static EXECUTE_OPERATION_ADDRESS: u32 = 0x00535760;
10+
static ENQUEUE_OPERATION_ADDRESS: u32 = 0x0054AA70;
11+
static ENQUEUE_OPERATION: &extern "thiscall" fn(*mut c_void, *const c_void) = unsafe { transmute(&ENQUEUE_OPERATION_ADDRESS) };
1012

1113
#[derive(Clone, Debug, Copy)]
1214
pub struct OperationsPtr {
@@ -27,6 +29,12 @@ impl OperationsPtr {
2729
pub unsafe fn get_player_merchant_index(&self) -> i32 {
2830
self.get(0x0924)
2931
}
32+
33+
pub unsafe fn enqueue_operation(&self, op: Operation) {
34+
debug!("Enqueuing operation {op:?}");
35+
let op_bytes = op.to_raw();
36+
ENQUEUE_OPERATION(OPERATIONS_ADDRESS as _, op_bytes.as_ptr() as _)
37+
}
3038
}
3139

3240
impl P3Pointer for OperationsPtr {

0 commit comments

Comments
 (0)