Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 156 157 [158] 159 160 ... 360

Author Topic: DFHack 0.43.03-r1  (Read 1124889 times)

Dirst

  • Bay Watcher
  • [EASILY_DISTRA
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2355 on: March 22, 2015, 10:49:12 pm »

I finally had some spare time, and here is my fix for the spawn-unit script so that it can process \\LOCATION properly.
I also had to coerce the caste ID into a number by adding 0 to it.  I'm sure there's a more graceful way to handle that, but I don't know it.

Code: (spawn-unit.lua) [Select]
--create unit at pointer or given location and with given civ (usefull to pass -1 for enemy). Usage e.g. "spawn-unit -race DWARF -caste 0 -name Dwarfy"
--[=[
    arguments
        -help
            print this help message
        -race <RACE_ID>
            The raw id of the creature's race, mandatory
        -caste <number>
            The caste's number, optional
        -name <doggy>
            The unit's name, optional
        -position [ x y z ]
            The unit's position, will try to use the cursor if ommited
        -civ_id
            The unit's civilisation or -1 for hostile, will be the player's if ommited

    Example : spawn-unit -race HUMAN -caste 0 -name Bob

    Made by warmist, but edited by Putnam for the dragon ball mod to be used in reactions
Hotfix by Dirst to repair location parameter

    TODO:
        throw a proper error if the user attempt to run it from the console, without good args
        orientation
        chosing a caste based on ratios
        birth time
        death time
        real body size
        blood max
        check if soulless and skip make soul
        set weapon body part
        nemesis/histfig : add an 'arrived on site' event
        generate name
--]=]
local utils=require 'utils'

-- Picking a caste or gender at random
local 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 getCaste(race_id,caste_id)
    local cr=df.creature_raw.find(race_id)

    return cr.caste[caste_id+0]
end

local function genBodyModifier(body_app_mod)
    local a=math.random(0,#body_app_mod.ranges-2)
    return math.random(body_app_mod.ranges[a],body_app_mod.ranges[a+1])
end

local function getBodySize(caste,time)
    --TODO: real body size...
    return caste.body_size_1[#caste.body_size_1-1] --returns last body size
end

local function genAttribute(array)
    local a=math.random(0,#array-2)
    return math.random(array[a],array[a+1])
end

local function norm()
    return math.sqrt((-2)*math.log(math.random()))*math.cos(2*math.pi*math.random())
end

local function normalDistributed(mean,sigma)
    return mean+sigma*norm()
end

local function clampedNormal(min,median,max)
    local val=normalDistributed(median,math.sqrt(max-min))
    if val<min then return min end
    if val>max then return max end
    return val
end

local function makeSoul(unit,caste)
    local tmp_soul=df.unit_soul:new()
    tmp_soul.unit_id=unit.id
    tmp_soul.name:assign(unit.name)
    tmp_soul.race=unit.race
    tmp_soul.sex=unit.sex
    tmp_soul.caste=unit.caste
    --todo: preferences,traits.
    local attrs=caste.attributes
    for k,v in pairs(attrs.ment_att_range) do
       local max_percent=attrs.ment_att_cap_perc[k]/100
       local cvalue=genAttribute(v)
       tmp_soul.mental_attrs[k]={value=cvalue,max_value=cvalue*max_percent}
    end
    for k,v in pairs(tmp_soul.personality.traits) do
        local min,mean,max
        min=caste.personality.a[k]
        mean=caste.personality.b[k]
        max=caste.personality.c[k]
        tmp_soul.personality.traits[k]=clampedNormal(min,mean,max)
    end
    --[[natural skill fix]]
    for k, skill in ipairs(caste.natural_skill_id) do
        local rating = caste.natural_skill_lvl[k]
        utils.insert_or_update(tmp_soul.skills,
            {new=true,id=skill,experience=caste.natural_skill_exp[k],rating=rating}, 'id')
    end
   
    unit.status.souls:insert("#",tmp_soul)
    unit.status.current_soul=tmp_soul
end

local function CreateUnit(race_id,caste_id)
    local race=df.creature_raw.find(race_id)
    if race==nil then error("Invalid race_id") end
    local caste
    local unit=df.unit:new()

    -- Pick a random caste is none are set
    if nil == caste_id then
        caste_id = getRandomCasteId(race_id)
    end

    caste = getCaste(race_id,caste_id)

    unit:assign{
        race=race_id,
        caste=caste_id,
        sex=caste.gender,
    }

    unit.relations.birth_year=df.global.cur_year-15 --AGE is set here
    if caste.misc.maxage_max==-1 then
        unit.relations.old_year=-1
    else
        unit.relations.old_year=df.global.cur_year+math.random(caste.misc.maxage_min,caste.misc.maxage_max)
    end
   
    --unit.relations.birth_time=??
    --unit.relations.old_time=?? --TODO add normal age
    --[[ interataction stuff, probably timers ]]--
    local num_inter=#caste.body_info.interactions  -- new for interactions
    unit.curse.own_interaction:resize(num_inter) -- new for interactions
    unit.curse.own_interaction_delay:resize(num_inter) -- new for interactions
    --[[ body stuff ]]
   
    local body=unit.body
    body.body_plan=caste.body_info
    local body_part_count=#body.body_plan.body_parts
    local layer_count=#body.body_plan.layer_part
    --[[ body components ]]
    local cp=body.components
    cp.body_part_status:resize(body_part_count)
    cp.numbered_masks:resize(#body.body_plan.numbered_masks)
    for num,v in ipairs(body.body_plan.numbered_masks) do
        cp.numbered_masks[num]=v
    end
    cp.layer_status:resize(layer_count)
    cp.layer_wound_area:resize(layer_count)
    cp.layer_cut_fraction:resize(layer_count)
    cp.layer_dent_fraction:resize(layer_count)
    cp.layer_effect_fraction:resize(layer_count)
   
    local attrs=caste.attributes
    for k,v in pairs(attrs.phys_att_range) do
        local max_percent=attrs.phys_att_cap_perc[k]/100
        local cvalue=genAttribute(v)
        unit.body.physical_attrs[k]={value=cvalue,max_value=cvalue*max_percent}
    end
 
   
    body.blood_max=getBodySize(caste,0) --TODO normal values
    body.blood_count=body.blood_max
    body.infection_level=0
    unit.status2.body_part_temperature:resize(body_part_count)
    for k,v in pairs(unit.status2.body_part_temperature) do
        unit.status2.body_part_temperature[k]={new=true,whole=10067,fraction=0}
       
    end
    --[[ largely unknown stuff ]]
    local stuff=unit.enemy
    stuff.body_part_878:resize(body_part_count) -- all = 3
    stuff.body_part_888:resize(body_part_count) -- all = 3
    stuff.body_part_relsize:resize(body_part_count) -- all =0
   
    stuff.were_race=race_id
    stuff.were_caste=caste_id
    stuff.normal_race=race_id
    stuff.normal_caste=caste_id
    stuff.body_part_8a8:resize(body_part_count) -- all = 1
    stuff.body_part_base_ins:resize(body_part_count)
    stuff.body_part_clothing_ins:resize(body_part_count)
    stuff.body_part_8d8:resize(body_part_count)
   
    --TODO add correct sizes. (calculate from age)
    local size=caste.body_size_2[#caste.body_size_2-1]
    body.size_info.size_cur=size
    body.size_info.size_base=size
    body.size_info.area_cur=math.pow(size,0.666)
    body.size_info.area_base=math.pow(size,0.666)
    body.size_info.area_cur=math.pow(size*10000,0.333)
    body.size_info.area_base=math.pow(size*10000,0.333)
   
    unit.recuperation.healing_rate:resize(layer_count)
   
    --appearance
    local app=unit.appearance
    app.body_modifiers:resize(#caste.body_appearance_modifiers) --3
    for k,v in pairs(app.body_modifiers) do
        app.body_modifiers[k]=genBodyModifier(caste.body_appearance_modifiers[k])
    end
    app.bp_modifiers:resize(#caste.bp_appearance.modifier_idx) --0
    for k,v in pairs(app.bp_modifiers) do
        app.bp_modifiers[k]=genBodyModifier(caste.bp_appearance.modifiers[caste.bp_appearance.modifier_idx[k]])
    end
    --app.unk_4c8:resize(33)--33
    app.tissue_style:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_civ_id:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_id:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_type:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_length:resize(#caste.bp_appearance.style_part_idx)
    app.genes.appearance:resize(#caste.body_appearance_modifiers+#caste.bp_appearance.modifiers) --3
    app.genes.colors:resize(#caste.color_modifiers*2) --???
    app.colors:resize(#caste.color_modifiers)--3
   
    makeSoul(unit,caste)
   
    --finally set the id
    unit.id=df.global.unit_next_id
    df.global.unit_next_id=df.global.unit_next_id+1
    df.global.world.units.all:insert("#",unit)
    df.global.world.units.active:insert("#",unit)
   
    return unit
end

local function findRace(name)
    for k,v in pairs(df.global.world.raws.creatures.all) do
        if v.creature_id==name then
            return k
        end
    end
    qerror("Race:"..name.." not found!")
end
 
local 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

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
 
local 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~=-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

-- Do the placement, returns the freshly spawned unit
function place(args)
    if not args.race then
        qerror("Please provide a race")
    end

local pos = {}
if args.position then
    pos.x=args.position[1]
pos.y=args.position[2]
pos.z=args.position[3]
else
    pos = copyall(df.global.cursor)
end

    if pos.x == -30000 then
        qerror("Point your pointy thing somewhere")
    end

    local i
    local race_id = findRace(args.race)
    local u = CreateUnit(race_id,args.caste)

    u.pos:assign(pos)
       
    if args.name then
        u.name.first_name = args.name
        u.name.has_name = true
    end

    local group_id
    if df.global.gamemode == df.game_mode.ADVENTURE then
        u.civ_id = args.civ_id or df.global.world.units.active[0].civ_id
        group_id = -1
    else   
        u.civ_id = args.civ_id or df.global.ui.civ_id
    end

    if args.civ_id == -1 then
        group_id = group_id or -1
    else
        group_id = group_id or df.global.ui.group_id
    end

    local desig,ocupan = dfhack.maps.getTileFlags(pos)
    if ocupan.unit then
        ocupan.unit_grounded = true
        u.flags1.on_ground = true
    else
        ocupan.unit = true
    end

    if df.historical_entity.find(u.civ_id) ~= nil  then
        createNemesis(u, u.civ_id,group_id)
    end

    return u
end

validArgs = validArgs or utils.invert({
    'help',
    'race',
    'caste',
    'name',
    'position',
    'civ_id',
})

local args = utils.processArgs({...}, validArgs)

if args.help then
 print([[scripts/spawn-unit.lua
arguments
    -help
        print this help message
    -race <RACE_ID>
        The raw id of the creature's race, mandatory
    -caste <number>
        The caste's number, optional
    -name <doggy>
        The unit's name, optional
    -position [ x y z ]
        The unit's position, will try to use the cursor if ommited
    -civ_id
        The unit's civilisation or -1 for hostile, will be the player's if ommited
]])
 return
end

if args.race then
    place(args) --Creature (ID), caste (number), name, x,y,z , civ_id(-1 for enemy, optional) for spawn.
end


I would like to start using the "standard" script for my mod (to take advantage of ongoing development), but to do that I'd need to request an -age parameter.  An alternative would be -newborn (age zero), -baby, -child and -adult flags.

Edit: It doesn't seem to like passing -civ_id -1, because the parser seems to think that -1 is a flag rather than a value.
« Last Edit: March 23, 2015, 12:22:51 am by Dirst »
Logged
Just got back, updating:
(0.42 & 0.43) The Earth Strikes Back! v2.15 - Pay attention...  It's a mine!  It's-a not yours!
(0.42 & 0.43) Appearance Tweaks v1.03 - Tease those hippies about their pointy ears.
(0.42 & 0.43) Accessibility Utility v1.04 - Console tools to navigate the map

Roses

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2356 on: March 23, 2015, 12:26:44 am »

Use \-1

Question about syndromes. This is kind of complicated to I'll just skip right to an example;

If I use add-syndrome to add a syndrome with an END I am guessing it will behave just as normal and finish at the appropriate time. But what if, instead, I used add-syndrome to add a syndrome with no END and instead removed said syndrome at a later time? Would that function the same way? Or is there something special that the game does when it ends a syndrome naturally, versus getting removed with a script?
Logged

Dirst

  • Bay Watcher
  • [EASILY_DISTRA
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2357 on: March 23, 2015, 12:53:25 am »

It didn't like -civ_id \-1 either ("inavlid escape sequence").  For now I'll add a -hostile flag to override the civ to -1 if it's present, but if there is a general solution I'd rather go with what's going to be in the spawn-unit.lua that everyone else is using.

Code: (tesb-spawn-unit.lua) [Select]
--create unit at pointer or given location and with given civ (usefull to pass -1 for enemy). Usage e.g. "spawn-unit -race DWARF -caste 0 -name Dwarfy"
--[=[
    arguments
        -help
            print this help message
        -race <RACE_ID>
            The raw id of the creature's race, mandatory
        -caste <number>
            The caste's number, optional
        -age <number>
            The unit's age in years, defaults to 15 if omitted
        -name <doggy>
            The unit's name, optional
        -position [ x y z ]
            The unit's position, will try to use the cursor if omitted
        -civ_id
            The unit's civilisation, will be the player's if omitted
        -hostile
            Overrides the civ_id to -1

    Example : spawn-unit -race HUMAN -caste 0 -name Bob

    Made by warmist, but edited by Putnam for the dragon ball mod to be used in reactions
Modified by Dirst for use in The Earth Strikes Back mod

    TODO:
        throw a proper error if the user attempt to run it from the console, without good args
        orientation
        chosing a caste based on ratios
        birth time
        death time
        real body size
        blood max
        check if soulless and skip make soul
        set weapon body part
        nemesis/histfig : add an 'arrived on site' event
        generate name
--]=]
local utils=require 'utils'

-- Picking a caste or gender at random
local 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 getCaste(race_id,caste_id)
    local cr=df.creature_raw.find(race_id)

    return cr.caste[tonumber(caste_id)]
end

local function genBodyModifier(body_app_mod)
    local a=math.random(0,#body_app_mod.ranges-2)
    return math.random(body_app_mod.ranges[a],body_app_mod.ranges[a+1])
end

local function getBodySize(caste,time)
    --TODO: real body size...
    return caste.body_size_1[#caste.body_size_1-1] --returns last body size
end

local function genAttribute(array)
    local a=math.random(0,#array-2)
    return math.random(array[a],array[a+1])
end

local function norm()
    return math.sqrt((-2)*math.log(math.random()))*math.cos(2*math.pi*math.random())
end

local function normalDistributed(mean,sigma)
    return mean+sigma*norm()
end

local function clampedNormal(min,median,max)
    local val=normalDistributed(median,math.sqrt(max-min))
    if val<min then return min end
    if val>max then return max end
    return val
end

local function makeSoul(unit,caste)
    local tmp_soul=df.unit_soul:new()
    tmp_soul.unit_id=unit.id
    tmp_soul.name:assign(unit.name)
    tmp_soul.race=unit.race
    tmp_soul.sex=unit.sex
    tmp_soul.caste=unit.caste
    --todo: preferences,traits.
    local attrs=caste.attributes
    for k,v in pairs(attrs.ment_att_range) do
       local max_percent=attrs.ment_att_cap_perc[k]/100
       local cvalue=genAttribute(v)
       tmp_soul.mental_attrs[k]={value=cvalue,max_value=cvalue*max_percent}
    end
    for k,v in pairs(tmp_soul.personality.traits) do
        local min,mean,max
        min=caste.personality.a[k]
        mean=caste.personality.b[k]
        max=caste.personality.c[k]
        tmp_soul.personality.traits[k]=clampedNormal(min,mean,max)
    end
    --[[natural skill fix]]
    for k, skill in ipairs(caste.natural_skill_id) do
        local rating = caste.natural_skill_lvl[k]
        utils.insert_or_update(tmp_soul.skills,
            {new=true,id=skill,experience=caste.natural_skill_exp[k],rating=rating}, 'id')
    end
   
    unit.status.souls:insert("#",tmp_soul)
    unit.status.current_soul=tmp_soul
end

local function CreateUnit(race_id,caste_id,unit_age)
    local race=df.creature_raw.find(race_id)
    if race==nil then error("Invalid race_id") end

unit_age = unit_age or 15
   
local caste
    local unit=df.unit:new()

    -- Pick a random caste is none are set
    if nil == caste_id then
        caste_id = getRandomCasteId(race_id)
    end

    caste = getCaste(race_id,caste_id)

    unit:assign{
        race=race_id,
        caste=caste_id,
        sex=caste.gender,
    }

    unit.relations.birth_year=df.global.cur_year-unit_age --AGE is set here
    if caste.misc.maxage_max==-1 then
        unit.relations.old_year=-1
    else
        unit.relations.old_year=df.global.cur_year+math.random(caste.misc.maxage_min,caste.misc.maxage_max)
    end
   
    unit.relations.birth_time=df.global.cur_year_tick
    --unit.relations.old_time=?? --TODO add normal age
    --[[ interataction stuff, probably timers ]]--
    local num_inter=#caste.body_info.interactions  -- new for interactions
    unit.curse.own_interaction:resize(num_inter) -- new for interactions
    unit.curse.own_interaction_delay:resize(num_inter) -- new for interactions
    --[[ body stuff ]]
   
    local body=unit.body
    body.body_plan=caste.body_info
    local body_part_count=#body.body_plan.body_parts
    local layer_count=#body.body_plan.layer_part
    --[[ body components ]]
    local cp=body.components
    cp.body_part_status:resize(body_part_count)
    cp.numbered_masks:resize(#body.body_plan.numbered_masks)
    for num,v in ipairs(body.body_plan.numbered_masks) do
        cp.numbered_masks[num]=v
    end
    cp.layer_status:resize(layer_count)
    cp.layer_wound_area:resize(layer_count)
    cp.layer_cut_fraction:resize(layer_count)
    cp.layer_dent_fraction:resize(layer_count)
    cp.layer_effect_fraction:resize(layer_count)
   
    local attrs=caste.attributes
    for k,v in pairs(attrs.phys_att_range) do
        local max_percent=attrs.phys_att_cap_perc[k]/100
        local cvalue=genAttribute(v)
        unit.body.physical_attrs[k]={value=cvalue,max_value=cvalue*max_percent}
    end
 
   
    body.blood_max=getBodySize(caste,0) --TODO normal values
    body.blood_count=body.blood_max
    body.infection_level=0
    unit.status2.body_part_temperature:resize(body_part_count)
    for k,v in pairs(unit.status2.body_part_temperature) do
        unit.status2.body_part_temperature[k]={new=true,whole=10067,fraction=0}
       
    end
    --[[ largely unknown stuff ]]
    local stuff=unit.enemy
    stuff.body_part_878:resize(body_part_count) -- all = 3
    stuff.body_part_888:resize(body_part_count) -- all = 3
    stuff.body_part_relsize:resize(body_part_count) -- all =0
   
    stuff.were_race=race_id
    stuff.were_caste=caste_id
    stuff.normal_race=race_id
    stuff.normal_caste=caste_id
    stuff.body_part_8a8:resize(body_part_count) -- all = 1
    stuff.body_part_base_ins:resize(body_part_count)
    stuff.body_part_clothing_ins:resize(body_part_count)
    stuff.body_part_8d8:resize(body_part_count)
   
    --TODO add correct sizes. (calculate from age)
    local size=caste.body_size_2[#caste.body_size_2-1]
    body.size_info.size_cur=size
    body.size_info.size_base=size
    body.size_info.area_cur=math.pow(size,0.666)
    body.size_info.area_base=math.pow(size,0.666)
    body.size_info.area_cur=math.pow(size*10000,0.333)
    body.size_info.area_base=math.pow(size*10000,0.333)
   
    unit.recuperation.healing_rate:resize(layer_count)
   
    --appearance
    local app=unit.appearance
    app.body_modifiers:resize(#caste.body_appearance_modifiers) --3
    for k,v in pairs(app.body_modifiers) do
        app.body_modifiers[k]=genBodyModifier(caste.body_appearance_modifiers[k])
    end
    app.bp_modifiers:resize(#caste.bp_appearance.modifier_idx) --0
    for k,v in pairs(app.bp_modifiers) do
        app.bp_modifiers[k]=genBodyModifier(caste.bp_appearance.modifiers[caste.bp_appearance.modifier_idx[k]])
    end
    --app.unk_4c8:resize(33)--33
    app.tissue_style:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_civ_id:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_id:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_type:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_length:resize(#caste.bp_appearance.style_part_idx)
    app.genes.appearance:resize(#caste.body_appearance_modifiers+#caste.bp_appearance.modifiers) --3
    app.genes.colors:resize(#caste.color_modifiers*2) --???
    app.colors:resize(#caste.color_modifiers)--3
   
    makeSoul(unit,caste)
   
    --finally set the id
    unit.id=df.global.unit_next_id
    df.global.unit_next_id=df.global.unit_next_id+1
    df.global.world.units.all:insert("#",unit)
    df.global.world.units.active:insert("#",unit)
   
    return unit
end

local function findRace(name)
    for k,v in pairs(df.global.world.raws.creatures.all) do
        if v.creature_id==name then
            return k
        end
    end
    qerror("Race:"..name.." not found!")
end
 
local 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

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
 
local 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~=-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

-- Do the placement, returns the freshly spawned unit
function place(args)
    if not args.race then
        qerror("Please provide a race")
    end

local pos = {}
if args.position then
    pos.x=args.position[1]
pos.y=args.position[2]
pos.z=args.position[3]
else
    pos = copyall(df.global.cursor)
end

    if pos.x == -30000 then
        qerror("Point your pointy thing somewhere")
    end

    local i
    local race_id = findRace(args.race)
    local u = CreateUnit(race_id,args.caste,args.age)

    u.pos:assign(pos)
       
    if args.name then
        u.name.first_name = args.name
        u.name.has_name = true
    end

if args.hostile then
    args.civ_id = -1
end

    local group_id
    if df.global.gamemode == df.game_mode.ADVENTURE then
        u.civ_id = args.civ_id or df.global.world.units.active[0].civ_id
        group_id = -1
    else   
        u.civ_id = args.civ_id or df.global.ui.civ_id
    end

    if args.civ_id == -1 then
        group_id = group_id or -1
    else
        group_id = group_id or df.global.ui.group_id
    end

    local desig,ocupan = dfhack.maps.getTileFlags(pos)
    if ocupan.unit then
        ocupan.unit_grounded = true
        u.flags1.on_ground = true
    else
        ocupan.unit = true
    end

    if df.historical_entity.find(u.civ_id) ~= nil  then
        createNemesis(u, u.civ_id,group_id)
    end

    return u
end

validArgs = validArgs or utils.invert({
    'help',
    'race',
    'caste',
    'age',
    'name',
    'position',
    'civ_id',
    'hostile',
})

local args = utils.processArgs({...}, validArgs)

if args.help then
 print([[scripts/spawn-unit.lua
arguments
    -help
        print this help message
    -race <RACE_ID>
        The raw id of the creature's race, mandatory
    -caste <number>
        The caste's number, optional
-age <number>
    The unit's age in years, defaults to 15 if omitted
-name <doggy>
        The unit's name, optional
    -position [ x y z ]
        The unit's position, will try to use the cursor if ommited
    -civ_id
        The unit's civilisation, will be the player's if ommited
    -hostile
        Overrides the civ_id to -1
]])
 return
end

if args.race then
    place(args) --Creature (ID), caste (number), age, name, x,y,z , civ_id(-1 for enemy, optional) for spawn.
end
« Last Edit: March 23, 2015, 12:58:24 am by Dirst »
Logged
Just got back, updating:
(0.42 & 0.43) The Earth Strikes Back! v2.15 - Pay attention...  It's a mine!  It's-a not yours!
(0.42 & 0.43) Appearance Tweaks v1.03 - Tease those hippies about their pointy ears.
(0.42 & 0.43) Accessibility Utility v1.04 - Console tools to navigate the map

Boltgun

  • Bay Watcher
  • [UTTERANCES]
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2358 on: March 23, 2015, 03:48:15 am »

A specific flag will be more explicit instead of -1 anyway.

There is the xyz2pos(x,y,z) and pos2xyz(pos). Handling position with those format still leads me to a lot of error somehow.
« Last Edit: March 23, 2015, 03:51:37 am by Boltgun »
Logged

expwnent

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2359 on: March 23, 2015, 11:36:02 am »

Use \-1

Question about syndromes. This is kind of complicated to I'll just skip right to an example;

If I use add-syndrome to add a syndrome with an END I am guessing it will behave just as normal and finish at the appropriate time. But what if, instead, I used add-syndrome to add a syndrome with no END and instead removed said syndrome at a later time? Would that function the same way? Or is there something special that the game does when it ends a syndrome naturally, versus getting removed with a script?

Not completely sure but I think it's fine except for transformations. It might even be fine for transformations. I haven't tested it thoroughly. Let me know how it goes. That ought to be documented.

It didn't like -civ_id \-1 either ("inavlid escape sequence").  For now I'll add a -hostile flag to override the civ to -1 if it's present, but if there is a general solution I'd rather go with what's going to be in the spawn-unit.lua that everyone else is using.

Code: (tesb-spawn-unit.lua) [Select]
--create unit at pointer or given location and with given civ (usefull to pass -1 for enemy). Usage e.g. "spawn-unit -race DWARF -caste 0 -name Dwarfy"
--[=[
    arguments
        -help
            print this help message
        -race <RACE_ID>
            The raw id of the creature's race, mandatory
        -caste <number>
            The caste's number, optional
        -age <number>
            The unit's age in years, defaults to 15 if omitted
        -name <doggy>
            The unit's name, optional
        -position [ x y z ]
            The unit's position, will try to use the cursor if omitted
        -civ_id
            The unit's civilisation, will be the player's if omitted
        -hostile
            Overrides the civ_id to -1

    Example : spawn-unit -race HUMAN -caste 0 -name Bob

    Made by warmist, but edited by Putnam for the dragon ball mod to be used in reactions
Modified by Dirst for use in The Earth Strikes Back mod

    TODO:
        throw a proper error if the user attempt to run it from the console, without good args
        orientation
        chosing a caste based on ratios
        birth time
        death time
        real body size
        blood max
        check if soulless and skip make soul
        set weapon body part
        nemesis/histfig : add an 'arrived on site' event
        generate name
--]=]
local utils=require 'utils'

-- Picking a caste or gender at random
local 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 getCaste(race_id,caste_id)
    local cr=df.creature_raw.find(race_id)

    return cr.caste[tonumber(caste_id)]
end

local function genBodyModifier(body_app_mod)
    local a=math.random(0,#body_app_mod.ranges-2)
    return math.random(body_app_mod.ranges[a],body_app_mod.ranges[a+1])
end

local function getBodySize(caste,time)
    --TODO: real body size...
    return caste.body_size_1[#caste.body_size_1-1] --returns last body size
end

local function genAttribute(array)
    local a=math.random(0,#array-2)
    return math.random(array[a],array[a+1])
end

local function norm()
    return math.sqrt((-2)*math.log(math.random()))*math.cos(2*math.pi*math.random())
end

local function normalDistributed(mean,sigma)
    return mean+sigma*norm()
end

local function clampedNormal(min,median,max)
    local val=normalDistributed(median,math.sqrt(max-min))
    if val<min then return min end
    if val>max then return max end
    return val
end

local function makeSoul(unit,caste)
    local tmp_soul=df.unit_soul:new()
    tmp_soul.unit_id=unit.id
    tmp_soul.name:assign(unit.name)
    tmp_soul.race=unit.race
    tmp_soul.sex=unit.sex
    tmp_soul.caste=unit.caste
    --todo: preferences,traits.
    local attrs=caste.attributes
    for k,v in pairs(attrs.ment_att_range) do
       local max_percent=attrs.ment_att_cap_perc[k]/100
       local cvalue=genAttribute(v)
       tmp_soul.mental_attrs[k]={value=cvalue,max_value=cvalue*max_percent}
    end
    for k,v in pairs(tmp_soul.personality.traits) do
        local min,mean,max
        min=caste.personality.a[k]
        mean=caste.personality.b[k]
        max=caste.personality.c[k]
        tmp_soul.personality.traits[k]=clampedNormal(min,mean,max)
    end
    --[[natural skill fix]]
    for k, skill in ipairs(caste.natural_skill_id) do
        local rating = caste.natural_skill_lvl[k]
        utils.insert_or_update(tmp_soul.skills,
            {new=true,id=skill,experience=caste.natural_skill_exp[k],rating=rating}, 'id')
    end
   
    unit.status.souls:insert("#",tmp_soul)
    unit.status.current_soul=tmp_soul
end

local function CreateUnit(race_id,caste_id,unit_age)
    local race=df.creature_raw.find(race_id)
    if race==nil then error("Invalid race_id") end

unit_age = unit_age or 15
   
local caste
    local unit=df.unit:new()

    -- Pick a random caste is none are set
    if nil == caste_id then
        caste_id = getRandomCasteId(race_id)
    end

    caste = getCaste(race_id,caste_id)

    unit:assign{
        race=race_id,
        caste=caste_id,
        sex=caste.gender,
    }

    unit.relations.birth_year=df.global.cur_year-unit_age --AGE is set here
    if caste.misc.maxage_max==-1 then
        unit.relations.old_year=-1
    else
        unit.relations.old_year=df.global.cur_year+math.random(caste.misc.maxage_min,caste.misc.maxage_max)
    end
   
    unit.relations.birth_time=df.global.cur_year_tick
    --unit.relations.old_time=?? --TODO add normal age
    --[[ interataction stuff, probably timers ]]--
    local num_inter=#caste.body_info.interactions  -- new for interactions
    unit.curse.own_interaction:resize(num_inter) -- new for interactions
    unit.curse.own_interaction_delay:resize(num_inter) -- new for interactions
    --[[ body stuff ]]
   
    local body=unit.body
    body.body_plan=caste.body_info
    local body_part_count=#body.body_plan.body_parts
    local layer_count=#body.body_plan.layer_part
    --[[ body components ]]
    local cp=body.components
    cp.body_part_status:resize(body_part_count)
    cp.numbered_masks:resize(#body.body_plan.numbered_masks)
    for num,v in ipairs(body.body_plan.numbered_masks) do
        cp.numbered_masks[num]=v
    end
    cp.layer_status:resize(layer_count)
    cp.layer_wound_area:resize(layer_count)
    cp.layer_cut_fraction:resize(layer_count)
    cp.layer_dent_fraction:resize(layer_count)
    cp.layer_effect_fraction:resize(layer_count)
   
    local attrs=caste.attributes
    for k,v in pairs(attrs.phys_att_range) do
        local max_percent=attrs.phys_att_cap_perc[k]/100
        local cvalue=genAttribute(v)
        unit.body.physical_attrs[k]={value=cvalue,max_value=cvalue*max_percent}
    end
 
   
    body.blood_max=getBodySize(caste,0) --TODO normal values
    body.blood_count=body.blood_max
    body.infection_level=0
    unit.status2.body_part_temperature:resize(body_part_count)
    for k,v in pairs(unit.status2.body_part_temperature) do
        unit.status2.body_part_temperature[k]={new=true,whole=10067,fraction=0}
       
    end
    --[[ largely unknown stuff ]]
    local stuff=unit.enemy
    stuff.body_part_878:resize(body_part_count) -- all = 3
    stuff.body_part_888:resize(body_part_count) -- all = 3
    stuff.body_part_relsize:resize(body_part_count) -- all =0
   
    stuff.were_race=race_id
    stuff.were_caste=caste_id
    stuff.normal_race=race_id
    stuff.normal_caste=caste_id
    stuff.body_part_8a8:resize(body_part_count) -- all = 1
    stuff.body_part_base_ins:resize(body_part_count)
    stuff.body_part_clothing_ins:resize(body_part_count)
    stuff.body_part_8d8:resize(body_part_count)
   
    --TODO add correct sizes. (calculate from age)
    local size=caste.body_size_2[#caste.body_size_2-1]
    body.size_info.size_cur=size
    body.size_info.size_base=size
    body.size_info.area_cur=math.pow(size,0.666)
    body.size_info.area_base=math.pow(size,0.666)
    body.size_info.area_cur=math.pow(size*10000,0.333)
    body.size_info.area_base=math.pow(size*10000,0.333)
   
    unit.recuperation.healing_rate:resize(layer_count)
   
    --appearance
    local app=unit.appearance
    app.body_modifiers:resize(#caste.body_appearance_modifiers) --3
    for k,v in pairs(app.body_modifiers) do
        app.body_modifiers[k]=genBodyModifier(caste.body_appearance_modifiers[k])
    end
    app.bp_modifiers:resize(#caste.bp_appearance.modifier_idx) --0
    for k,v in pairs(app.bp_modifiers) do
        app.bp_modifiers[k]=genBodyModifier(caste.bp_appearance.modifiers[caste.bp_appearance.modifier_idx[k]])
    end
    --app.unk_4c8:resize(33)--33
    app.tissue_style:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_civ_id:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_id:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_style_type:resize(#caste.bp_appearance.style_part_idx)
    app.tissue_length:resize(#caste.bp_appearance.style_part_idx)
    app.genes.appearance:resize(#caste.body_appearance_modifiers+#caste.bp_appearance.modifiers) --3
    app.genes.colors:resize(#caste.color_modifiers*2) --???
    app.colors:resize(#caste.color_modifiers)--3
   
    makeSoul(unit,caste)
   
    --finally set the id
    unit.id=df.global.unit_next_id
    df.global.unit_next_id=df.global.unit_next_id+1
    df.global.world.units.all:insert("#",unit)
    df.global.world.units.active:insert("#",unit)
   
    return unit
end

local function findRace(name)
    for k,v in pairs(df.global.world.raws.creatures.all) do
        if v.creature_id==name then
            return k
        end
    end
    qerror("Race:"..name.." not found!")
end
 
local 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

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
 
local 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~=-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

-- Do the placement, returns the freshly spawned unit
function place(args)
    if not args.race then
        qerror("Please provide a race")
    end

local pos = {}
if args.position then
    pos.x=args.position[1]
pos.y=args.position[2]
pos.z=args.position[3]
else
    pos = copyall(df.global.cursor)
end

    if pos.x == -30000 then
        qerror("Point your pointy thing somewhere")
    end

    local i
    local race_id = findRace(args.race)
    local u = CreateUnit(race_id,args.caste,args.age)

    u.pos:assign(pos)
       
    if args.name then
        u.name.first_name = args.name
        u.name.has_name = true
    end

if args.hostile then
    args.civ_id = -1
end

    local group_id
    if df.global.gamemode == df.game_mode.ADVENTURE then
        u.civ_id = args.civ_id or df.global.world.units.active[0].civ_id
        group_id = -1
    else   
        u.civ_id = args.civ_id or df.global.ui.civ_id
    end

    if args.civ_id == -1 then
        group_id = group_id or -1
    else
        group_id = group_id or df.global.ui.group_id
    end

    local desig,ocupan = dfhack.maps.getTileFlags(pos)
    if ocupan.unit then
        ocupan.unit_grounded = true
        u.flags1.on_ground = true
    else
        ocupan.unit = true
    end

    if df.historical_entity.find(u.civ_id) ~= nil  then
        createNemesis(u, u.civ_id,group_id)
    end

    return u
end

validArgs = validArgs or utils.invert({
    'help',
    'race',
    'caste',
    'age',
    'name',
    'position',
    'civ_id',
    'hostile',
})

local args = utils.processArgs({...}, validArgs)

if args.help then
 print([[scripts/spawn-unit.lua
arguments
    -help
        print this help message
    -race <RACE_ID>
        The raw id of the creature's race, mandatory
    -caste <number>
        The caste's number, optional
-age <number>
    The unit's age in years, defaults to 15 if omitted
-name <doggy>
        The unit's name, optional
    -position [ x y z ]
        The unit's position, will try to use the cursor if ommited
    -civ_id
        The unit's civilisation, will be the player's if ommited
    -hostile
        Overrides the civ_id to -1
]])
 return
end

if args.race then
    place(args) --Creature (ID), caste (number), age, name, x,y,z , civ_id(-1 for enemy, optional) for spawn.
end

Sorry if I missed it, but do you have an exact example of  \-1 failing? What does devel/print-args output? If it doesn't work then that's a bug in processArgs.
« Last Edit: March 23, 2015, 11:49:17 am by expwnent »
Logged

Roses

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2360 on: March 23, 2015, 12:06:54 pm »

Use \-1

Question about syndromes. This is kind of complicated to I'll just skip right to an example;

If I use add-syndrome to add a syndrome with an END I am guessing it will behave just as normal and finish at the appropriate time. But what if, instead, I used add-syndrome to add a syndrome with no END and instead removed said syndrome at a later time? Would that function the same way? Or is there something special that the game does when it ends a syndrome naturally, versus getting removed with a script?

Not completely sure but I think it's fine except for transformations. It might even be fine for transformations. I haven't tested it thoroughly. Let me know how it goes. That ought to be documented.

I suppose it can be tested pretty easily by just creating two syndromes that are the same with different names, expect one has an END and the other doesn't then terminating the one that doesn't with add-syndrome. I'll test how this functions for various types of syndromes.

The only problem I forsee in actual practice is how to make sure you get rid of the correct syndrome. For instance, if you have syndrome A on a unit and they get another syndrome A, how do you tell add-syndrome to remove the first syndrome A? Similarly, what if you add to the duration or reset it instead of making a new instance? Is there anyway to modify a dfhack.timeout call to add more time?

EDIT: So it has been a while since I have actually gone through DFHack and seeing what there is, I have noticed a couple things that I may have missed before, or may be new, and have a couple questions.

actions
1. Am I correct in assuming that these are the actions that the unit performed?
2. I notice things like parry, block, dodge, suckblood, etc... Is it possible to use these in item-trigger? For instance, instead of -onStrike can we create an -onParry?
3. If a unit performs an action I assume a timer gets set for that specific action. Would it be possible to make a "quick" like spell, where the timer is reset allowing the unit to attack, dodge, or whatever more often/quickly?

interactions
4. I see both interaction_delay and own_interaction_delay in the curse section. Are these referencing syndrome vs innate interactions?
5. Similarly to 3, if I set the delay to 0 will they be able to use the interaction again before they normally would be?

used items
6. Can we now artificially make a dwarf attached to an item? Like make a cursed item where when the dwarf picks it up they are super affectionate to it?
7. What game play effects does attachement have?

EDIT2: Another question. I know the text for a dwarf's thoughts and preferences are based on things that dfhack can manipulate, but is there a way to get that text to use in a different area? What I am hoping to do is restructure the way you view a unit by creating another gui, and was hoping I could separate out certain things.
« Last Edit: March 23, 2015, 12:51:27 pm by Roses »
Logged

Dirst

  • Bay Watcher
  • [EASILY_DISTRA
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2361 on: March 23, 2015, 03:17:36 pm »

Sorry if I missed it, but do you have an exact example of  \-1 failing? What does devel/print-args output? If it doesn't work then that's a bug in processArgs.
Other than my "invalid escape sequence" quote, you didn't miss anything.  It might be a bit before I have time to replicate under controlled conditions, but the first version of spawn-unit.lua I posted ought to exhibit the error.  If it makes a difference, -civ_id was the last argument on the command line.
Logged
Just got back, updating:
(0.42 & 0.43) The Earth Strikes Back! v2.15 - Pay attention...  It's a mine!  It's-a not yours!
(0.42 & 0.43) Appearance Tweaks v1.03 - Tease those hippies about their pointy ears.
(0.42 & 0.43) Accessibility Utility v1.04 - Console tools to navigate the map

expwnent

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2362 on: March 24, 2015, 05:40:51 am »

Sorry if I missed it, but do you have an exact example of  \-1 failing? What does devel/print-args output? If it doesn't work then that's a bug in processArgs.
Other than my "invalid escape sequence" quote, you didn't miss anything.  It might be a bit before I have time to replicate under controlled conditions, but the first version of spawn-unit.lua I posted ought to exhibit the error.  If it makes a difference, -civ_id was the last argument on the command line.

Code: [Select]
modtools/force -eventType \-1

#[...]modtools/force.lua:58: Invalid eventType: -1

This crashes (correctly) on line 58, after utils.processArgs.
Logged

thepaan

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2363 on: March 25, 2015, 08:51:07 pm »

I'm trying to find the biome for a specific embark tile like this.

I've messed around a little with
Code: [Select]
dfhack.maps.getRegionBiome()I can get the following, but don't know how to interpret the output to get the info as in the first image above.

Is there a reference document or something I can read that explains the output? Or, should I be approaching it differently?

Any assistance is greatly appreciated.
Logged

Max™

  • Bay Watcher
  • [CULL:SQUARE]
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2364 on: March 26, 2015, 03:54:46 pm »

Wouldn't that just be the elevation/rainfall stuff? It's very low, moist, would have vegetation if not for being underwater, it's very warm, not evil at all, decent drainage, below average volcanism, high savagery.
Logged

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2365 on: March 26, 2015, 03:59:19 pm »

A landmass_id of -1 could refer to an ocean as well.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

Eldin00

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2366 on: March 26, 2015, 04:53:31 pm »

Elevation, rainfall, drainage, and temperature are the main factors that go into determining biome. From the wiki entry for biome: Elevation <= 99 is ocean, elevation >= 300 is mountain. Low enough temperature creates glacier. Otherwise, drainage and rainfall create a base biome. If it's warm enough, (wiki suggests cutoff is near 65) it is the tropical variant. If it's cold enough, it becomes tundra or taiga (depending on what the base type was). If you have wetlands, look at the salinity to determine freshwater/saltwater. The only bit I'm not sure how to differentiate from just the info in that screenshot is broadleaf vs conifer forest.

The wiki has a table to determine the base biome type from drainage and rainfall, but the values in that table are taken from an older version and should probably be checked to make sure that they are still accurate.
« Last Edit: March 26, 2015, 05:01:13 pm by Eldin00 »
Logged

thepaan

  • Bay Watcher
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2367 on: March 26, 2015, 05:20:17 pm »

Elevation, rainfall, drainage, and temperature are the main factors that go into determining biome...

I think I can deal with that, but is there a function which provides that information for the local window? Right now I can only find info for the region, but I'd like it to go down to the local scale.
Logged

Dirst

  • Bay Watcher
  • [EASILY_DISTRA
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2368 on: March 26, 2015, 08:35:26 pm »

Elevation, rainfall, drainage, and temperature are the main factors that go into determining biome...

I think I can deal with that, but is there a function which provides that information for the local window? Right now I can only find info for the region, but I'd like it to go down to the local scale.
Also, try running your query somewhere with a lake and somewhere else with a river to see if the structure changes.  Don't want the tool to have unrealistic expectations of data stability.
Logged
Just got back, updating:
(0.42 & 0.43) The Earth Strikes Back! v2.15 - Pay attention...  It's a mine!  It's-a not yours!
(0.42 & 0.43) Appearance Tweaks v1.03 - Tease those hippies about their pointy ears.
(0.42 & 0.43) Accessibility Utility v1.04 - Console tools to navigate the map

Dirst

  • Bay Watcher
  • [EASILY_DISTRA
    • View Profile
Re: DFHack 0.40.24-r2
« Reply #2369 on: March 27, 2015, 11:07:18 pm »

Sorry if I missed it, but do you have an exact example of  \-1 failing? What does devel/print-args output? If it doesn't work then that's a bug in processArgs.

Thanks for the advice.  It turns out that the error was in the calling script and not the called one!  Apparently backslashes inside Lua strings need to be treated carefully.  When I built the string with \\-1, it got into the string as \-1, which then executed properly in a dfhack.run_command() call.  A single backslash led to an invalid escape sequence with the string.

Now I know... and knowing is half the battle.
Logged
Just got back, updating:
(0.42 & 0.43) The Earth Strikes Back! v2.15 - Pay attention...  It's a mine!  It's-a not yours!
(0.42 & 0.43) Appearance Tweaks v1.03 - Tease those hippies about their pointy ears.
(0.42 & 0.43) Accessibility Utility v1.04 - Console tools to navigate the map
Pages: 1 ... 156 157 [158] 159 160 ... 360