Skip to content

Commit 9fc8c91

Browse files
committed
Price thresholds
1 parent 4a85b38 commit 9fc8c91

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Patrician 3 Insights
2+
3+
## Run Locally
4+
`mdbook serve`
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,191 @@
11
# Thresholds
2+
A town's price thresholds are updated by the `update_town_price_thresholds` function at `0x00528070` every time the town ticks.
3+
4+
The calculation is partially understood, but some aspects are still to be determined.
5+
The following pseudocode denotes what is known:
6+
```rust
7+
fn update_town_price_thresholds(town) {
8+
let mut thresholds = [[0; 4]; 24];
9+
let mut building_material_factor = 1;
10+
let mut extra_demand_bitmask = 0;
11+
let mut t1_days = 14;
12+
13+
// Consider the town's situation
14+
if town.flags & (TOWN_FLAG_SIEGE | TOWN_FLAG_BLOCKADE | TOWN_FLAG_PIRATE_ATTACK | TOWN_FLAG_FROZEN) != 0 {
15+
t1_days = 28;
16+
building_material_factor = 2;
17+
extra_demand_bitmask = ware_threshold_bitmask_grain |
18+
ware_threshold_bitmask_meat |
19+
ware_threshold_bitmask_fish |
20+
ware_threshold_bitmask_beer |
21+
ware_threshold_bitmask_salt |
22+
ware_threshold_bitmask_honey |
23+
ware_threshold_bitmask_spices |
24+
ware_threshold_bitmask_wine |
25+
ware_threshold_bitmask_timber;
26+
} else {
27+
if town.flags & TOWN_FLAG_FIRE != 0 {
28+
extra_demand_bitmask = ware_threshold_bitmask_grain |
29+
ware_threshold_bitmask_meat |
30+
ware_threshold_bitmask_fish |
31+
ware_threshold_bitmask_beer |
32+
ware_threshold_bitmask_salt |
33+
ware_threshold_bitmask_honey |
34+
ware_threshold_bitmask_spices |
35+
ware_threshold_bitmask_wine |
36+
ware_threshold_bitmask_timber;
37+
} else {
38+
if town.flags & TOWN_FLAG_FAMINE != 0 {
39+
extra_demand_bitmask = ware_threshold_bitmask_grain |
40+
ware_threshold_bitmask_meat |
41+
ware_threshold_bitmask_fish |
42+
ware_threshold_bitmask_beer |
43+
ware_threshold_bitmask_salt |
44+
ware_threshold_bitmask_honey |
45+
ware_threshold_bitmask_spices |
46+
ware_threshold_bitmask_wine;
47+
} else if own.flags & TOWN_FLAG_FAMINE != 0 {
48+
extra_demand_bitmask = ware_threshold_bitmask_grain |
49+
ware_threshold_bitmask_meat |
50+
ware_threshold_bitmask_fish |
51+
ware_threshold_bitmask_beer |
52+
ware_threshold_bitmask_salt |
53+
ware_threshold_bitmask_honey |
54+
ware_threshold_bitmask_spices;
55+
}
56+
}
57+
}
58+
59+
// Initialize t0 and t1 (for normale wares except bricks)
60+
for (_, threshold) in thresholds.iter_mut().enumerate().take(19) {
61+
let t0_days = if extra_demand_bitmask & 1 != 0 { 14 } else { 7 };
62+
threshold[0] = t0_days;
63+
threshold[1] = t0_days + t1_days;
64+
extra_demand_bitmask >>= 1;
65+
}
66+
67+
// Initialize t0 and t1 for the rest
68+
thresholds[WareId::Bricks][0] = 0;
69+
thresholds[WareId::Brick][1] = 0;
70+
thresholds[WareId::Sword][0] = 0;
71+
thresholds[WareId::Sword][1] = 0;
72+
thresholds[WareId::Bow][0] = 0;
73+
thresholds[WareId::Bow][1] = 0;
74+
thresholds[WareId::Crossbow][0] = 0;
75+
thresholds[WareId::Crossbow][1] = 0;
76+
thresholds[WareId::Carbine][0] = 0;
77+
thresholds[WareId::Carbine][1] = 0;
78+
79+
// Grain t1 bonus
80+
thresholds[WareId::Grain][1] += t1_days;
81+
82+
// Scale t0 and t1 with consumption
83+
for (i, threshold) in thresholds.iter_mut().enumerate().take(20) {
84+
let consumption = town.consumption_businesses[i]
85+
+ town.consumption_citizens[i]
86+
+ 1;
87+
threshold[0] *= consumption;
88+
threshold[1] *= consumption;
89+
}
90+
91+
// Siege pitch bonus
92+
if town.flags & TOWN_FLAG_SIEGE {
93+
thresholds[WareId::Pitch][0] += 7 * town.get_siege_pitch_consumption();
94+
thresholds[WareId::Pitch][1] += 14 * town.get_siege_pitch_consumption();
95+
}
96+
97+
// Seasonal t1 boni
98+
match now().month {
99+
Month::September => { // 0.15
100+
thresholds[WareId::Grain][1] += thresholds[WareId::Grain][1] * 3 / 20;
101+
thresholds[WareId::Wine][1] += thresholds[WareId::Wine][1] * 3 / 20;
102+
}
103+
Month::October => { // 0.3
104+
thresholds[WareId::Grain as usize][1] += thresholds[WareId::Grain as usize][1] * 3 / 10;
105+
thresholds[WareId::Wine as usize][1] += thresholds[WareId::Wine as usize][1] * 3 / 10;
106+
}
107+
Month::November => { // 0.2
108+
thresholds[WareId::Grain as usize][1] += thresholds[WareId::Grain as usize][1] / 5;
109+
thresholds[WareId::Wine as usize][1] += thresholds[WareId::Wine as usize][1] / 5;
110+
}
111+
Month::December => { // 0.1
112+
thresholds[WareId::Grain as usize][1] += thresholds[WareId::Grain as usize][1] / 10;
113+
thresholds[WareId::Wine as usize][1] += thresholds[WareId::Wine as usize][1] / 10;
114+
}
115+
_ => {}
116+
}
117+
118+
// Building material boni
119+
thresholds[WareId::Pitch][0] += 1800;
120+
thresholds[WareId::Bricks][0] += 80000 * building_material_factor;
121+
thresholds[WareId::Timber][0] += 42000;
122+
thresholds[WareId::Timber][1] += 84000;
123+
thresholds[WareId::Bricks][1] += 160000 * building_material_factor;
124+
thresholds[WareId::Pitch][1] += 3600;
125+
thresholds[WareId::Hemp][0] += 5000 * building_material_factor;
126+
thresholds[WareId::IronGoods][0] += 2000 * building_material_factor;
127+
thresholds[WareId::IronGoods][1] += 4000 * building_material_factor;
128+
129+
/*
130+
TODO: Weapons
131+
let mut scaled_citizens = 10 * town.citizens_total / 200;
132+
if town.flags & (TOWN_FLAG_SIEGE | TOWN_FLAG_PIRATE_ATTACK) != 0 {
133+
scaled_citizens *= 2;
134+
}
135+
*/
136+
137+
// Set t2 and t3 except for bricks and weapons
138+
for i in 0..19 {
139+
thresholds[i][2] = thresholds[i][1] + 10 * town.unidentified_array[i];
140+
thresholds[i][3] = thresholds[i][2] + thresholds[i][0];
141+
}
142+
143+
// Pitch and bricks production bonus
144+
if town.production[WareId::Pitch] > 0 {
145+
thresholds[WareId::Pitch][3] += 3600;
146+
}
147+
if town.production[WareId::Bricks] > 0 {
148+
thresholds[WareId::Bricks][3] += 160000;
149+
}
150+
151+
// Clothes bonus
152+
thresholds[WareId::Cloth][0] += 400;
153+
thresholds[WareId::Cloth][1] += 800;
154+
thresholds[WareId::Cloth][2] += 800;
155+
thresholds[WareId::Cloth][3] += 1600;
156+
157+
// Bricks t2 and t3
158+
if has_effective_bricks_production {
159+
thresholds[WareId::Bricks][2] = thresholds[WareId::Bricks][1] + town.unidentified_array[WareId::Bricks];
160+
thresholds[WareId::Bricks][3] = thresholds[WareId::Bricks][1] + 2 * town.unidentified_array[WareId::Bricks];
161+
} else if thresholds[WareId::Bricks][2] > 2 * thresholds[WareId::Bricks][1] {
162+
// TODO: can this every be true?
163+
thresholds[WareId::Bricks][2] = 2 * thresholds[WareId::Bricks][1];
164+
thresholds[WareId::Bricks][3] = 3 * thresholds[WareId::Bricks][1];
165+
}
166+
167+
// Enforce minima
168+
for (i, threshold) in thresholds.iter_mut().enumerate().take(20) {
169+
let ware_id = WareId::from_usize(i).unwrap();
170+
let minimum = if ware_id.is_barrel_ware() {
171+
1000
172+
} else {
173+
10000
174+
};
175+
if threshold[0] < minimum {
176+
threshold[0] = minimum;
177+
}
178+
let mut min = minimum + minimum;
179+
for j in 1..4 {
180+
if threshold[j] < min {
181+
threshold[j] = min;
182+
}
183+
if threshold[j] <= threshold[j - 1] {
184+
threshold[j] = threshold[j - 1] + minimum;
185+
}
186+
187+
min += minimum;
188+
}
189+
}
190+
}
191+
```

0 commit comments

Comments
 (0)