11use std:: {
22 arch:: global_asm,
3- ffi:: { c_void, CStr , CString } ,
4- ptr,
3+ ffi:: c_void,
4+ mem , ptr,
55 sync:: atomic:: { AtomicPtr , Ordering } ,
66} ;
77
8- use hooklet:: { FunctionPointerHook , X86Rel32Type } ;
8+ use hooklet:: windows:: x86:: { deploy_rel32_raw, hook_call_rel32, CallRel32Hook , FunctionPointerHook , X86Rel32Type } ;
9+ use hooklet:: windows:: x86:: hook_function_pointer;
910use log:: debug;
10- use p3_api:: {
11- data:: { class48:: Class48Ptr , ddraw_set_constant_color, ddraw_set_text_mode, ui_render_text_at} ,
12- game_world:: GAME_WORLD_PTR ,
13- missions:: alderman_missions:: { AldermanMissionDataPtr , FoundTownPtr } ,
14- scheduled_tasks:: {
15- scheduled_task:: { ScheduledTaskData , ScheduledTaskPtr } ,
16- SCHEDULED_TASKS_PTR ,
17- } ,
18- ui:: {
19- font:: { self , get_normal_font} ,
20- ui_town_hall_window:: UITownHallWindowPtr ,
21- } ,
22- } ;
11+ use p3_api:: ui:: ui_town_hall_window:: UITownHallWindowPtr ;
2312use windows:: core:: PCSTR ;
2413
25- pub static TOWN : & CStr = c"Town" ;
26- pub static TASK_DUE_IN : & CStr = c"Rescheduling in" ;
27- pub static EFFECTIVE_PRODUCTION : & CStr = c"Effective Production" ;
28-
2914const TOWN_HALL_WINDOW_OPEN_POINTER_OFFSET : u32 = UITownHallWindowPtr :: VTABLE_OFFSET + 0x120 ;
3015pub static TOWN_HALL_WINDOW_OPEN_HOOK_PTR : AtomicPtr < FunctionPointerHook > = AtomicPtr :: new ( std:: ptr:: null_mut ( ) ) ;
3116
17+ const TOWN_HALL_SIDEPANEL_SET_SELECTED_PAGE_PATCH_OFFSET : u32 = 0x1A94BC ;
18+ pub static TOWN_HALL_SIDEPANEL_SET_SELECTED_PAGE_HOOK_PTR : AtomicPtr < CallRel32Hook > = AtomicPtr :: new ( std:: ptr:: null_mut ( ) ) ;
19+
3220const LOAD_TOWN_HALL_SELECTED_PAGE_PATCH_ADDRESS : u32 = 0x005E09AC ;
3321static LOAD_TOWN_HALL_SELECTED_PAGE_CONTINUATION : u32 = 0x005E09B2 ;
3422
@@ -37,108 +25,69 @@ pub unsafe extern "C" fn start() -> u32 {
3725 let _ = log:: set_logger ( & win_dbg_logger:: DEBUGGER_LOGGER ) ;
3826 log:: set_max_level ( log:: LevelFilter :: Trace ) ;
3927
40- debug ! ( "Hooking town hall's open function through vtable" ) ;
41- match hooklet :: hook_function_pointer (
28+ debug ! ( "Hooking town hall window 's open function through vtable" ) ;
29+ match hook_function_pointer (
4230 PCSTR :: from_raw ( ptr:: null ( ) ) ,
4331 TOWN_HALL_WINDOW_OPEN_POINTER_OFFSET ,
44- town_hall_open_hook as usize as u32 ,
32+ town_hall_window_open_hook as usize as u32 ,
4533 ) {
4634 Ok ( hook) => {
47- debug ! ( "Hook {hook:?} set" ) ;
35+ debug ! ( "Hook {hook:X ?} set" ) ;
4836 TOWN_HALL_WINDOW_OPEN_HOOK_PTR . store ( Box :: into_raw ( Box :: new ( hook) ) , Ordering :: SeqCst ) ;
4937 }
5038 Err ( _) => {
5139 return 1 ;
5240 }
5341 }
5442
43+ debug ! ( "Hooking sidepanel's call to ui_town_hall_window_set_selected_page" ) ;
44+ match hook_call_rel32 (
45+ PCSTR :: from_raw ( ptr:: null ( ) ) ,
46+ TOWN_HALL_SIDEPANEL_SET_SELECTED_PAGE_PATCH_OFFSET ,
47+ town_hall_window_set_selected_page_hook as usize as u32 ,
48+ ) {
49+ Ok ( hook) => {
50+ debug ! ( "Hook {hook:X?} set" ) ;
51+ TOWN_HALL_SIDEPANEL_SET_SELECTED_PAGE_HOOK_PTR . store ( Box :: into_raw ( Box :: new ( hook) ) , Ordering :: SeqCst ) ;
52+ }
53+ Err ( _) => {
54+ return 2 ;
55+ }
56+ }
57+
5558 debug ! ( "Detouring town hall's rendering function at the selected page switch" ) ;
56- if hooklet :: deploy_rel32_raw (
59+ if deploy_rel32_raw (
5760 LOAD_TOWN_HALL_SELECTED_PAGE_PATCH_ADDRESS as _ ,
5861 ( & load_town_hall_selected_page_detour) as * const _ as _ ,
5962 X86Rel32Type :: Jump ,
6063 )
6164 . is_err ( )
6265 {
63- return 2 ;
66+ return 3 ;
6467 }
6568
6669 0
6770}
6871
6972#[ no_mangle]
70- pub unsafe extern "thiscall" fn town_hall_open_hook ( ui_town_hall_window_address : u32 ) {
71- crate :: handle_open ( ui_town_hall_window_address)
73+ unsafe extern "thiscall" fn town_hall_window_open_hook ( ui_town_hall_window_address : u32 ) {
74+ let orig_address = ( * TOWN_HALL_WINDOW_OPEN_HOOK_PTR . load ( Ordering :: SeqCst ) ) . old_absolute ;
75+ let orig: extern "thiscall" fn ( a1 : u32 ) = mem:: transmute ( orig_address) ;
76+ orig ( ui_town_hall_window_address) ;
77+ crate :: handle_open ( )
7278}
7379
7480#[ no_mangle]
75- pub unsafe extern "thiscall" fn town_hall_rendering_hook ( ) -> i32 {
76- crate :: handle_selected_page_switch ( )
77- }
78-
79- pub unsafe fn render_aldermans_office_modifications ( window : & UITownHallWindowPtr ) {
80- let next_mission_index = window. get_next_mission_index ( ) ;
81- if next_mission_index == 0 {
82- return ;
83- }
84-
85- let selected_mission_index = window. get_selected_alderman_mission_index ( ) ;
86- if selected_mission_index == 0xff {
87- return ;
88- }
89- let task_index = window. get_task_index ( selected_mission_index) ;
90- let task = SCHEDULED_TASKS_PTR . get_scheduled_task ( task_index) ;
91- let data = match task. get_data ( ) {
92- Some ( e) => e,
93- None => return ,
94- } ;
95-
96- let mission = match data {
97- ScheduledTaskData :: AldermanMission ( mission) => mission,
98- _ => return ,
99- } ;
100- match mission. get_data ( ) {
101- AldermanMissionDataPtr :: FoundTownPtr ( ptr) => render_aldermans_office_modifications_found_town ( window, & task, & ptr) ,
102- AldermanMissionDataPtr :: OverlandTradeRoute ( _ptr) => { }
103- AldermanMissionDataPtr :: NotoriousPirate ( _ptr) => { }
104- AldermanMissionDataPtr :: PirateHideout ( _ptr) => { }
105- AldermanMissionDataPtr :: SupplyProblems ( _ptr) => { }
106- }
81+ unsafe extern "thiscall" fn town_hall_window_set_selected_page_hook ( ui_town_hall_window_address : u32 , page : u32 ) {
82+ let orig_address = ( * TOWN_HALL_SIDEPANEL_SET_SELECTED_PAGE_HOOK_PTR . load ( Ordering :: SeqCst ) ) . old_absolute ;
83+ let orig: extern "thiscall" fn ( ui_town_hall_window_address : u32 , page : u32 ) = mem:: transmute ( orig_address) ;
84+ orig ( ui_town_hall_window_address, page) ;
85+ crate :: handle_set_selected_page ( page)
10786}
10887
109- unsafe fn render_aldermans_office_modifications_found_town ( window : & UITownHallWindowPtr , task : & ScheduledTaskPtr , data : & FoundTownPtr ) {
110- let town = data. get_town ( ) ;
111- let effective = data. get_production_effective ( ) ;
112- let class48 = Class48Ptr :: new ( ) ;
113- class48. set_ignore_below_gradient ( 0 ) ;
114- class48. set_gradient_y ( 0 ) ;
115-
116- ddraw_set_constant_color ( 0xff000000 ) ;
117- ddraw_set_text_mode ( 2 ) ;
118- font:: ddraw_set_font ( get_normal_font ( ) ) ;
119- let x = window. get_x ( ) ;
120- let mut y = window. get_y ( ) + 60 ;
121-
122- ui_render_text_at ( x + 120 , y, TASK_DUE_IN . to_bytes ( ) ) ;
123- let due_in = task. get_due_timestamp ( ) - GAME_WORLD_PTR . get_game_time_raw ( ) ;
124- let task_due_in_cstring = CString :: new ( format ! ( "{due_in}" ) ) . unwrap ( ) ;
125- ui_render_text_at ( x + 420 , y, task_due_in_cstring. to_bytes ( ) ) ;
126- y += 20 ;
127-
128- ui_render_text_at ( x + 120 , y, TOWN . to_bytes ( ) ) ;
129- let town_cstring = CString :: new ( format ! ( "{town:?}" ) ) . unwrap ( ) ;
130- ui_render_text_at ( x + 420 , y, town_cstring. to_bytes ( ) ) ;
131- y += 20 ;
132-
133- ui_render_text_at ( x + 120 , y, EFFECTIVE_PRODUCTION . to_bytes ( ) ) ;
134- let mut effective_string = String :: new ( ) ;
135- for facility in effective {
136- effective_string. push_str ( & format ! ( "{facility:?}, " ) ) ;
137- }
138- effective_string. pop ( ) ;
139- effective_string. pop ( ) ;
140- let effective_cstring = CString :: new ( effective_string) . unwrap ( ) ;
141- ui_render_text_at ( x + 420 , y, effective_cstring. to_bytes ( ) ) ;
88+ #[ no_mangle]
89+ unsafe extern "thiscall" fn town_hall_selected_page_switch_hook ( ) -> i32 {
90+ crate :: handle_selected_page_switch ( )
14291}
14392
14493extern "C" {
@@ -161,5 +110,5 @@ pop ecx
161110jmp [{continuation}]
162111" ,
163112load_town_hall_selected_page_detour = sym load_town_hall_selected_page_detour,
164- town_hall_rendering_hook = sym town_hall_rendering_hook ,
113+ town_hall_rendering_hook = sym town_hall_selected_page_switch_hook ,
165114continuation = sym LOAD_TOWN_HALL_SELECTED_PAGE_CONTINUATION ) ;
0 commit comments