Skip to content

Instantly share code, notes, and snippets.

@pronvit
Last active March 1, 2021 16:29
Show Gist options
  • Save pronvit/e256267e3c65c0e89e08b1aa947df600 to your computer and use it in GitHub Desktop.
Save pronvit/e256267e3c65c0e89e08b1aa947df600 to your computer and use it in GitHub Desktop.
function find_race(name)
name = name:lower()
for i,v in ipairs(df.global.world.raws.creatures.all) do
if v.creature_id:lower() == name:lower() then
return i
end
end
end
function find_entity_for_race(race)
for i,v in ipairs(df.global.world.entities.all) do
if v.flags.named_civ and v.race == race then
return i
end
end
end
function find_entity_by_name(name)
name = name:lower()
for i,v in ipairs(df.global.world.entities.all) do
if v.flags.named_civ and dfhack.TranslateName(v.name, true):lower():find(name) then
return i
end
end
end
function find_cultural_identity(civ)
for i,v in ipairs(df.global.world.cultural_identities.all) do
if v.civ_id == civ then
return i
end
end
end
local utils = require 'utils'
validArgs = validArgs or utils.invert({
'civ',
'race',
'count',
'undead',
'cleanup',
'debug',
})
local args = utils.processArgs({...}, validArgs)
if not args.race or not args.count then
print 'You need to specify at least one race with -race parameter, and count with -count parameter'
return
end
local race_names = type(args.race) == 'table' and args.race or { args.race }
if type(args.count) == 'table' and #args.race ~= #args.count then
print 'Number of counts and races provided do not match'
return
end
local civ_id
if args.civ == 'self' then
civ_id = df.global.ui.civ_id
elseif args.civ then
local race_id = find_race(args.civ)
if race_id then
civ_id = find_entity_for_race(race_id)
if not civ_id then
print ('Could not find a named civilization for race ' .. args.civ)
return
end
else
civ_id = find_entity_by_name(args.civ)
if not civ_id then
print ('Could not find civilization ' .. args.civ)
return
end
end
else
local race_id = find_race(race_names[1])
civ_id = race_id and find_entity_for_race(race_id)
if not civ_id then
print ('Could not find a named civilization for race ' .. race_names[1])
return
end
end
local pop_id = df.historical_entity.find(civ_id).populations[0]
local cult_id = find_cultural_identity(civ_id)
if args.debug then
print ('Civilization "'.. dfhack.TranslateName(df.historical_entity.find(civ_id).name, true) .. '" ID ' .. civ_id)
end
-- Army
a = df.army:new()
a.id = df.global.army_next_id
df.global.army_next_id = df.global.army_next_id + 1
a.pos.x = 1000 -- can be anything
a.pos.y = 1000
a.last_pos.x = -1
a.last_pos.y = -1
a.unk_10 = 8 -- wait timer, decreased by 16 each tick, siege occurs when reaches zero
for i,race_name in ipairs(race_names) do
local race_id = find_race(race_name)
if not race_id then
print ('Could not find race ' .. race_name)
--todo: cleanup
return
end
local b = df.army.T_unk_2c:new()
b.count = type(args.count) == 'table' and args.count[i] or args.count
b.race = race_id
b.civ_id = civ_id
b.population_id = pop_id
b.cultural_identity = cult_id
b.unk_10 = 0 -- -> unit.unk_c0
b.unk_18 = args.undead and 100 or 0 -- from xml: made creatures undead, so not sure maybe affliction?
b.unk_1c = 0 -- from xml: crashed df...
b.unk_20 = 0 -- -> unit.enemy.anon_4
b.unk_24 = 0 -- -> unit.enemy.anon_5
b.unk_28 = 0
a.unk_2c:insert(0,b)
end
a.unk_3c = 50
a.unk_pos_x:insert(0,df.global.world.map.region_x*3)
a.unk_pos_y:insert(0,df.global.world.map.region_y*3)
a.unk_70:insert(0,100)
a.unk_80:insert(0,20)
a.unk_9c = 50
a.unk_a0 = 50
a.unk_a4 = 100
s = df.new('string')
s.value='GENERAL_POISON'
a.creature_class:insert(0,s)
-- Max(TM) pointed out these might be a tent material
a.item_type = 54
a.mat_type = 37
a.mat_index = 184
ac = df.army_controller:new()
ac.id=df.global.army_controller_next_id
df.global.army_controller_next_id = df.global.army_controller_next_id + 1
-- also ac.id -> unit.enemy.anon_6
-- Army controller
ac.entity_id = civ_id
ac.unk_8 = df.global.ui.site_id
ac.pos_x = df.global.world.map.region_x*3
ac.pos_y = df.global.world.map.region_y*3
ac.unk_14 = 50
ac.unk_18 = -1
ac.year = df.global.cur_year
ac.year_tick = df.global.cur_year_tick
ac.unk_34 = -1 -- these two are ids of other army controllers, some kind of relationship
ac.unk_38 = -1
-- Hesperid mentioned these are army leader and the civ leader, they will be visible in legends if present
ac.unk_3c = -1
ac.unk_40 = -1 -- -> history_event_war_attacked_sitest.attacker_general_hf
ac.unk_54 = 0
ac.type = 2
-- Something
t = df.new('char',100)
t[0]=4 --4
t[4]=1 --1
t[8]=-1 -- all -1
t[9]=-1
t[10]=-1
t[11]=-1
t[12]=-1 -- all -1
t[13]=-1
t[14]=-1
t[15]=-1
--0x42 0x07 0x00 0x00 0x7f 0x1b 0x00 0x00
t[0x5c] = 0x42 --1858
t[0x5d] = 0x7
t[0x60] = 0x7f --7039
t[0x61] = 0x1b
ac.unk_58 = t
if args.debug then
print('Army ID ' .. a.id)
print('Controller ID ' .. ac.id)
end
a.controller_id=ac.id
a.controller=ac
df.global.world.army_controllers.all:insert(#df.global.world.army_controllers.all,ac)
df.global.world.armies.all:insert(#df.global.world.armies.all,a)
-- Experimental
if args.cleanup then
df.global.pause_state = false
df.global.gview.view.child:logic()
df.global.pause_state = true
utils.erase_sorted_key(df.global.world.army_controllers.all, ac.id, 'id')
for i,unit in ipairs(df.global.world.units.all) do
if unit.enemy.anon_6 == ac.id then
unit.enemy.anon_6 = -1
end
end
df.delete(t)
ac.unk_58 = nil
ac:delete()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment