Skip to content

Commit 19cf0ef

Browse files
committed
more api functions, rename low production
1 parent 5f83b7e commit 19cf0ef

File tree

11 files changed

+191
-28
lines changed

11 files changed

+191
-28
lines changed

mod-town-hall-details/src/pages/aldermans_office.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static TASK_RESCHEDULING_IN: &CStr = c"Rescheduling in";
1818
static TASK_RESCHEDULES_REMAINING: &CStr = c"Reschedule Counter";
1919
static TOWN: &CStr = c"Town";
2020
static EFFECTIVE_PRODUCTION: &CStr = c"Effective Production";
21-
static INEFFECTIVE_PRODUCTION: &CStr = c"Ineffective Production";
21+
static LOW_PRODUCTION: &CStr = c"Low Production";
2222

2323
pub(crate) unsafe fn draw_page(window: UITownHallWindowPtr) {
2424
let next_mission_index = window.get_next_mission_index();
@@ -133,7 +133,7 @@ unsafe fn render_aldermans_office_modifications_found_town(window: UITownHallWin
133133
y += 20;
134134

135135
font::ddraw_set_text_mode(font::TextMode::AlignLeft);
136-
ui_render_text_at(x + COL_OFFSETS[0], y, INEFFECTIVE_PRODUCTION.to_bytes());
136+
ui_render_text_at(x + COL_OFFSETS[0], y, LOW_PRODUCTION.to_bytes());
137137

138138
font::ddraw_set_text_mode(font::TextMode::AlignRight);
139139
let mut ineffective_string = String::new();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub(crate) unsafe fn draw_page(window: UITownHallWindowPtr) {
5656
hanse_data[ware].total_wares += office_stock[ware];
5757
hanse_data[ware].total_consumption += office_consumption[ware];
5858
}
59-
office_index = office.next_office_in_town_index();
59+
office_index = office.get_next_office_in_town_index();
6060
}
6161
}
6262
hanse_data.sort_by_key(|a| a.get_ratio());

p3-api/src/class35.rs

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,80 @@
1-
use std::{ffi::c_void, mem, ptr};
1+
use std::{mem, ops::Deref, ptr};
22

3-
use log::debug;
3+
use log::warn;
44

5-
use crate::{data::p3_ptr::P3Pointer, Point};
5+
use crate::{
6+
data::{
7+
enums::{ShipType, TownId},
8+
p3_ptr::P3Pointer,
9+
},
10+
town::static_town_data::StaticTownDataPtr,
11+
Point,
12+
};
613

714
const CLASS35_PTR_ADDRESS: *const u32 = 0x006CBDC8 as _;
15+
pub const CAPACITY_FACTOR_MAX: u32 = 4096;
16+
pub const HEALTH_FACTOR_MAX: u32 = 256;
817

9-
#[derive(Clone, Debug)]
18+
#[derive(Clone, Debug, Copy)]
1019
pub struct Class35Ptr {
1120
pub address: u32,
1221
}
1322

23+
#[derive(Clone, Debug)]
24+
pub struct ShipRoutePtr {
25+
pub address: u32,
26+
pub needs_free: bool,
27+
}
28+
29+
impl ShipRoutePtr {
30+
pub unsafe fn calculate_distance(&self) -> i32 {
31+
let mut distance = 0;
32+
if self.len > 1 {
33+
for i in 1..self.len as usize {
34+
let p0 = (*self.points.add(i - 1)).clone();
35+
let p1 = (*self.points.add(i)).clone();
36+
let x_diff = (p0.x - p1.x).abs();
37+
let y_diff = (p0.y - p1.y).abs();
38+
if x_diff <= y_diff {
39+
distance += (16 * y_diff + 7 * x_diff) as i32;
40+
} else {
41+
distance += (16 * x_diff + 7 * y_diff) as i32;
42+
}
43+
}
44+
}
45+
46+
distance
47+
}
48+
49+
pub unsafe fn calculate_travel_time(&self, ship_type: ShipType, health_factor: u32, capacity_factor: u32) -> u32 {
50+
let capacity_scaled_speed = (ship_type.get_base_speed() as u32 * capacity_factor) >> 12;
51+
let speed_factor = (capacity_scaled_speed * health_factor) >> 10;
52+
8 * self.calculate_distance() as u32 / speed_factor
53+
}
54+
55+
pub unsafe fn free(self) {
56+
if !self.needs_free {
57+
return;
58+
}
59+
if !self.points.is_null() {
60+
crate::free(self.points as usize as _);
61+
}
62+
crate::free(self.address);
63+
}
64+
}
65+
66+
impl Deref for ShipRoutePtr {
67+
type Target = ShipRoute;
68+
69+
fn deref(&self) -> &Self::Target {
70+
unsafe { &*(self.address as *const ShipRoute) }
71+
}
72+
}
73+
1474
#[derive(Clone, Debug)]
1575
#[repr(C)]
1676
pub struct ShipRoute {
17-
pub points: *const c_void,
77+
pub points: *mut Point<i16>,
1878
pub len: i32,
1979
}
2080

@@ -37,18 +97,33 @@ impl Class35Ptr {
3797
Self { address: *CLASS35_PTR_ADDRESS }
3898
}
3999

40-
pub unsafe fn calculate_ship_route(&self, source: Point<i16>, destination: Point<i16>) -> *const ShipRoute {
41-
let args_inner = ShipRouteArgsInner { source, destination };
100+
pub unsafe fn calculate_town_route(&self, source: TownId, destination: TownId) -> Option<ShipRoutePtr> {
101+
let source_data = StaticTownDataPtr::new(source);
102+
let destination_data = StaticTownDataPtr::new(destination);
103+
self.calculate_route(&source_data.get_point_i16(), &destination_data.get_point_i16())
104+
}
105+
106+
pub unsafe fn calculate_route(&self, source: &Point<i16>, destination: &Point<i16>) -> Option<ShipRoutePtr> {
107+
let args_inner = ShipRouteArgsInner {
108+
source: source.clone(),
109+
destination: destination.clone(),
110+
};
42111
let args = ShipRouteArgs {
43112
args_inner: &args_inner,
44113
route_type: 2,
45114
};
46-
let mut ship_route: *const ShipRoute = ptr::null_mut();
47-
debug!("Calling calculate_ship_route orig");
48-
let orig: extern "thiscall" fn(this: u32, route_args: *const ShipRouteArgs, route: *mut *const ShipRoute) -> i32 = mem::transmute(0x00445010);
49-
orig(self.address, &args, &mut ship_route);
50-
debug!("Calling calculate_ship_route survived! {ship_route:?}");
51-
ship_route
115+
let mut ship_route: *mut ShipRoute = ptr::null_mut();
116+
let orig: extern "thiscall" fn(this: u32, route_args: *const ShipRouteArgs, route: *mut *mut ShipRoute) -> bool = mem::transmute(0x00445010);
117+
let needs_free = orig(self.address, &args, &mut ship_route);
118+
if !ship_route.is_null() {
119+
Some(ShipRoutePtr {
120+
address: ship_route as _,
121+
needs_free,
122+
})
123+
} else {
124+
warn!("Failed to calculate route {:x}", ship_route as u32);
125+
None
126+
}
52127
}
53128
}
54129

p3-api/src/data/enums.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ pub enum ShipWeaponId {
112112
}
113113

114114
#[derive(Clone, Copy, Debug, Eq, PartialEq, EnumIter, FromPrimitive)]
115-
pub enum ShipTypeId {
115+
#[repr(u8)]
116+
pub enum ShipType {
116117
Snaikkka = 0x00,
117118
Craier = 0x01,
118119
Cog = 0x02,
@@ -209,6 +210,18 @@ impl WareId {
209210
_ => true,
210211
}
211212
}
213+
214+
pub unsafe fn get_base_price(&self) -> f32 {
215+
let base_price_ptr: *const f32 = 0x00673A18 as _;
216+
*base_price_ptr.add(*self as usize)
217+
}
218+
}
219+
220+
impl ShipType {
221+
pub unsafe fn get_base_speed(&self) -> u16 {
222+
let base_speed_ptr: *const u16 = 0x0067366C as _;
223+
*base_speed_ptr.add(*self as usize)
224+
}
212225
}
213226

214227
impl ShipWeaponId {

p3-api/src/data/office.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{p3_ptr::P3Pointer, storage::StoragePtr};
22

33
pub const OFFICE_SIZE: u32 = 0x44C;
44

5-
#[derive(Debug)]
5+
#[derive(Debug, Clone, Copy)]
66
pub struct OfficePtr {
77
pub address: u32,
88
}
@@ -16,13 +16,25 @@ impl OfficePtr {
1616
StoragePtr::new(self.address)
1717
}
1818

19-
pub fn get_merchant_id(&self) -> u16 {
19+
pub fn get_merchant_index(&self) -> u16 {
2020
unsafe { self.get(0x2c4) }
2121
}
2222

23-
pub fn next_office_in_town_index(&self) -> u16 {
23+
pub fn get_next_office_of_merchant_index(&self) -> u16 {
24+
unsafe { self.get(0x2c8) }
25+
}
26+
27+
pub fn get_next_office_in_town_index(&self) -> u16 {
2428
unsafe { self.get(0x2ca) }
2529
}
30+
31+
pub unsafe fn set_administrator_trade_prices(&self, prices: [i32; 20]) {
32+
self.set(0x2f4, &prices)
33+
}
34+
35+
pub unsafe fn set_administrator_trade_actions(&self, actions: [i32; 20]) {
36+
self.set(0x2f4, &actions)
37+
}
2638
}
2739

2840
impl P3Pointer for OfficePtr {

p3-api/src/data/p3_ptr.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::ptr;
22

3-
pub trait P3Pointer {
3+
pub trait P3Pointer: Sized {
44
fn get_address(&self) -> u32;
55

66
/// # Safety
@@ -19,4 +19,8 @@ pub trait P3Pointer {
1919
let address = self.get_address() + offset;
2020
ptr::copy(data as *const _ as _, address as *mut u8, std::mem::size_of::<T>());
2121
}
22+
23+
unsafe fn free(self) {
24+
crate::free(self.get_address());
25+
}
2226
}

p3-api/src/game_world.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,8 @@ impl GameWorldPtr {
8080
unsafe { self.get(0x18) }
8181
}
8282

83-
pub fn get_town_id(&self, index: u8) -> Option<TownId> {
84-
assert!(index < 40);
85-
FromPrimitive::from_u8(unsafe { self.get(0x18 + index as u32) })
83+
pub fn get_town_id(&self, index: u8) -> TownId {
84+
FromPrimitive::from_u8(unsafe { self.get(0x18 + index as u32) }).unwrap()
8685
}
8786

8887
pub fn get_town(&self, town_index: u8) -> TownPtr {
@@ -121,6 +120,26 @@ impl GameWorldPtr {
121120
MerchantPtr::new(base_address + index as u32 * MERCHANT_SIZE)
122121
}
123122

123+
pub unsafe fn get_office_index(&self, town_index: u8, merchant_id: u16) -> Option<u16> {
124+
let offices_count = self.get_offices_count();
125+
let town = self.get_town(town_index);
126+
let mut office_index = town.get_first_office_index();
127+
loop {
128+
if office_index >= offices_count {
129+
return None;
130+
}
131+
132+
let office = self.get_office(office_index);
133+
if office.get_merchant_index() == merchant_id {
134+
trace!("returning office {:#x}", office_index);
135+
return Some(office_index);
136+
}
137+
138+
trace!("{:?} belongs to someone else {:#x}", &office, office.get_merchant_index());
139+
office_index = office.get_next_office_in_town_index();
140+
}
141+
}
142+
124143
pub unsafe fn get_office_in_of(&self, town_index: u8, merchant_id: u16) -> Option<OfficePtr> {
125144
let offices_count = self.get_offices_count();
126145
let town = self.get_town(town_index);
@@ -131,13 +150,13 @@ impl GameWorldPtr {
131150
}
132151

133152
let office = self.get_office(office_id);
134-
if office.get_merchant_id() == merchant_id {
153+
if office.get_merchant_index() == merchant_id {
135154
trace!("returning office {:#x}", office_id);
136155
return Some(office);
137156
}
138157

139-
trace!("{:?} belongs to someone else {:#x}", &office, office.get_merchant_id());
140-
office_id = office.next_office_in_town_index();
158+
trace!("{:?} belongs to someone else {:#x}", &office, office.get_merchant_index());
159+
office_id = office.get_next_office_in_town_index();
141160
}
142161
}
143162

p3-api/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![allow(clippy::missing_safety_doc)]
2+
23
extern crate num_derive;
34

45
pub mod class35;
@@ -41,3 +42,8 @@ pub unsafe fn latin1_ptr_to_string(mut s: *const u8) -> String {
4142
}
4243
result
4344
}
45+
46+
pub unsafe fn free(address: u32) {
47+
let orig: extern "cdecl" fn(ptr: u32) = std::mem::transmute(0x0063A1B6);
48+
orig(address);
49+
}

p3-api/src/merchant.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ impl MerchantPtr {
1212
Self { address }
1313
}
1414

15+
pub fn get_first_office_index(&self) -> u16 {
16+
unsafe { self.get(0x0c) }
17+
}
18+
1519
pub fn get_first_ship_index(&self) -> u16 {
1620
unsafe { self.get(0x0e) }
1721
}

p3-api/src/operation.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ pub enum Operation {
2323
RepairShip {
2424
ship_index: u32,
2525
},
26+
ShipMoveWares {
27+
amount: i32,
28+
ship_index: u16,
29+
ware_id: WareId,
30+
merchant_index: u16,
31+
to_ship: bool,
32+
},
2633
MoveWaresConvoy {
2734
raw_amount: i32,
2835
convoy_index: u16,
@@ -78,6 +85,22 @@ impl Operation {
7885
op[0..4].copy_from_slice(&opcode.to_le_bytes());
7986
op[0x04..0x08].copy_from_slice(&ship_id.to_le_bytes());
8087
}
88+
Operation::ShipMoveWares {
89+
amount,
90+
ship_index,
91+
ware_id,
92+
merchant_index,
93+
to_ship,
94+
} => {
95+
let opcode: u32 = 0x08;
96+
let ware_id: u16 = *ware_id as _;
97+
op[0x00..0x04].copy_from_slice(&opcode.to_le_bytes());
98+
op[0x04..0x08].copy_from_slice(&amount.to_le_bytes());
99+
op[0x08..0x0a].copy_from_slice(&ship_index.to_le_bytes());
100+
op[0x0a..0x0c].copy_from_slice(&ware_id.to_le_bytes());
101+
op[0x0c..0x0e].copy_from_slice(&merchant_index.to_le_bytes());
102+
op[0x0e] = *to_ship as u8;
103+
}
81104
Operation::MoveWaresConvoy {
82105
raw_amount: amount,
83106
convoy_index: convoy_id,

0 commit comments

Comments
 (0)