2015-07-27 06:46:01 -06:00
-- create-unit.lua
-- Originally created by warmist, edited by Putnam for the dragon ball mod to be used in reactions, modified by Dirst for use in The Earth Strikes Back mod, incorporating fixes discovered by Boltgun then Mifiki wrote the bit where it switches to arena mode briefly to do some of the messy work, then Expwnent combined that with the old script to make it function for histfigs
2016-03-01 22:40:34 -07:00
-- version 0.51
2015-07-27 06:46:01 -06:00
-- This is a beta version. Use at your own risk.
2016-03-01 22:40:34 -07:00
-- Modifications from 0.5: civ -1 creates are NOT historical figures, mitigated screen-movement bug in createUnit()
2015-09-15 00:19:09 -06:00
--[[
TODO
children and babies : set child / baby job
confirm body size is computed appropriately for different ages / life stages
incarnate pre - existing historical figures
some sort of invasion helper script
set invasion_id , etc
announcement for fake natural birth if appropriate
] ]
2015-10-23 17:57:04 -06:00
--[[=begin
modtools / create - unit
====================
Creates a unit . Use ` ` modtools / create - unit - help ` ` for more info .
= end ] ]
2015-09-15 00:19:09 -06:00
2015-07-27 06:46:01 -06:00
--[[
if dfhack.gui . getCurViewscreen ( ) . _type ~= df.viewscreen_dwarfmodest or df.global . ui.main . mode ~= df.ui_sidebar_mode . LookAround then
print ' activate loo[k] mode '
return
end
--]]
local utils = require ' utils '
function createUnit ( race_id , caste_id )
2016-03-01 22:40:34 -07:00
local view_x = df.global . window_x
local view_y = df.global . window_y
local view_z = df.global . window_z
2015-07-27 06:46:01 -06:00
local curViewscreen = dfhack.gui . getCurViewscreen ( )
local dwarfmodeScreen = df.viewscreen_dwarfmodest : new ( )
curViewscreen.child = dwarfmodeScreen
dwarfmodeScreen.parent = curViewscreen
local oldMode = df.global . ui.main . mode
df.global . ui.main . mode = df.ui_sidebar_mode . LookAround
local gui = require ' gui '
df.global . world.arena_spawn . race : resize ( 0 )
df.global . world.arena_spawn . race : insert ( 0 , race_id ) --df.global.ui.race_id)
df.global . world.arena_spawn . caste : resize ( 0 )
df.global . world.arena_spawn . caste : insert ( 0 , caste_id )
df.global . world.arena_spawn . creature_cnt : resize ( 0 )
df.global . world.arena_spawn . creature_cnt : insert ( 0 , 0 )
--df.global.world.arena_spawn.equipment.skills:insert(0,99)
--df.global.world.arena_spawn.equipment.skill_levels:insert(0,0)
2015-11-09 15:25:55 -07:00
local old_gametype = df.global . gametype
df.global . gametype = df.game_type . DWARF_ARENA
2015-09-15 00:19:09 -06:00
2015-07-27 06:46:01 -06:00
gui.simulateInput ( dfhack.gui . getCurViewscreen ( ) , ' D_LOOK_ARENA_CREATURE ' )
gui.simulateInput ( dfhack.gui . getCurViewscreen ( ) , ' SELECT ' )
2015-11-09 15:25:55 -07:00
df.global . gametype = old_gametype
2015-07-27 06:46:01 -06:00
curViewscreen.child = nil
dwarfmodeScreen : delete ( )
df.global . ui.main . mode = oldMode
local id = df.global . unit_next_id - 1
2016-03-01 22:40:34 -07:00
df.global . window_x = view_x
df.global . window_y = view_y
df.global . window_z = view_z
2015-07-27 06:46:01 -06:00
return id
end
--local u = df.unit.find(df.global.unit_next_id-1)
--u.civ_id = df.global.ui.civ_id
--u.population_id = df.historical_entity.find(df.global.ui.civ_id).populations[0]
--local group = df.global.ui.group_id
-- Picking a caste or gender at random
function getRandomCasteId ( race_id )
2015-09-15 00:19:09 -06:00
local cr = df.creature_raw . find ( race_id )
local caste_id , casteMax
2015-07-27 06:46:01 -06:00
2015-09-15 00:19:09 -06:00
casteMax = # cr.caste - 1
2015-07-27 06:46:01 -06:00
2015-09-15 00:19:09 -06:00
if casteMax > 0 then
return math.random ( 0 , casteMax )
end
2015-07-27 06:46:01 -06:00
2015-09-15 00:19:09 -06:00
return 0
2015-07-27 06:46:01 -06:00
end
local function allocateNewChunk ( hist_entity )
2015-09-15 00:19:09 -06:00
hist_entity.save_file_id = df.global . unit_chunk_next_id
df.global . unit_chunk_next_id = df.global . unit_chunk_next_id + 1
hist_entity.next_member_idx = 0
print ( " allocating chunk: " , hist_entity.save_file_id )
2015-07-27 06:46:01 -06:00
end
local function allocateIds ( nemesis_record , hist_entity )
2015-09-15 00:19:09 -06:00
if hist_entity.next_member_idx == 100 then
allocateNewChunk ( hist_entity )
end
nemesis_record.save_file_id = hist_entity.save_file_id
nemesis_record.member_idx = hist_entity.next_member_idx
hist_entity.next_member_idx = hist_entity.next_member_idx + 1
2015-07-27 06:46:01 -06:00
end
function createFigure ( trgunit , he , he_group )
2015-09-15 00:19:09 -06:00
local hf = df.historical_figure : new ( )
hf.id = df.global . hist_figure_next_id
hf.race = trgunit.race
hf.caste = trgunit.caste
hf.profession = trgunit.profession
hf.sex = trgunit.sex
df.global . hist_figure_next_id = df.global . hist_figure_next_id + 1
hf.appeared_year = df.global . cur_year
2015-10-26 19:02:03 -06:00
2015-09-15 00:19:09 -06:00
hf.born_year = trgunit.relations . birth_year
hf.born_seconds = trgunit.relations . birth_time
hf.curse_year = trgunit.relations . curse_year
hf.curse_seconds = trgunit.relations . curse_time
hf.birth_year_bias = trgunit.relations . birth_year_bias
hf.birth_time_bias = trgunit.relations . birth_time_bias
hf.old_year = trgunit.relations . old_year
hf.old_seconds = trgunit.relations . old_time
hf.died_year = - 1
hf.died_seconds = - 1
hf.name : assign ( trgunit.name )
hf.civ_id = trgunit.civ_id
hf.population_id = trgunit.population_id
hf.breed_id = - 1
hf.unit_id = trgunit.id
df.global . world.history . figures : insert ( " # " , hf )
hf.info = df.historical_figure_info : new ( )
hf.info . unk_14 = df.historical_figure_info . T_unk_14 : new ( ) -- hf state?
--unk_14.region_id = -1; unk_14.beast_id = -1; unk_14.unk_14 = 0
hf.info . unk_14.unk_18 = - 1 ; hf.info . unk_14.unk_1c = - 1
-- set values that seem related to state and do event
--change_state(hf, dfg.ui.site_id, region_pos)
--lets skip skills for now
--local skills = df.historical_figure_info.T_skills:new() -- skills snap shot
-- ...
-- note that innate skills are automaticaly set by DF
hf.info . skills = { new = true }
he.histfig_ids : insert ( ' # ' , hf.id )
he.hist_figures : insert ( ' # ' , hf )
if he_group then
he_group.histfig_ids : insert ( ' # ' , hf.id )
he_group.hist_figures : insert ( ' # ' , hf )
hf.entity_links : insert ( " # " , { new = df.histfig_entity_link_memberst , entity_id = he_group.id , link_strength = 100 } )
end
trgunit.flags1 . important_historical_figure = true
trgunit.flags2 . important_historical_figure = true
trgunit.hist_figure_id = hf.id
trgunit.hist_figure_id2 = hf.id
hf.entity_links : insert ( " # " , { new = df.histfig_entity_link_memberst , entity_id = trgunit.civ_id , link_strength = 100 } )
--add entity event
local hf_event_id = df.global . hist_event_next_id
df.global . hist_event_next_id = df.global . hist_event_next_id + 1
df.global . world.history . events : insert ( " # " , { new = df.history_event_add_hf_entity_linkst , year = trgunit.relations . birth_year ,
seconds = trgunit.relations . birth_time , id = hf_event_id , civ = hf.civ_id , histfig = hf.id , link_type = 0 } )
return hf
2015-07-27 06:46:01 -06:00
end
2015-09-15 00:19:09 -06:00
2015-07-27 06:46:01 -06:00
function createNemesis ( trgunit , civ_id , group_id )
2015-09-15 00:19:09 -06:00
local id = df.global . nemesis_next_id
local nem = df.nemesis_record : new ( )
nem.id = id
nem.unit_id = trgunit.id
nem.unit = trgunit
nem.flags : resize ( 4 )
--not sure about these flags...
-- [[
nem.flags [ 4 ] = true
nem.flags [ 5 ] = true
nem.flags [ 6 ] = true
nem.flags [ 7 ] = true
nem.flags [ 8 ] = true
nem.flags [ 9 ] = true
--]]
--[[for k=4,8 do
nem.flags [ k ] = true
end ] ]
nem.unk10 =- 1
nem.unk11 =- 1
nem.unk12 =- 1
df.global . world.nemesis . all : insert ( " # " , nem )
df.global . nemesis_next_id = id + 1
trgunit.general_refs : insert ( " # " , { new = df.general_ref_is_nemesisst , nemesis_id = id } )
trgunit.flags1 . important_historical_figure = true
nem.save_file_id =- 1
local he = df.historical_entity . find ( civ_id )
he.nemesis_ids : insert ( " # " , id )
he.nemesis : insert ( " # " , nem )
local he_group
if group_id and group_id ~=- 1 then
he_group = df.historical_entity . find ( group_id )
end
if he_group then
he_group.nemesis_ids : insert ( " # " , id )
he_group.nemesis : insert ( " # " , nem )
end
allocateIds ( nem , he )
nem.figure = createFigure ( trgunit , he , he_group )
2015-07-27 06:46:01 -06:00
end
--createNemesis(u, u.civ_id,group)
function createUnitInCiv ( race_id , caste_id , civ_id , group_id )
local uid = createUnit ( race_id , caste_id )
local unit = df.unit . find ( uid )
if ( civ_id ) then
createNemesis ( unit , civ_id , group_id )
end
return uid
end
function createUnitInFortCiv ( race_id , caste_id )
return createUnitInCiv ( race_id , caste_id , df.global . ui.civ_id )
end
function createUnitInFortCivAndGroup ( race_id , caste_id )
return createUnitInCiv ( race_id , caste_id , df.global . ui.civ_id , df.global . ui.group_id )
end
function domesticate ( uid , group_id )
local u = df.unit . find ( uid )
group_id = group_id or df.global . ui.group_id
-- If a friendly animal, make it domesticated. From Boltgun & Dirst
local caste = df.creature_raw . find ( u.race ) . caste [ u.caste ]
if not ( caste.flags . CAN_SPEAK and caste.flags . CAN_LEARN ) then
-- Fix friendly animals (from Boltgun)
u.flags2 . resident = false ;
u.flags3 . body_temp_in_range = true ;
u.population_id = - 1
u.status . current_soul.unit_id = u.id
u.animal . population.region_x = - 1
u.animal . population.region_y = - 1
u.animal . population.unk_28 = - 1
u.animal . population.population_idx = - 1
u.animal . population.depth = - 1
u.counters . soldier_mood_countdown = - 1
u.counters . death_cause = - 1
u.enemy . anon_4 = - 1
u.enemy . anon_5 = - 1
u.enemy . anon_6 = - 1
-- And make them tame (from Dirst)
u.flags1 . tame = true
u.training_level = 7
end
end
2016-03-01 22:40:34 -07:00
function wild ( uid )
local u = df.unit . find ( uid )
local caste = df.creature_raw . find ( u.race ) . caste [ u.caste ]
-- x = df.global.world.world_data.active_site[0].pos.x
-- y = df.global.world.world_data.active_site[0].pos.y
-- region = df.global.map.map_blocks[df.global.map.x_count_block*x+y]
if not ( caste.flags . CAN_SPEAK and caste.flags . CAN_LEARN ) then
u.animal . population.region_x = 1
u.animal . population.region_y = 1
u.animal . population.unk_28 = - 1
u.animal . population.population_idx = 1
u.animal . population.depth = 0
end
end
2015-07-27 06:46:01 -06:00
function nameUnit ( id , entityRawName , civ_id )
--pick a random appropriate name
--choose three random words in the appropriate things
local unit = df.unit . find ( id )
local entity_raw
if entityRawName then
for k , v in ipairs ( df.global . world.raws . entities ) do
if v.code == entityRawName then
entity_raw = v
break
end
end
else
local entity = df.historical_entity . find ( civ_id )
entity_raw = entity.entity_raw
end
2015-09-15 00:19:09 -06:00
2015-07-27 06:46:01 -06:00
if not entity_raw then
error ( ' entity raw = nil: ' , id , entityRawName , civ_id )
end
2015-09-15 00:19:09 -06:00
2015-07-27 06:46:01 -06:00
local translation = entity_raw.translation
local translationIndex
for k , v in ipairs ( df.global . world.raws . language.translations ) do
if v.name == translation then
translationIndex = k
break
end
end
--translation = df.language_translation.find(translation)
local language_word_table = entity_raw.symbols . symbols1 [ 0 ] --educated guess
function randomWord ( )
local index = math.random ( 0 , # language_word_table.words [ 0 ] - 1 )
return index
end
local firstName = randomWord ( )
local lastName1 = randomWord ( )
local lastName2 = randomWord ( )
local name = unit.status . current_soul.name
name.words [ 0 ] = language_word_table.words [ 0 ] [ lastName1 ]
name.parts_of_speech [ 0 ] = language_word_table.parts [ 0 ] [ lastName1 ]
name.words [ 1 ] = language_word_table.words [ 0 ] [ lastName2 ]
name.parts_of_speech [ 1 ] = language_word_table.parts [ 0 ] [ lastName2 ]
name.first_name = df.language_word . find ( language_word_table.words [ 0 ] [ firstName ] ) . forms [ language_word_table.parts [ 0 ] [ firstName ] ]
name.has_name = true
name.language = translationIndex
name = unit.name
name.words [ 0 ] = language_word_table.words [ 0 ] [ lastName1 ]
name.parts_of_speech [ 0 ] = language_word_table.parts [ 0 ] [ lastName1 ]
name.words [ 1 ] = language_word_table.words [ 0 ] [ lastName2 ]
name.parts_of_speech [ 1 ] = language_word_table.parts [ 0 ] [ lastName2 ]
name.first_name = df.language_word . find ( language_word_table.words [ 0 ] [ firstName ] ) . forms [ language_word_table.parts [ 0 ] [ firstName ] ]
name.has_name = true
name.language = translationIndex
if unit.hist_figure_id ~= - 1 then
local histfig = df.historical_figure . find ( unit.hist_figure_id )
name = histfig.name
name.words [ 0 ] = language_word_table.words [ 0 ] [ lastName1 ]
name.parts_of_speech [ 0 ] = language_word_table.parts [ 0 ] [ lastName1 ]
name.words [ 1 ] = language_word_table.words [ 0 ] [ lastName2 ]
name.parts_of_speech [ 1 ] = language_word_table.parts [ 0 ] [ lastName2 ]
name.first_name = df.language_word . find ( language_word_table.words [ 0 ] [ firstName ] ) . forms [ language_word_table.parts [ 0 ] [ firstName ] ]
name.has_name = true
name.language = translationIndex
end
end
validArgs = --[[validArgs or]] utils.invert ( {
' help ' ,
' race ' ,
' caste ' ,
' domesticate ' ,
' civId ' ,
' groupId ' ,
' flagSet ' ,
' flagClear ' ,
' name ' ,
2015-10-26 19:02:03 -06:00
' nick ' ,
2015-09-14 23:07:31 -06:00
' location ' ,
' age '
2015-07-27 06:46:01 -06:00
} )
if moduleMode then
return
end
local args = utils.processArgs ( { ... } , validArgs )
if args.help then
2015-09-15 00:19:09 -06:00
print (
2015-09-14 23:07:31 -06:00
[ [ scripts / modtools / create - unit.lua
arguments :
- help
print this help message
- race raceName
specify the race of the unit to be created
examples :
DWARF
HUMAN
- caste casteName
specify the caste of the unit to be created
examples :
MALE
FEMALE
2015-09-15 00:19:09 -06:00
- domesticate
if the unit can ' t learn or can ' t speak , then make it a friendly animal
2015-09-14 23:07:31 -06:00
- civId id
2015-09-15 00:19:09 -06:00
make the created unit a member of the specified civ ( or none if id = - 1 )
if id is \ \ LOCAL , then make it a member of the civ associated with the current fort
otherwise id must be an integer
- groupId id
make the created unit a member of the specified group ( or none if id = - 1 )
if id is \ \ LOCAL , then make it a member of the group associated with the current fort
otherwise id must be an integer
- name entityRawName
set the unit ' s name to be a random name appropriate for the given entity
examples :
MOUNTAIN
2015-10-26 19:02:03 -06:00
- nick nickname
set the unit ' s nickname directly
2015-09-14 23:07:31 -06:00
- location [ x y z ]
2015-09-15 00:19:09 -06:00
create the unit at the specified coordinates
- age howOld
set the birth date of the unit to the specified number of years ago
2015-09-14 23:07:31 -06:00
- flagSet [ flag1 flag2 ... ]
2015-09-15 00:19:09 -06:00
set the specified unit flags in the new unit to true
flags may be selected from df.unit_flags1 , df.unit_flags2 , or df.unit_flags3
- flagClear [ flag1 flag2 ... ]
set the specified unit flags in the new unit to false
flags may be selected from df.unit_flags1 , df.unit_flags2 , or df.unit_flags3
2015-09-14 23:07:31 -06:00
] ] )
2015-09-15 00:19:09 -06:00
return
2015-07-27 06:46:01 -06:00
end
local race
local raceIndex
local casteIndex
if not args.race or not args.caste then
error ' Specfiy a race and caste for the new unit. '
end
--find race
for i , v in ipairs ( df.global . world.raws . creatures.all ) do
if v.creature_id == args.race then
raceIndex = i
race = v
break
end
end
if not race then
error ' Invalid race. '
end
for i , v in ipairs ( race.caste ) do
if v.caste_id == args.caste then
casteIndex = i
break
end
end
if not casteIndex then
error ' Invalid caste. '
end
2015-09-14 23:36:29 -06:00
local age
if args.age then
age = tonumber ( args.age )
if not age and not age == 0 then
error ( ' Invalid age: ' .. args.age )
end
end
2015-07-27 06:46:01 -06:00
local civ_id
if args.civId == ' \\ LOCAL ' then
civ_id = df.global . ui.civ_id
2016-03-01 22:40:34 -07:00
elseif args.civId and tonumber ( args.civId ) then
2015-07-27 06:46:01 -06:00
civ_id = tonumber ( args.civId )
end
local group_id
if args.groupId == ' \\ LOCAL ' then
group_id = df.global . ui.group_id
elseif args.groupId and tonumber ( args.groupId ) then
group_id = tonumber ( args.groupId )
end
2016-03-01 22:40:34 -07:00
local unitId
if civ_id == - 1 then
unitId = createUnit ( raceIndex , casteIndex )
else
unitId = createUnitInCiv ( raceIndex , casteIndex , civ_id , group_id )
end
2016-03-02 02:39:59 -07:00
2015-07-27 06:46:01 -06:00
if args.domesticate then
domesticate ( unitId , group_id )
2016-03-01 22:40:34 -07:00
else
wild ( unitId )
2015-07-27 06:46:01 -06:00
end
2015-09-15 01:17:57 -06:00
if age or age == 0 then
2015-09-14 23:36:29 -06:00
local u = df.unit . find ( unitId )
local oldYearDelta = u.relations . old_year - u.relations . birth_year
u.relations . birth_year = df.global . cur_year - age
u.relations . old_year = u.relations . birth_year + oldYearDelta
--these flags are an educated guess of how to get the game to compute sizes correctly: use -flagSet and -flagClear arguments to override or supplement
u.flags2 . calculated_nerves = false
u.flags2 . calculated_bodyparts = false
u.flags3 . body_part_relsize_computed = false
u.flags3 . size_modifier_computed = false
u.flags3 . compute_health = true
u.flags3 . weight_computed = false
--TODO: if the unit is a child or baby it will still behave like an adult
end
2015-07-27 06:46:01 -06:00
if args.flagSet or args.flagClear then
local u = df.unit . find ( unitId )
local flagsToSet = { }
local flagsToClear = { }
for _ , v in ipairs ( args.flagSet or { } ) do
flagsToSet [ v ] = true
end
for _ , v in ipairs ( args.flagClear or { } ) do
flagsToClear [ v ] = true
end
for _ , k in ipairs ( df.unit_flags1 ) do
if flagsToSet [ k ] then
u.flags1 [ k ] = true ;
elseif flagsToClear [ k ] then
u.flags1 [ k ] = false ;
end
end
for _ , k in ipairs ( df.unit_flags2 ) do
if flagsToSet [ k ] then
u.flags2 [ k ] = true ;
elseif flagsToClear [ k ] then
u.flags2 [ k ] = false ;
end
end
for _ , k in ipairs ( df.unit_flags3 ) do
if flagsToSet [ k ] then
u.flags3 [ k ] = true ;
elseif flagsToClear [ k ] then
u.flags3 [ k ] = false ;
end
end
end
if args.name then
nameUnit ( unitId , args.name , civ_id )
else
local unit = df.unit . find ( unitId )
unit.name . has_name = false
if unit.status . current_soul then
unit.status . current_soul.name . has_name = false
end
--[[if unit.hist_figure_id ~= -1 then
local histfig = df.historical_figure . find ( unit.hist_figure_id )
histfig.name . has_name = false
end --]]
end
2015-10-26 19:02:03 -06:00
if args.nick and type ( args.nick ) == ' string ' then
dfhack.units . setNickname ( df.unit . find ( unitId ) , args.nick )
end
2015-07-27 06:46:01 -06:00
if civ_id then
local u = df.unit . find ( unitId )
u.civ_id = civ_id
end
if args.location then
local u = df.unit . find ( unitId )
local pos = df.coord : new ( )
pos.x = tonumber ( args.location [ 1 ] )
pos.y = tonumber ( args.location [ 2 ] )
pos.z = tonumber ( args.location [ 3 ] )
local teleport = dfhack.script_environment ( ' teleport ' )
teleport.teleport ( u , pos )
end
--[[if group_id then
local u = df.unit . find ( unitId )
u.group_id = group_id
end --]]