Skip to content

Commit b6d0c51

Browse files
committed
council meeting
1 parent 8a2705c commit b6d0c51

File tree

5 files changed

+149
-2
lines changed

5 files changed

+149
-2
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [Update Shipyard Experience](./scheduled-tasks/0006-update-shipyard-experience.md)
2121
- [Celebration](./scheduled-tasks/0007-celebration.md)
2222
- [Update Sailor Pools](./scheduled-tasks/0026-update-sailor-pools.md)
23+
- [Council Meeting](./scheduled-tasks/002e-council-meeting.md)
2324
- [Unfreeze Port](./scheduled-tasks/0053-unfreeze-port.md)
2425
- [Towns](./towns.md)
2526
- [Ticks](./towns/ticks.md)

src/operations/0048-make-town-hall-offer.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ struct operation_48_make_town_hall_offer
1717
```
1818

1919
## Normal Towns
20-
For normal towns a *Council Meeting* scheduled task is scheduled at `0xE00` ticks (14 days) ahead.
20+
For normal towns a *Council Meeting* scheduled task is scheduled at the given *meeting timestamp*.
2121

2222
## Hanseatic Settlements
2323
Hanseatic settlements have no council and expand military or enlarge town wall offers.
24-
A change to the head tax is applied immediately, and an *Extra Tax* scheduled task is scheduled at the next tick.
24+
A change to the head tax is applied immediately, an *Extra Tax* scheduled task is scheduled at the next tick.
50.5 KB
Loading
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Council Meeting
2+
The `handle_st_2e_council_meeting` function at `0x004E9A94` handles the entire council meeting voting process by rescheduling itself multiple times.
3+
4+
```c
5+
struct scheduled_task_2e_council_meeting
6+
{
7+
signed __int32 field_0_extra_tax_amount;
8+
unsigned __int8 field_4_town_index;
9+
council_meeting_type field_5_meeting_type;
10+
char field_6_pending_yes;
11+
char field_7_pending_no;
12+
unsigned __int8 field_8_yes;
13+
unsigned __int8 field_9_no;
14+
char field_A_maybe_abstain;
15+
unsigned __int8 field_B_player_vote_bitmask;
16+
signed __int16 field_C_tax_per_head_amount;
17+
char field_E_merchant_index;
18+
char field_F;
19+
};
20+
```
21+
22+
## First Execution
23+
On the first tick of the day (and thus the first tick of the meeting), the task is initialized:
24+
- `pending_no` is set to `22`.
25+
- `pending_no` is decreased by `1` for every bribed councillor.
26+
- For every player merchant:
27+
- If the merchant is a councillor or higher, a notification is sent to the player.
28+
- `pending_no` is decreased by `1` for a councillor, by `2` for a patrician and mayor, and by `3` for an alderman.
29+
- Should `pending_no` be smaller than `4`, it is set to `4`.
30+
31+
Afterwards the offer-specific votes in favour are determined, and the task is rescheduled at 4 ticks in the future.
32+
33+
### Extra Tax
34+
TODO
35+
36+
### Enlarge Town Walls
37+
TODO
38+
39+
### Expand Military
40+
The expand military voting behaviour is calculated as follows:
41+
```python
42+
if town.is_under_siege():
43+
total_citizens *= 2
44+
45+
t = 512 - 203 * town.approved_militia_size + total_citizens
46+
if t < 100:
47+
pending_yes = pending_no // 10
48+
elif t <= 920:
49+
pending_yes = pending_no * t // 256
50+
else:
51+
pending_yes = 9 * pending_no // 10
52+
53+
pending_no -= pending_yes
54+
```
55+
56+
This causes the following relationship of citizens and military size:
57+
![](002e-council-meeting-approved-limits.png)
58+
59+
### Change Tax per Head
60+
TODO
61+
62+
## Subsequent Executions
63+
If `pending_no` and `pending_yes` are bigger than `0`, the yes vote count is increased if the following formula is true:
64+
```python
65+
yes + 3 * pending_yes <= no + 3 * pending_no
66+
```
67+
Otherwise the no vote count is increased.
68+
69+
If only one of `pending_no` and `pending_yes` is bigger than `0`, the corresponding vote count is increased.
70+
71+
If both `pending_no` and `pending_yes` are `0`, no vote count is increased.
72+
73+
If the least significant byte of the timestamp is smaller than `0xDC`, the scheduled task is rescheduled at 4 ticks in the future.
74+
Otherwise the task is rescheduled at the next tick.
75+
76+
77+
## Final Execution and Result
78+
During the execution of the task on the first tick of the following day the result of the ballot is determined and applied.
79+
80+
### Extra Tax
81+
TODO
82+
83+
### Enlarge Town Walls
84+
TODO
85+
86+
### Expand Military
87+
If the town's old approved military size is below `0x8000`, it is increased by `10`.
88+
89+
### Change Tax per Head
90+
TODO
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
4+
5+
def is_upgrade_approved(rank: int, total_citizens: int, old_approved_size: int, under_siege: bool) -> bool:
6+
no = 22
7+
# Assuming no bribes
8+
# Assuming singleplayer
9+
if rank == 4:
10+
no -= 1 # Councillor
11+
elif rank == 5:
12+
no -= 2 # Patrician
13+
else:
14+
no -= 3 # Mayor/Alderman
15+
16+
if under_siege:
17+
total_citizens *= 2
18+
19+
t = 512 - 203 * old_approved_size + total_citizens
20+
if t < 100:
21+
yes = no // 10
22+
elif t <= 920:
23+
yes = no * t >> 10
24+
else:
25+
yes = 9 * no // 10
26+
no -= yes
27+
28+
if rank == 4:
29+
yes += 1
30+
else:
31+
yes += 3
32+
33+
return yes > no
34+
35+
36+
def plot_approved_limit_per_citizens():
37+
plt.clf()
38+
plt.title("Militia Expansion Votes (Singleplayer, Alderman, No Bribes)")
39+
plt.xlabel("Total Citizens")
40+
plt.ylabel("Approved Size")
41+
x_data = []
42+
y_data = []
43+
44+
for x in range(1_000, 6_000):
45+
x_data.append(x)
46+
for old_approved_size in range(1, 100).__reversed__():
47+
if is_upgrade_approved(7, x, old_approved_size, False):
48+
y_data.append(old_approved_size)
49+
break
50+
51+
52+
plt.plot(x_data, y_data, linewidth=1)
53+
plt.savefig("002e-council-meeting-approved-limits.png", dpi=200)
54+
55+
56+
plot_approved_limit_per_citizens()

0 commit comments

Comments
 (0)