Initial commit for modtools/create-unit.lua.

develop
expwnent 2015-07-27 08:46:01 -04:00
parent 83f89480aa
commit 7b91730352
4 changed files with 640 additions and 66 deletions

@ -4,17 +4,97 @@
local utils = require 'utils'
validArgs = validArgs or utils.invert({
validArgs = --[[validArgs or--]] utils.invert({
'help',
'creator',
'material',
'item',
-- 'creature',
-- 'caste',
'matchingGloves',
'matchingShoes'
'leftHand',
'rightHand',
'quality'
})
organicTypes = organicTypes or utils.invert({
df.item_type.REMAINS,
df.item_type.FISH,
df.item_type.FISH_RAW,
df.item_type.VERMIN,
df.item_type.PET,
df.item_type.EGG,
})
badTypes = badTypes or utils.invert({
df.item_type.CORPSE,
df.item_type.CORPSEPIECE,
df.item_type.FOOD,
})
function createItem(creatorID, item, material, leftHand, rightHand, quality)
local itemQuality = quality and df.item_quality[quality]
print(itemQuality)
local creator = df.unit.find(creatorID)
if not creator then
error 'Invalid creator.'
end
if not item then
error 'Invalid item.'
end
local itemType = dfhack.items.findType(item)
if itemType == -1 then
error 'Invalid item.'
end
local itemSubtype = dfhack.items.findSubtype(item)
if organicTypes[itemType] then
--TODO: look up creature and caste
error 'Not yet supported.'
end
if badTypes[itemType] then
error 'Not supported.'
end
if not material then
error 'Invalid material.'
end
local materialInfo = dfhack.matinfo.find(material)
if not materialInfo then
error 'Invalid material.'
end
local item1 = dfhack.items.createItem(itemType, itemSubtype, materialInfo['type'], materialInfo.index, creator)
local item = df.item.find(item1)
if leftHand then
item:setGloveHandedness(2)
elseif rightHand then
item:setGloveHandedness(1)
end
if itemQuality then
item:setQuality(itemQuality)
end
--[[if matchingGloves or matchingShoes then
if matchingGloves then
item1 = df.item.find(item1)
item1:setGloveHandedness(1);
end
local item2 = dfhack.items.createItem(itemType, itemSubtype, materialInfo['type'], materialInfo.index, creator)
if matchingGloves then
item2 = df.item.find(item2)
item2:setGloveHandedness(2);
end
end --]]
return item1
end
if moduleMode then
return
end
local args = utils.processArgs({...}, validArgs)
if args.help then
@ -46,65 +126,4 @@ arguments:
return
end
if not args.creator or not tonumber(args.creator) or not df.unit.find(tonumber(args.creator)) then
error 'Invalid creator.'
end
args.creator = df.unit.find(tonumber(args.creator))
if not args.creator then
error 'Invalid creator.'
end
if not args.item then
error 'Invalid item.'
end
local itemType = dfhack.items.findType(args.item)
if itemType == -1 then
error 'Invalid item.'
end
local itemSubtype = dfhack.items.findSubtype(args.item)
organicTypes = organicTypes or utils.invert({
df.item_type.REMAINS,
df.item_type.FISH,
df.item_type.FISH_RAW,
df.item_type.VERMIN,
df.item_type.PET,
df.item_type.EGG,
})
if organicTypes[itemType] then
--TODO: look up creature and caste
error 'Not yet supported.'
end
badTypes = badTypes or utils.invert({
df.item_type.CORPSE,
df.item_type.CORPSEPIECE,
df.item_type.FOOD,
})
if badTypes[itemType] then
error 'Not supported.'
end
if not args.material then
error 'Invalid material.'
end
args.material = dfhack.matinfo.find(args.material)
if not args.material then
error 'Invalid material.'
end
local item1 = dfhack.items.createItem(itemType, itemSubtype, args.material['type'], args.material.index, args.creator)
if args.matchingGloves or args.matchingShoes then
if args.matchingGloves then
item1 = df.item.find(item1)
item1:setGloveHandedness(1);
end
local item2 = dfhack.items.createItem(itemType, itemSubtype, args.material['type'], args.material.index, args.creator)
if args.matchingGloves then
item2 = df.item.find(item2)
item2:setGloveHandedness(2);
end
end
createItem(tonumber(args.creator), args.item, args.material, args.leftHand, args.rightHand, args.quality)

@ -0,0 +1,452 @@
-- 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
-- version 0.4
-- This is a beta version. Use at your own risk.
--[[
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)
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)
df.global.gametype = 4
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'D_LOOK_ARENA_CREATURE')
gui.simulateInput(dfhack.gui.getCurViewscreen(), 'SELECT')
df.global.gametype = 0
curViewscreen.child = nil
dwarfmodeScreen:delete()
df.global.ui.main.mode = oldMode
local id = df.global.unit_next_id-1
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)
local cr = df.creature_raw.find(race_id)
local caste_id, casteMax
casteMax = #cr.caste - 1
if casteMax > 0 then
return math.random(0, casteMax)
end
return 0
end
local function allocateNewChunk(hist_entity)
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)
end
local function allocateIds(nemesis_record,hist_entity)
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
end
function createFigure(trgunit,he,he_group)
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
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
-- ...
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
end
function createNemesis(trgunit,civ_id,group_id)
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)
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
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
if not entity_raw then
error('entity raw = nil: ', id, entityRawName, civ_id)
end
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',
'location'
})
if moduleMode then
return
end
local args = utils.processArgs({...}, validArgs)
if args.help then
print('help string TODO')
return
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
local civ_id
if args.civId == '\\LOCAL' then
civ_id = df.global.ui.civ_id
elseif args.civId and tonumber(args.civId) then
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
local unitId = createUnitInCiv(raceIndex, casteIndex, civ_id, group_id)
if args.domesticate then
domesticate(unitId, group_id)
end
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
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--]]

@ -0,0 +1,99 @@
-- modtools/equip-item.lua
-- equip an item on a unit with a particular body part
local utils = require 'utils'
function equipItem(unit, item, bodyPart, mode)
--it is assumed that the item is on the ground
item.flags.on_ground = false
item.flags.in_inventory = true
local block = dfhack.maps.getTileBlock(item.pos)
local occupancy = block.occupancy[item.pos.x%16][item.pos.y%16]
for k,v in ipairs(block.items) do
--local blockItem = df.item.find(v)
if v == item.id then
block.items:erase(k)
break
end
end
local foundItem = false
for k,v in ipairs(block.items) do
local blockItem = df.item.find(v)
if blockItem.pos.x == item.pos.x and blockItem.pos.y == item.pos.y then
foundItem = true
break
end
end
if not foundItem then
occupancy.item = false
end
local inventoryItem = df.unit_inventory_item:new()
inventoryItem.item = item
inventoryItem.mode = mode
inventoryItem.body_part_id = bodyPart
unit.inventory:insert(#unit.inventory,inventoryItem)
end
validArgs = --[[validArgs or--]] utils.invert({
'help',
'unit',
'item',
'bodyPart',
'mode'
})
if moduleMode then
return
end
local args = utils.processArgs({...}, validArgs)
if args.help then
print(
[[scripts/modtools/equip-item.lua
arguments:
-help
print this help message
]])
return
end
local unitId = tonumber(args.unit) or ((args.unit == '\\LAST') and (df.global.unit_next_id-1))
local unit = df.unit.find(unitId)
if not unit then
error('invalid unit!', args.unit)
end
local itemId = tonumber(args.item) or ((args.item == '\\LAST') and (df.global.item_next_id-1))
local item = df.item.find(itemId)
if not item then
error('invalid item!', args.item)
end
local bodyPartName = args.bodyPart
local creature_raw = df.global.world.raws.creatures.all[unit.race]
local caste_raw = creature_raw.caste[unit.caste]
local body_info = caste_raw.body_info
local partId
local part
for k,v in ipairs(body_info.body_parts) do
if v.token == bodyPartName then
partId = k
part = v
break
end
end
if not part then
error('invalid body part name: ', bodyPartName)
end
local mode = args.mode
mode = df.unit_inventory_item.T_mode[mode]
equipItem(unit, item, partId, mode)

@ -3,7 +3,7 @@
-- author Putnam
-- edited by expwnent
local function teleport(unit,pos)
function teleport(unit,pos)
local unitoccupancy = dfhack.maps.getTileBlock(unit.pos).occupancy[unit.pos.x%16][unit.pos.y%16]
local newoccupancy = dfhack.maps.getTileBlock(pos).occupancy[pos.x%16][pos.y%16]
if newoccupancy.unit then
@ -26,6 +26,10 @@ validArgs = validArgs or utils.invert({
'showpos'
})
if moduleMode then
return
end
local args = utils.processArgs({...}, validArgs)
if args.showunitid or args.showpos then