Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 20 21 [22] 23 24 ... 44

Author Topic: Putnam's DFHack scripts  (Read 119070 times)

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #315 on: August 27, 2013, 11:39:42 am »

The debug narrowed it down to the one function, so all I had to do was find where in the function it was going wrong.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #316 on: August 27, 2013, 10:37:20 pm »

Ok, it's sort of working now.  The syndrome gets applied, but doesn't get refreshed after its duration expires.  Might just be something weird with arena mode...

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #317 on: August 27, 2013, 10:46:48 pm »

That's exactly what it is. Itemsyndrome (or any other scripts) won't recognize that the world is loaded when arena mode is, so it doesn't activate.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #318 on: August 28, 2013, 10:18:15 am »

That's exactly what it is. Itemsyndrome (or any other scripts) won't recognize that the world is loaded when arena mode is, so it doesn't activate.

No worries, this will do for testing. :)

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #319 on: August 29, 2013, 07:15:02 pm »

Alright, another issue.  Itemsyndrome does nothing in fortress mode until "itemsyndrome force" is run at least once.

Before you ask, yes, it's enabled in the init.

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #320 on: August 29, 2013, 07:25:25 pm »

But force does nothing with the repeating thing...

Did you use "itemsyndrome enable"?

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #321 on: August 29, 2013, 07:28:54 pm »

But force does nothing with the repeating thing...

Did you use "itemsyndrome enable"?

Yes.  Here's my init.

Code: [Select]
##########LFR v0.20 init file##########

##binary patches to fix vanilla bugs##

binpatch apply deconstruct-heapfall #prevents buildings from killing or injuring dwarves when deconstructed#
binpatch apply deconstruct-teleport  #prevents items from teleporting around when a building is deconstructed#
binpatch apply hospital-overstocking #makes hospitals actually obey their stock limits#
binpatch apply custom-reagent-size #allows for partial use of reagents with dimensions in custom reactions - not used in LFR, but doesn't hurt#
binpatch apply training-ammo #allows marksdwarves to pick up and use training ammunition even if their quiver is full of combat ammo#
binpatch apply armorstand-capacity
#doubles the capacity of armorstands#
binpatch apply weaponrack-unassign #fixes weapon racks - works together with the "fix armory" plugin#

##tweaks##

tweak patrol-duty #dwarves will not get negative thoughts for training sessions#
tweak stable-cursor #cursor remembers its position between menus#
tweak fix-dimensions #something involved with the custom reagent size fix#
tweak military-stable-assign #military position assignment list will no longer jump back to the start every time a unit is assigned#
tweak military-color-assigned #units already in squads will appear as a different color in the military assignment list#

##plugins##

load autoSyndrome #required for ritual transformations and mechanical constructs#
load trueTransformation #required to make paragons work properly#


##scripts##

fix/growthbug enable #Fixes a bug with dwarves not growing to full adult size#
itemsyndrome enable #Required for magical weapons#
itemsyndrome 150 #Modification to itemsyndrome settings#

When I embark, I bring a few itemsyndrome weapons for testing, then assign them to dwarves to go beat the ever-living crap out of the local wildlife.  They refuse to use the interactions unless I run "itemsndrome force."  It doesn't seem to matter if I run this before or after they pick the weapons up, but it works fine after that, with the syndromes being re-applied and everything.
« Last Edit: August 29, 2013, 07:31:44 pm by narhiril »
Logged

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #322 on: August 29, 2013, 07:30:06 pm »

Ah. Try "itemsyndrome enable 150" instead of having it twice.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #323 on: August 29, 2013, 07:32:04 pm »

Ah. Try "itemsyndrome enable 150" instead of having it twice.

Ok, I'll get back to you with that.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #324 on: August 29, 2013, 07:38:41 pm »

No dice.  Itemsyndrome doesn't seem to recognize when a game is started or loaded and it's supposed to start working.

I don't know much about lua, but is it possible that it's checking for a loaded world on startup, not finding it (obviously), and then failing to perform later checks?

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #325 on: August 29, 2013, 07:47:08 pm »

Code: [Select]
-- Checks regularly if creature has an item equipped with a special syndrome and applies item's syndrome if it is. Use "disable" (minus quotes) to disable. You can also change the

local function getDelayTicks(args)
for k,v in ipairs(args) do
if tonumber(v) and tonumber(v) > 0 then
return tonumber(v)
end
end
return nil
end

local args = {...}

function processArgs(args)
if #args==0 then enable = true return end
for k,v in ipairs(args) do
if v == "enable" then enable = true end
if v == "disable" then disable = true end
if v == "force" then force = true end
if v == "plus" then delayTicks = delayTicks+1 end
if v == "minus" then delayTicks = delayTicks-1 end
if v == "debugon" then itemsyndromedebug = true end
if v == "debugoff" then itemsyndromedebug = false end
end
end

delayTicks = getDelayTicks(args) or delayTicks or 499

processArgs(args)

local function getMaterial(item)
    local material = dfhack.matinfo.decode(item)
    if material.mode ~= "inorganic"  then
return nil
else
return material.material --the "material" thing up there contains a bit more info which is all pretty important, like the creature that the material comes from
end
end

local function findItemSyndromeInorganic()
local allInorganics = {}
    for matID,material in ipairs(df.global.world.raws.inorganics) do
        if string.find(material.id,"DFHACK_ITEMSYNDROME_MATERIAL_") then table.insert(allInorganics,matID) end --the last underscore is needed to prevent duped raws; I want good modder courtesy if it kills me, dammit!
    end
if itemsyndromedebug then printall(allInorganics) end
    if #allInorganics>0 then return allInorganics else return nil end
end

local function getAllItemSyndromeMats(itemSyndromeMatIDs)
local allActualInorganics = {}
for _,itemSyndromeMatID in ipairs(itemSyndromeMatIDs) do
table.insert(allActualInorganics,df.global.world.raws.inorganics[itemSyndromeMatID].material)
end
if itemsyndromedebug then printall(allActualInorganics) end
return allActualInorganics
end

itemSyndromeMatIDs = findItemSyndromeInorganic()

if itemSyndromeMatIDs then itemSyndromeMats = getAllItemSyndromeMats(itemSyndromeMatIDs) end

local function getSyndrome(material)
    if material==nil then return nil end
    if #material.syndrome>0 then return material.syndrome[0]
    else return nil end
end

local function syndromeIsDfHackSyndrome(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_ITEM_SYNDROME" then return true end
    end
    return false
end

local function itemHasNoSubtype(item)
    local itemtype = tostring(item)
    local subtypedItemTypes =
    {
    "armor",
    "weapon",
    "helm",
    "shoes",
    "shield",
    "glove",
    "pants",
    "tool",
    "siegeammo",
    "ammo",
    "trapcomp",
    "instrument",
    "toy"}
    for _,v in ipairs(subtypedItemTypes) do
        if string.find(itemtype,v) then return false end
    end
    return true
end

local function itemHasSyndrome(item)
    if itemHasNoSubtype(item) or not itemSyndromeMats then return nil end
    for _,material in ipairs(itemSyndromeMats) do
for __,syndrome in ipairs(material.syndrome) do
if syndrome.syn_name == item.subtype.name then return syndrome end
end
end
    return nil
end

local function alreadyHasSyndrome(unit,syn_id)
    for _,syndrome in ipairs(unit.syndromes.active) do
        if syndrome.type == syn_id then return true end
    end
    return false
end

local function assignSyndrome(target,syn_id) --taken straight from here, but edited so I can understand it better: https://gist.github.com/warmist/4061959/. Also implemented expwnent's changes for compatibility with syndromeTrigger.
    if target==nil then
        return nil
    end
    if alreadyHasSyndrome(target,syn_id) then
        local syndrome
        for k,v in ipairs(target.syndromes.active) do
            if v.type == syn_id then syndrome = v end
        end
        if not syndrome then return nil end
        syndrome.ticks=1
        return true
    end
    local newSyndrome=df.unit_syndrome:new()
    local target_syndrome=df.syndrome.find(syn_id)
    newSyndrome.type=target_syndrome.id
    newSyndrome.year=df.global.cur_year
    newSyndrome.year_time=df.global.cur_year_tick
    newSyndrome.ticks=1
    newSyndrome.unk1=1
    for k,v in ipairs(target_syndrome.ce) do
        local sympt=df.unit_syndrome.T_symptoms:new()
        sympt.ticks=1
        sympt.flags=2
        newSyndrome.symptoms:insert("#",sympt)
    end
    target.syndromes.active:insert("#",newSyndrome)
if itemsyndromedebug then
print("Assigned syndrome #" ..syn_id.." to unit.")
end
    return true
end

local function syndromeIsIndiscriminate(syndrome)
    if #syndrome.syn_affected_class==0 and #syndrome.syn_affected_creature==0 and #syndrome.syn_affected_caste==0 and #syndrome.syn_immune_class==0 and #syndrome.syn_immune_creature==0 and #syndrome.syn_immune_caste==0 then return true end
    return false
end

local function creatureIsAffected(unit,syndrome)
    if syndromeIsIndiscriminate(syndrome) then return true end
    local affected = false
    local unitraws = df.creature_raw.find(unit.race)
    local casteraws = unitraws.caste[unit.caste]
    local unitracename = unitraws.creature_id
    local castename = casteraws.caste_id
    local unitclasses = casteraws.creature_class
    for _,unitclass in ipairs(unitclasses) do
        for _,syndromeclass in ipairs(syndrome.syn_affected_class) do
            if unitclass.value==syndromeclass.value then affected = true end
        end
    end
    for caste,creature in ipairs(syndrome.syn_affected_creature) do
        local affected_creature = creature.value
        local affected_caste = syndrome.syn_affected_caste[caste].value --slightly evil, but oh well, hehe.
        if affected_creature == unitracename and affected_caste == castename then affected = true end
    end
    for _,unitclass in ipairs(unitclasses) do
        for _,syndromeclass in ipairs(syndrome.syn_immune_class) do
            if unitclass.value==syndromeclass.value then affected = false end
        end
    end
    for caste,creature in ipairs(syndrome.syn_immune_creature) do
        local immune_creature = creature.value
        local immune_caste = syndrome.syn_immune_caste[caste].value
        if immune_creature == unitracename and immune_caste == castename then affected = false end
    end
if itemsyndromedebug then
if not affected then print ("Creature is not affected.") else print("Creature is affected") end
end
    return affected
end

local function itemAffectsHauler(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_AFFECTS_HAULER" then return true end
    end
    return false
end

local function itemAffectsStuckins(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_AFFECTS_STUCKIN" then return true end
    end
    return false
end

local function itemIsArmorOnly(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_ARMOR_ONLY" then return true end
    end
    return false
end
   
local function itemIsWieldedOnly(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_WIELDED_ONLY" then return true end
    end
    return false
end
   
local function itemOnlyAffectsStuckins(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_STUCKINS_ONLY" then return true end
    end
    return false
end
       
local function itemIsInValidPosition(item_inv, syndrome)
    if (item_inv.mode == 0 and not itemAffectsHauler(syndrome)) or (item_inv.mode == 7 and not itemAffectsStuckins(syndrome)) or (item_inv.mode ~= 2 and itemIsArmorOnly(syndrome)) or (item_inv.mode ~=1 and itemIsWieldedOnly(syndrome)) or (item_inv.mode ~=7 and itemOnlyAffectsStuckins(syndrome)) then return false end
    return true
end

local function syndromeIsTransformation(syndrome)
    for _,effect in ipairs(syndrome.ce) do
        local effectType = tostring(effect)
        if string.find(effectType,"body_transformation") then return true end
    end
    return false
end

local function rememberInventory(unit)
    local invCopy = {}
    for inv_id,item_inv in ipairs(unit.inventory) do
        invCopy[inv_id+1] = {}
        local itemToWorkOn = invCopy[inv_id+1]
        itemToWorkOn.item = item_inv.item
        itemToWorkOn.mode = item_inv.mode
        itemToWorkOn.body_part_id = item_inv.body_part_id
    end
    return invCopy
end

local function moveAllToInventory(unit,invTable)
    for _,item_inv in ipairs(invTable) do
        dfhack.items.moveToInventory(item_inv.item,unit,item_inv.mode,item_inv.body_part_id)
    end
end

local function findItems()
    for _uid,unit in ipairs(df.global.world.units.all) do
        local transformation = false
        for itemid,item_inv in ipairs(unit.inventory) do
            local item = item_inv.item
if itemsyndromedebug then print("checking item #" .. itemid .." on unit #" .. _uid) end
            if getSyndrome(getMaterial(item)) then
if itemsyndromedebug then print("item has a syndrome, checking if item is valid for application...") end
                local syndrome = getSyndrome(getMaterial(item))
                local syndromeApplied
                if syndromeIsTransformation(syndrome) then
                    unitInventory = rememberInventory(unit)
                    transformation = true
                end
                if syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then
                    assignSyndrome(unit,syndrome.id)
                    syndromeApplied = true
                end
            end
            if itemHasSyndrome(item) then
if itemsyndromedebug then print("Item itself has a syndrome, checking if item is in correct position and creature is affected") end
                local syndrome = itemHasSyndrome(item)
                if syndromeIsTransformation(syndrome) then
                    unitInventory = rememberInventory(unit)
                    transformation = true
                end
                if item_inv.mode~=0 and item_inv.mode~=7 and creatureIsAffected(unit,syndrome) then assignSyndrome(unit,syndrome.id) end --the mode thing is to avoid stuckins from doing
            end
            if item.contaminants then
if itemsyndromedebug then print("Item has contaminants. Checking for syndromes...") end
                for _,contaminant in ipairs(item.contaminants) do
if itemsyndromedebug then print("Checking contaminant #" .. _ .. " on item #" .. itemid .. " on unit #" .. _uid ..".") end
                    if getSyndrome(getMaterial(contaminant)) then
                        local syndrome = getSyndrome(getMaterial(contaminant))
                        if syndromeIsTransformation(syndrome) then
                            unitInventory = rememberInventory(unit)
                            transformation =true
                        end
                        if syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then assignSyndrome(unit,syndrome.id) end
                    end
                end
            end
        end
        if transformation then dfhack.timeout(2,"ticks",function() moveAllToInventory(unit,unitInventory) end) end
    end
end


dfhack.onStateChange.itemsyndrome = function(code) --Many thanks to Warmist for pointing this out to me!
    if code==SC_WORLD_LOADED then
print("World loaded, itemsyndrome running...")
        itemsyndrome()
    end
end

function itemsyndrome()
if itemsyndromedebug then print("Beginning cycle.")
    findItems()
    dfhack.timeout(delayTicks,'ticks',itemsyndrome)
end

if enable then
    dfhack.onStateChange.itemsyndrome()
print("Enabled itemsyndrome.")
enable = false
end

if force then
findItems()
force = false
end

if disable then
itemsyndrome = nil
dfhack.onStateChange.itemsyndrome = nil
print("Disabled itemsyndrome.")
disable = false
end

print(delayTicks)

Here's that debug thing again, with some more code added. Tell me the output when you run "itemsyndrome enable 150 debug".

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #326 on: August 29, 2013, 07:49:15 pm »

...rs\Anna\Desktop\LFR DFHack Test Copy\hack\lua\dfhack.lua:348: ...sktop\LFR DF
Hack Test Copy\hack\scripts/itemsyndrome.lua:332: 'end' expected (to close 'func
tion' at line 308) near <eof>
stack traceback:
        [C]: in function 'error'
        ...rs\Anna\Desktop\LFR DFHack Test Copy\hack\lua\dfhack.lua:348: in func
tion <...rs\Anna\Desktop\LFR DFHack Test Copy\hack\lua\dfhack.lua:338>

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #327 on: August 29, 2013, 07:51:13 pm »

eheheh... that's embarrassing >_>

Code: [Select]
-- Checks regularly if creature has an item equipped with a special syndrome and applies item's syndrome if it is. Use "disable" (minus quotes) to disable. You can also change the

local function getDelayTicks(args)
for k,v in ipairs(args) do
if tonumber(v) and tonumber(v) > 0 then
return tonumber(v)
end
end
return nil
end

local args = {...}

function processArgs(args)
if #args==0 then enable = true return end
for k,v in ipairs(args) do
if v == "enable" then enable = true end
if v == "disable" then disable = true end
if v == "force" then force = true end
if v == "plus" then delayTicks = delayTicks+1 end
if v == "minus" then delayTicks = delayTicks-1 end
if v == "debugon" then itemsyndromedebug = true end
if v == "debugoff" then itemsyndromedebug = false end
end
end

delayTicks = getDelayTicks(args) or delayTicks or 499

processArgs(args)

local function getMaterial(item)
    local material = dfhack.matinfo.decode(item)
    if material.mode ~= "inorganic"  then
return nil
else
return material.material --the "material" thing up there contains a bit more info which is all pretty important, like the creature that the material comes from
end
end

local function findItemSyndromeInorganic()
local allInorganics = {}
    for matID,material in ipairs(df.global.world.raws.inorganics) do
        if string.find(material.id,"DFHACK_ITEMSYNDROME_MATERIAL_") then table.insert(allInorganics,matID) end --the last underscore is needed to prevent duped raws; I want good modder courtesy if it kills me, dammit!
    end
if itemsyndromedebug then printall(allInorganics) end
    if #allInorganics>0 then return allInorganics else return nil end
end

local function getAllItemSyndromeMats(itemSyndromeMatIDs)
local allActualInorganics = {}
for _,itemSyndromeMatID in ipairs(itemSyndromeMatIDs) do
table.insert(allActualInorganics,df.global.world.raws.inorganics[itemSyndromeMatID].material)
end
if itemsyndromedebug then printall(allActualInorganics) end
return allActualInorganics
end

itemSyndromeMatIDs = findItemSyndromeInorganic()

if itemSyndromeMatIDs then itemSyndromeMats = getAllItemSyndromeMats(itemSyndromeMatIDs) end

local function getSyndrome(material)
    if material==nil then return nil end
    if #material.syndrome>0 then return material.syndrome[0]
    else return nil end
end

local function syndromeIsDfHackSyndrome(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_ITEM_SYNDROME" then return true end
    end
    return false
end

local function itemHasNoSubtype(item)
    local itemtype = tostring(item)
    local subtypedItemTypes =
    {
    "armor",
    "weapon",
    "helm",
    "shoes",
    "shield",
    "glove",
    "pants",
    "tool",
    "siegeammo",
    "ammo",
    "trapcomp",
    "instrument",
    "toy"}
    for _,v in ipairs(subtypedItemTypes) do
        if string.find(itemtype,v) then return false end
    end
    return true
end

local function itemHasSyndrome(item)
    if itemHasNoSubtype(item) or not itemSyndromeMats then return nil end
    for _,material in ipairs(itemSyndromeMats) do
for __,syndrome in ipairs(material.syndrome) do
if syndrome.syn_name == item.subtype.name then return syndrome end
end
end
    return nil
end

local function alreadyHasSyndrome(unit,syn_id)
    for _,syndrome in ipairs(unit.syndromes.active) do
        if syndrome.type == syn_id then return true end
    end
    return false
end

local function assignSyndrome(target,syn_id) --taken straight from here, but edited so I can understand it better: https://gist.github.com/warmist/4061959/. Also implemented expwnent's changes for compatibility with syndromeTrigger.
    if target==nil then
        return nil
    end
    if alreadyHasSyndrome(target,syn_id) then
        local syndrome
        for k,v in ipairs(target.syndromes.active) do
            if v.type == syn_id then syndrome = v end
        end
        if not syndrome then return nil end
        syndrome.ticks=1
        return true
    end
    local newSyndrome=df.unit_syndrome:new()
    local target_syndrome=df.syndrome.find(syn_id)
    newSyndrome.type=target_syndrome.id
    newSyndrome.year=df.global.cur_year
    newSyndrome.year_time=df.global.cur_year_tick
    newSyndrome.ticks=1
    newSyndrome.unk1=1
    for k,v in ipairs(target_syndrome.ce) do
        local sympt=df.unit_syndrome.T_symptoms:new()
        sympt.ticks=1
        sympt.flags=2
        newSyndrome.symptoms:insert("#",sympt)
    end
    target.syndromes.active:insert("#",newSyndrome)
if itemsyndromedebug then
print("Assigned syndrome #" ..syn_id.." to unit.")
end
    return true
end

local function syndromeIsIndiscriminate(syndrome)
    if #syndrome.syn_affected_class==0 and #syndrome.syn_affected_creature==0 and #syndrome.syn_affected_caste==0 and #syndrome.syn_immune_class==0 and #syndrome.syn_immune_creature==0 and #syndrome.syn_immune_caste==0 then return true end
    return false
end

local function creatureIsAffected(unit,syndrome)
    if syndromeIsIndiscriminate(syndrome) then return true end
    local affected = false
    local unitraws = df.creature_raw.find(unit.race)
    local casteraws = unitraws.caste[unit.caste]
    local unitracename = unitraws.creature_id
    local castename = casteraws.caste_id
    local unitclasses = casteraws.creature_class
    for _,unitclass in ipairs(unitclasses) do
        for _,syndromeclass in ipairs(syndrome.syn_affected_class) do
            if unitclass.value==syndromeclass.value then affected = true end
        end
    end
    for caste,creature in ipairs(syndrome.syn_affected_creature) do
        local affected_creature = creature.value
        local affected_caste = syndrome.syn_affected_caste[caste].value --slightly evil, but oh well, hehe.
        if affected_creature == unitracename and affected_caste == castename then affected = true end
    end
    for _,unitclass in ipairs(unitclasses) do
        for _,syndromeclass in ipairs(syndrome.syn_immune_class) do
            if unitclass.value==syndromeclass.value then affected = false end
        end
    end
    for caste,creature in ipairs(syndrome.syn_immune_creature) do
        local immune_creature = creature.value
        local immune_caste = syndrome.syn_immune_caste[caste].value
        if immune_creature == unitracename and immune_caste == castename then affected = false end
    end
if itemsyndromedebug then
if not affected then print ("Creature is not affected.") else print("Creature is affected") end
end
    return affected
end

local function itemAffectsHauler(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_AFFECTS_HAULER" then return true end
    end
    return false
end

local function itemAffectsStuckins(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_AFFECTS_STUCKIN" then return true end
    end
    return false
end

local function itemIsArmorOnly(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_ARMOR_ONLY" then return true end
    end
    return false
end
   
local function itemIsWieldedOnly(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_WIELDED_ONLY" then return true end
    end
    return false
end
   
local function itemOnlyAffectsStuckins(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_STUCKINS_ONLY" then return true end
    end
    return false
end
       
local function itemIsInValidPosition(item_inv, syndrome)
    if (item_inv.mode == 0 and not itemAffectsHauler(syndrome)) or (item_inv.mode == 7 and not itemAffectsStuckins(syndrome)) or (item_inv.mode ~= 2 and itemIsArmorOnly(syndrome)) or (item_inv.mode ~=1 and itemIsWieldedOnly(syndrome)) or (item_inv.mode ~=7 and itemOnlyAffectsStuckins(syndrome)) then return false end
    return true
end

local function syndromeIsTransformation(syndrome)
    for _,effect in ipairs(syndrome.ce) do
        local effectType = tostring(effect)
        if string.find(effectType,"body_transformation") then return true end
    end
    return false
end

local function rememberInventory(unit)
    local invCopy = {}
    for inv_id,item_inv in ipairs(unit.inventory) do
        invCopy[inv_id+1] = {}
        local itemToWorkOn = invCopy[inv_id+1]
        itemToWorkOn.item = item_inv.item
        itemToWorkOn.mode = item_inv.mode
        itemToWorkOn.body_part_id = item_inv.body_part_id
    end
    return invCopy
end

local function moveAllToInventory(unit,invTable)
    for _,item_inv in ipairs(invTable) do
        dfhack.items.moveToInventory(item_inv.item,unit,item_inv.mode,item_inv.body_part_id)
    end
end

local function findItems()
    for _uid,unit in ipairs(df.global.world.units.all) do
        local transformation = false
        for itemid,item_inv in ipairs(unit.inventory) do
            local item = item_inv.item
if itemsyndromedebug then print("checking item #" .. itemid .." on unit #" .. _uid) end
            if getSyndrome(getMaterial(item)) then
if itemsyndromedebug then print("item has a syndrome, checking if item is valid for application...") end
                local syndrome = getSyndrome(getMaterial(item))
                local syndromeApplied
                if syndromeIsTransformation(syndrome) then
                    unitInventory = rememberInventory(unit)
                    transformation = true
                end
                if syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then
                    assignSyndrome(unit,syndrome.id)
                    syndromeApplied = true
                end
            end
            if itemHasSyndrome(item) then
if itemsyndromedebug then print("Item itself has a syndrome, checking if item is in correct position and creature is affected") end
                local syndrome = itemHasSyndrome(item)
                if syndromeIsTransformation(syndrome) then
                    unitInventory = rememberInventory(unit)
                    transformation = true
                end
                if item_inv.mode~=0 and item_inv.mode~=7 and creatureIsAffected(unit,syndrome) then assignSyndrome(unit,syndrome.id) end --the mode thing is to avoid stuckins from doing
            end
            if item.contaminants then
if itemsyndromedebug then print("Item has contaminants. Checking for syndromes...") end
                for _,contaminant in ipairs(item.contaminants) do
if itemsyndromedebug then print("Checking contaminant #" .. _ .. " on item #" .. itemid .. " on unit #" .. _uid ..".") end
                    if getSyndrome(getMaterial(contaminant)) then
                        local syndrome = getSyndrome(getMaterial(contaminant))
                        if syndromeIsTransformation(syndrome) then
                            unitInventory = rememberInventory(unit)
                            transformation =true
                        end
                        if syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then assignSyndrome(unit,syndrome.id) end
                    end
                end
            end
        end
        if transformation then dfhack.timeout(2,"ticks",function() moveAllToInventory(unit,unitInventory) end) end
    end
end


dfhack.onStateChange.itemsyndrome = function(code) --Many thanks to Warmist for pointing this out to me!
    if code==SC_WORLD_LOADED then
print("World loaded, itemsyndrome running...")
        itemsyndrome()
    end
end

function itemsyndrome()
if itemsyndromedebug then print("Beginning cycle.") end
    findItems()
    dfhack.timeout(delayTicks,'ticks',itemsyndrome)
end

if enable then
    dfhack.onStateChange.itemsyndrome()
print("Enabled itemsyndrome.")
enable = false
end

if force then
findItems()
force = false
end

if disable then
itemsyndrome = nil
dfhack.onStateChange.itemsyndrome = nil
print("Disabled itemsyndrome.")
disable = false
end

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #328 on: August 29, 2013, 07:53:02 pm »

eheheh... that's embarrassing >_>

Code: [Select]
-- Checks regularly if creature has an item equipped with a special syndrome and applies item's syndrome if it is. Use "disable" (minus quotes) to disable. You can also change the

local function getDelayTicks(args)
for k,v in ipairs(args) do
if tonumber(v) and tonumber(v) > 0 then
return tonumber(v)
end
end
return nil
end

local args = {...}

function processArgs(args)
if #args==0 then enable = true return end
for k,v in ipairs(args) do
if v == "enable" then enable = true end
if v == "disable" then disable = true end
if v == "force" then force = true end
if v == "plus" then delayTicks = delayTicks+1 end
if v == "minus" then delayTicks = delayTicks-1 end
if v == "debugon" then itemsyndromedebug = true end
if v == "debugoff" then itemsyndromedebug = false end
end
end

delayTicks = getDelayTicks(args) or delayTicks or 499

processArgs(args)

local function getMaterial(item)
    local material = dfhack.matinfo.decode(item)
    if material.mode ~= "inorganic"  then
return nil
else
return material.material --the "material" thing up there contains a bit more info which is all pretty important, like the creature that the material comes from
end
end

local function findItemSyndromeInorganic()
local allInorganics = {}
    for matID,material in ipairs(df.global.world.raws.inorganics) do
        if string.find(material.id,"DFHACK_ITEMSYNDROME_MATERIAL_") then table.insert(allInorganics,matID) end --the last underscore is needed to prevent duped raws; I want good modder courtesy if it kills me, dammit!
    end
if itemsyndromedebug then printall(allInorganics) end
    if #allInorganics>0 then return allInorganics else return nil end
end

local function getAllItemSyndromeMats(itemSyndromeMatIDs)
local allActualInorganics = {}
for _,itemSyndromeMatID in ipairs(itemSyndromeMatIDs) do
table.insert(allActualInorganics,df.global.world.raws.inorganics[itemSyndromeMatID].material)
end
if itemsyndromedebug then printall(allActualInorganics) end
return allActualInorganics
end

itemSyndromeMatIDs = findItemSyndromeInorganic()

if itemSyndromeMatIDs then itemSyndromeMats = getAllItemSyndromeMats(itemSyndromeMatIDs) end

local function getSyndrome(material)
    if material==nil then return nil end
    if #material.syndrome>0 then return material.syndrome[0]
    else return nil end
end

local function syndromeIsDfHackSyndrome(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_ITEM_SYNDROME" then return true end
    end
    return false
end

local function itemHasNoSubtype(item)
    local itemtype = tostring(item)
    local subtypedItemTypes =
    {
    "armor",
    "weapon",
    "helm",
    "shoes",
    "shield",
    "glove",
    "pants",
    "tool",
    "siegeammo",
    "ammo",
    "trapcomp",
    "instrument",
    "toy"}
    for _,v in ipairs(subtypedItemTypes) do
        if string.find(itemtype,v) then return false end
    end
    return true
end

local function itemHasSyndrome(item)
    if itemHasNoSubtype(item) or not itemSyndromeMats then return nil end
    for _,material in ipairs(itemSyndromeMats) do
for __,syndrome in ipairs(material.syndrome) do
if syndrome.syn_name == item.subtype.name then return syndrome end
end
end
    return nil
end

local function alreadyHasSyndrome(unit,syn_id)
    for _,syndrome in ipairs(unit.syndromes.active) do
        if syndrome.type == syn_id then return true end
    end
    return false
end

local function assignSyndrome(target,syn_id) --taken straight from here, but edited so I can understand it better: https://gist.github.com/warmist/4061959/. Also implemented expwnent's changes for compatibility with syndromeTrigger.
    if target==nil then
        return nil
    end
    if alreadyHasSyndrome(target,syn_id) then
        local syndrome
        for k,v in ipairs(target.syndromes.active) do
            if v.type == syn_id then syndrome = v end
        end
        if not syndrome then return nil end
        syndrome.ticks=1
        return true
    end
    local newSyndrome=df.unit_syndrome:new()
    local target_syndrome=df.syndrome.find(syn_id)
    newSyndrome.type=target_syndrome.id
    newSyndrome.year=df.global.cur_year
    newSyndrome.year_time=df.global.cur_year_tick
    newSyndrome.ticks=1
    newSyndrome.unk1=1
    for k,v in ipairs(target_syndrome.ce) do
        local sympt=df.unit_syndrome.T_symptoms:new()
        sympt.ticks=1
        sympt.flags=2
        newSyndrome.symptoms:insert("#",sympt)
    end
    target.syndromes.active:insert("#",newSyndrome)
if itemsyndromedebug then
print("Assigned syndrome #" ..syn_id.." to unit.")
end
    return true
end

local function syndromeIsIndiscriminate(syndrome)
    if #syndrome.syn_affected_class==0 and #syndrome.syn_affected_creature==0 and #syndrome.syn_affected_caste==0 and #syndrome.syn_immune_class==0 and #syndrome.syn_immune_creature==0 and #syndrome.syn_immune_caste==0 then return true end
    return false
end

local function creatureIsAffected(unit,syndrome)
    if syndromeIsIndiscriminate(syndrome) then return true end
    local affected = false
    local unitraws = df.creature_raw.find(unit.race)
    local casteraws = unitraws.caste[unit.caste]
    local unitracename = unitraws.creature_id
    local castename = casteraws.caste_id
    local unitclasses = casteraws.creature_class
    for _,unitclass in ipairs(unitclasses) do
        for _,syndromeclass in ipairs(syndrome.syn_affected_class) do
            if unitclass.value==syndromeclass.value then affected = true end
        end
    end
    for caste,creature in ipairs(syndrome.syn_affected_creature) do
        local affected_creature = creature.value
        local affected_caste = syndrome.syn_affected_caste[caste].value --slightly evil, but oh well, hehe.
        if affected_creature == unitracename and affected_caste == castename then affected = true end
    end
    for _,unitclass in ipairs(unitclasses) do
        for _,syndromeclass in ipairs(syndrome.syn_immune_class) do
            if unitclass.value==syndromeclass.value then affected = false end
        end
    end
    for caste,creature in ipairs(syndrome.syn_immune_creature) do
        local immune_creature = creature.value
        local immune_caste = syndrome.syn_immune_caste[caste].value
        if immune_creature == unitracename and immune_caste == castename then affected = false end
    end
if itemsyndromedebug then
if not affected then print ("Creature is not affected.") else print("Creature is affected") end
end
    return affected
end

local function itemAffectsHauler(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_AFFECTS_HAULER" then return true end
    end
    return false
end

local function itemAffectsStuckins(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_AFFECTS_STUCKIN" then return true end
    end
    return false
end

local function itemIsArmorOnly(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_ARMOR_ONLY" then return true end
    end
    return false
end
   
local function itemIsWieldedOnly(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_WIELDED_ONLY" then return true end
    end
    return false
end
   
local function itemOnlyAffectsStuckins(syndrome)
    for k,v in ipairs(syndrome.syn_class) do
        if v.value=="DFHACK_STUCKINS_ONLY" then return true end
    end
    return false
end
       
local function itemIsInValidPosition(item_inv, syndrome)
    if (item_inv.mode == 0 and not itemAffectsHauler(syndrome)) or (item_inv.mode == 7 and not itemAffectsStuckins(syndrome)) or (item_inv.mode ~= 2 and itemIsArmorOnly(syndrome)) or (item_inv.mode ~=1 and itemIsWieldedOnly(syndrome)) or (item_inv.mode ~=7 and itemOnlyAffectsStuckins(syndrome)) then return false end
    return true
end

local function syndromeIsTransformation(syndrome)
    for _,effect in ipairs(syndrome.ce) do
        local effectType = tostring(effect)
        if string.find(effectType,"body_transformation") then return true end
    end
    return false
end

local function rememberInventory(unit)
    local invCopy = {}
    for inv_id,item_inv in ipairs(unit.inventory) do
        invCopy[inv_id+1] = {}
        local itemToWorkOn = invCopy[inv_id+1]
        itemToWorkOn.item = item_inv.item
        itemToWorkOn.mode = item_inv.mode
        itemToWorkOn.body_part_id = item_inv.body_part_id
    end
    return invCopy
end

local function moveAllToInventory(unit,invTable)
    for _,item_inv in ipairs(invTable) do
        dfhack.items.moveToInventory(item_inv.item,unit,item_inv.mode,item_inv.body_part_id)
    end
end

local function findItems()
    for _uid,unit in ipairs(df.global.world.units.all) do
        local transformation = false
        for itemid,item_inv in ipairs(unit.inventory) do
            local item = item_inv.item
if itemsyndromedebug then print("checking item #" .. itemid .." on unit #" .. _uid) end
            if getSyndrome(getMaterial(item)) then
if itemsyndromedebug then print("item has a syndrome, checking if item is valid for application...") end
                local syndrome = getSyndrome(getMaterial(item))
                local syndromeApplied
                if syndromeIsTransformation(syndrome) then
                    unitInventory = rememberInventory(unit)
                    transformation = true
                end
                if syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then
                    assignSyndrome(unit,syndrome.id)
                    syndromeApplied = true
                end
            end
            if itemHasSyndrome(item) then
if itemsyndromedebug then print("Item itself has a syndrome, checking if item is in correct position and creature is affected") end
                local syndrome = itemHasSyndrome(item)
                if syndromeIsTransformation(syndrome) then
                    unitInventory = rememberInventory(unit)
                    transformation = true
                end
                if item_inv.mode~=0 and item_inv.mode~=7 and creatureIsAffected(unit,syndrome) then assignSyndrome(unit,syndrome.id) end --the mode thing is to avoid stuckins from doing
            end
            if item.contaminants then
if itemsyndromedebug then print("Item has contaminants. Checking for syndromes...") end
                for _,contaminant in ipairs(item.contaminants) do
if itemsyndromedebug then print("Checking contaminant #" .. _ .. " on item #" .. itemid .. " on unit #" .. _uid ..".") end
                    if getSyndrome(getMaterial(contaminant)) then
                        local syndrome = getSyndrome(getMaterial(contaminant))
                        if syndromeIsTransformation(syndrome) then
                            unitInventory = rememberInventory(unit)
                            transformation =true
                        end
                        if syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then assignSyndrome(unit,syndrome.id) end
                    end
                end
            end
        end
        if transformation then dfhack.timeout(2,"ticks",function() moveAllToInventory(unit,unitInventory) end) end
    end
end


dfhack.onStateChange.itemsyndrome = function(code) --Many thanks to Warmist for pointing this out to me!
    if code==SC_WORLD_LOADED then
print("World loaded, itemsyndrome running...")
        itemsyndrome()
    end
end

function itemsyndrome()
if itemsyndromedebug then print("Beginning cycle.") end
    findItems()
    dfhack.timeout(delayTicks,'ticks',itemsyndrome)
end

if enable then
    dfhack.onStateChange.itemsyndrome()
print("Enabled itemsyndrome.")
enable = false
end

if force then
findItems()
force = false
end

if disable then
itemsyndrome = nil
dfhack.onStateChange.itemsyndrome = nil
print("Disabled itemsyndrome.")
disable = false
end

It happens, I understand.  :)

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #329 on: August 29, 2013, 07:57:07 pm »

I get "World loaded, itemsyndrome running..." when it loads up the world, but the syndrome still doesn't get applied unless I force it.

Code: (material) [Select]
[INORGANIC:DFHACK_ITEMSYNDROME_MATERIAL_FLAYER]
[USE_MATERIAL_TEMPLATE:STONE_VAPOR_TEMPLATE]
[SYNDROME]
[SYN_NAME:flayer]
[SYN_CLASS:DFHACK_ITEM_SYNDROME]
[SYN_CLASS:DFHACK_WIELDED_ONLY]
[CE_CAN_DO_INTERACTION:START:0:END:160]
  [CDI:INTERACTION:FLAYER_WEAPON_SKILL_LFR]
    [CDI:ADV_NAME:Inflict pain]
      [CDI:USAGE_HINT:ATTACK]
    [CDI:TARGET:C:LINE_OF_SIGHT]
    [CDI:TARGET_RANGE:C:2]
  [CDI:TARGET_VERB:feel the painful presence of a nearby flayer:feels the painful presence of a nearby flayer]
    [CDI:MAX_TARGET_NUMBER:C:20]
    [CDI:WAIT_PERIOD:50]
  [CDI:FREE_ACTION]




Code: (weapon) [Select]
[ITEM_WEAPON:ITEM_WEAPON_FLAYER]
[NAME:flayer:flayers]
[SIZE:300]
[SKILL:WHIP]
[TWO_HANDED:25500]
[MINIMUM_SIZE:20500]
[MATERIAL_SIZE:2]
[ATTACK:EDGE:100:10:lash:lashes:NO_SUB:1800]
[ATTACK:EDGE:100:10:whip:whips:many tongues:1700]

Code: (interaction) [Select]
[INTERACTION:FLAYER_WEAPON_SKILL_LFR]
[I_SOURCE:CREATURE_ACTION]
[I_TARGET:C:CREATURE]
[IT_LOCATION:CONTEXT_CREATURE]
[IT_CANNOT_TARGET_IF_ALREADY_AFFECTED]
[IT_MANUAL_INPUT:target]
[IT_CANNOT_HAVE_SYNDROME_CLASS:OLD_GOD_LFR]
[IT_CANNOT_HAVE_SYNDROME_CLASS:HEX_IMMUNITY]
[I_EFFECT:ADD_SYNDROME]
[IE_TARGET:C]
[IE_IMMEDIATE]
[SYNDROME]
[SYN_CLASS:HEX_LFR]
[SYN_NAME:flayer exposure]
[SYN_IMMUNE_CLASS:OLD_GOD_LFR]
          [SYN_IMMUNE_CREATURE:CARBUNCLE_LFR:FEMALE_SPEC_FIVE]
[CE_PAIN:SEV:1400:PROB:100:BP:BY_CATEGORY:ALL:SKIN:START:0:PEAK:60:END:100]
[CE_PAIN:SEV:600:PROB:100:BP:BY_CATEGORY:ALL:MUSCLE:START:0:PEAK:60:END:100]
[CE_BLEEDING:SEV:100:PROB:80:BP:BY_CATEGORY:ALL:SKIN:START:0:PEAK:1:END:100]
« Last Edit: August 29, 2013, 08:01:41 pm by narhiril »
Logged
Pages: 1 ... 20 21 [22] 23 24 ... 44