Skip to content

Commit 5894d49

Browse files
authored
Merge pull request #9 from LoireLab/9hdvkm-codex
Tie holy-war to deity spheres and grudges
2 parents 1d72e2a + dba3c1a commit 5894d49

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

docs/holy-war.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
holy-war
2+
========
3+
4+
.. dfhack-tool::
5+
:summary: Start wars when religions clash.
6+
:tags: fort gameplay diplomacy
7+
8+
This tool compares the spheres of influence represented by the gods of
9+
nearby civilizations with those worshipped by your civilization and
10+
represented in fortress temples. If no spheres overlap, or if the
11+
historical record shows a ``religious_persecution_grudge`` between the
12+
two peoples, the civilization is set to war.
13+
14+
Usage
15+
-----
16+
17+
::
18+
19+
holy-war [--dry-run]
20+
21+
When run without options, wars are declared immediately on all
22+
qualifying civilizations and an announcement is displayed. With
23+
``--dry-run``, the tool only reports which civilizations would be
24+
affected without actually changing diplomacy.

holy-war.lua

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
-- Trigger wars based on conflicts between deity spheres
2+
--@ module = true
3+
4+
local utils = require('utils')
5+
6+
local help = [====[
7+
holy-war
8+
========
9+
10+
Provoke wars with civilizations that do not share deity spheres with
11+
your civilization or the temples in your fortress. Religious
12+
persecution grudges in the historical record also trigger war.
13+
14+
Usage:
15+
holy-war [--dry-run]
16+
17+
If ``--dry-run`` is specified, no diplomatic changes are made and a list of
18+
potential targets is printed instead.
19+
]====]
20+
21+
local valid_args = utils.invert({ 'dry-run', 'help' })
22+
23+
local RELIGIOUS_PERSECUTION_GRUDGE =
24+
df.vague_relationship_type.RELIGIOUS_PERSECUTION_GRUDGE or
25+
df.vague_relationship_type.religious_persecution_grudge
26+
27+
local function merge(dst, src)
28+
for k in pairs(src) do dst[k] = true end
29+
end
30+
31+
local function get_deity_spheres(hfid)
32+
local spheres = {}
33+
local hf = df.historical_figure.find(hfid)
34+
if hf and hf.info and hf.info.metaphysical then
35+
for _, sph in ipairs(hf.info.metaphysical.spheres) do
36+
spheres[sph] = true
37+
end
38+
end
39+
return spheres
40+
end
41+
42+
local function get_civ_spheres(civ)
43+
local spheres = {}
44+
for _, deity_id in ipairs(civ.relations.deities) do
45+
merge(spheres, get_deity_spheres(deity_id))
46+
end
47+
return spheres
48+
end
49+
50+
local function get_fort_spheres()
51+
local spheres = {}
52+
for _, bld in ipairs(df.global.world.buildings.all) do
53+
if bld:getType() == df.building_type.Temple then
54+
local dtype = bld.deity_type
55+
if dtype == df.religious_practice_type.WORSHIP_HFID then
56+
merge(spheres, get_deity_spheres(bld.deity_data.HFID))
57+
elseif dtype == df.religious_practice_type.RELIGION_ENID then
58+
local rciv = df.historical_entity.find(bld.deity_data.Religion)
59+
if rciv then merge(spheres, get_civ_spheres(rciv)) end
60+
end
61+
end
62+
end
63+
return spheres
64+
end
65+
66+
local function union(a, b)
67+
local u = {}
68+
merge(u, a)
69+
merge(u, b)
70+
return u
71+
end
72+
73+
local function share(p1, p2)
74+
for k in pairs(p1) do
75+
if p2[k] then return true end
76+
end
77+
return false
78+
end
79+
80+
local function get_civ_hists(civ)
81+
local hfs = {}
82+
for _, id in ipairs(civ.histfig_ids) do hfs[id] = true end
83+
return hfs
84+
end
85+
86+
local function has_religious_grudge(p_hfs, t_hfs)
87+
if not RELIGIOUS_PERSECUTION_GRUDGE then return false end
88+
for _, set in ipairs(df.global.world.history.relationship_events) do
89+
for i = 0, set.next_element-1 do
90+
if set.relationship[i] == RELIGIOUS_PERSECUTION_GRUDGE then
91+
local src = set.source_hf[i]
92+
local tgt = set.target_hf[i]
93+
if (p_hfs[src] and t_hfs[tgt]) or (p_hfs[tgt] and t_hfs[src]) then
94+
return true
95+
end
96+
end
97+
end
98+
end
99+
return false
100+
end
101+
102+
local function change_relation(target, relation)
103+
local pciv = df.historical_entity.find(df.global.plotinfo.civ_id)
104+
for _, state in ipairs(pciv.relations.diplomacy.state) do
105+
if state.group_id == target.id then
106+
state.relation = relation
107+
end
108+
end
109+
for _, state in ipairs(target.relations.diplomacy.state) do
110+
if state.group_id == pciv.id then
111+
state.relation = relation
112+
end
113+
end
114+
end
115+
116+
local function main(...)
117+
local args = utils.processArgs({...}, valid_args)
118+
119+
if args.help then
120+
print(help)
121+
return
122+
end
123+
124+
local dry_run = args['dry-run']
125+
local pciv = df.historical_entity.find(df.global.plotinfo.civ_id)
126+
local player_spheres = union(get_civ_spheres(pciv), get_fort_spheres())
127+
local player_hfs = get_civ_hists(pciv)
128+
129+
for _, civ in ipairs(df.global.world.entities.all) do
130+
if civ.type == 0 and civ.id ~= pciv.id then
131+
local status
132+
for _, state in ipairs(pciv.relations.diplomacy.state) do
133+
if state.group_id == civ.id then
134+
status = state.relation
135+
break
136+
end
137+
end
138+
if status == 0 or status == nil then -- peace or unknown
139+
local civ_spheres = get_civ_spheres(civ)
140+
local civ_hfs = get_civ_hists(civ)
141+
if not share(player_spheres, civ_spheres) or
142+
has_religious_grudge(player_hfs, civ_hfs) then
143+
local name = dfhack.translation.translateName(civ.name, true)
144+
if dry_run then
145+
print(('Would declare war on %s over divine conflict.'):format(name))
146+
else
147+
change_relation(civ, 1) -- war
148+
dfhack.gui.showAnnouncement(
149+
('Religious persecution sparks war with %s!'):format(name),
150+
COLOR_RED, true)
151+
end
152+
end
153+
end
154+
end
155+
end
156+
end
157+
158+
if not dfhack_flags.module then
159+
main(...)
160+
end

0 commit comments

Comments
 (0)