Bay 12 Games Forum

Please login or register.

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

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

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Putnam's DFHack modder's utilities
« Reply #300 on: August 26, 2013, 01:21:47 pm »

Add SYN_AFFECTED_CREATURE:DWARF:ALL. But otherwise I see no problems, it looks correct to me.
Logged
::: ☼Meph Tileset☼☼Map Tileset☼- 32x graphic sets with TWBT :::
::: ☼MASTERWORK DF☼ - A comprehensive mod pack now on Patreon - 250.000+ downloads and counting :::
::: WorldBicyclist.com - Follow my bike tours around the world - 148 countries visited :::

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #301 on: August 26, 2013, 01:40:36 pm »

If it has no SYN_AFFECTED_CREATURE, it should work regardless. Also, the end value may be messing you up; I have it set so that it's 499 ticks between reapplication instead of 150 for speed. You could set it back to 150 with "itemsyndrome 150" in the init. Also, I don't think DWARF:ALL will work.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #302 on: August 26, 2013, 03:40:26 pm »

Still doesn't work with ticks set to 150 or with an affected creature specified.  Is this an insurmountable problem with arena mode or am I doing something wrong?  What I want is any creature who picks up a weapon of this type to be able to use the interaction, regardless of the item's material or origin.
« Last Edit: August 26, 2013, 03:42:05 pm by narhiril »
Logged

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #303 on: August 26, 2013, 03:41:27 pm »

Hmm... if you have another itemsyndrome inorganic, try placing the syndrome in there.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #304 on: August 26, 2013, 03:42:44 pm »

Hmm... if you have another itemsyndrome inorganic, try placing the syndrome in there.

Does this need to be in hack/raw?

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #305 on: August 26, 2013, 03:44:51 pm »

It should be in your normal raws, with all the other raws. Hack/raws is just where examples go. I should really put my examples there, actually...

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #306 on: August 26, 2013, 03:53:36 pm »

It should be in your normal raws, with all the other raws. Hack/raws is just where examples go. I should really put my examples there, actually...

Code: (inorganic_z_itemsyndrome_lfr.txt) [Select]
inorganic_z_itemsyndrome_lfr

[OBJECT:INORGANIC]

[INORGANIC:DFHACK_ITEMSYNDROME_MATERIAL_HELLFIRE1]
[USE_MATERIAL_TEMPLATE:STONE_VAPOR_TEMPLATE]
[SYNDROME]
[SYN_NAME:hellfire brand]
[SYN_CLASS:DFHACK_ITEM_SYNDROME]
[SYN_CLASS:DFHACK_WIELDED_ONLY]
[CE_CAN_DO_INTERACTION:START:0:END:160]
[CDI:ADV_NAME:Zalkor's hellstorm]
[CDI:INTERACTION:MATERIAL_EMISSION]
[CDI:FLOW:DRAGONFIRE]
[CDI:TARGET:C:LINE_OF_SIGHT]
[CDI:TARGET_RANGE:C:12]
    [CDI:VERB:invoke a hellstorm:invokes a hellstorm:NA]
[CDI:MAX_TARGET_NUMBER:C:3]
[CDI:WAIT_PERIOD:1500]
[CDI:USAGE_HINT:ATTACK]


Code: (item_weapon_hellfire_test.txt) [Select]
item_weapon_hellfire_test


[OBJECT:ITEM]

[ITEM_WEAPON:ITEM_WEAPON_HELLFIRE_BRAND]
[NAME:hellfire brand:hellfire brands]
[SIZE:550]
[SKILL:SWORD]
[TWO_HANDED:22500]
[MINIMUM_SIZE:20000]
[MATERIAL_SIZE:3]
[ATTACK:BLUNT:10:4000:jab:jabs:end:1100]
[ATTACK:BLUNT:8000:3000:beat:beats:NO_SUB:1100]
[ATTACK:BLUNT:50:3000:strike:strikes:pommel:1000]


Fire it up in arena, give an iron hellfire brand to a dwarf, give him a target, enable itemsyndrome, change ticks to 150, then force itemsyndrome.  Nothing happens.  He doesn't get a syndrome in his unit window and he sure as hell isn't shooting fire. 

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #307 on: August 26, 2013, 04:13:13 pm »

Here, try this debug version of itemsyndrome and tell me what it puts into the DFHack console:

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
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
printall(allInorganics)
    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
printall(allActualInorganics)
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 itemSyndromeMat 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)
print("Assigned syndrome #" ..syn_id.." to unit.")
    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
    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 getSyndrome(getMaterial(item)) then
                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
                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
                for _,contaminant in ipairs(item.contaminants) do
                    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
        itemsyndrome()
    end
end

function itemsyndrome()
    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
callback = nil
dfhack.onStateChange.itemsyndrome = nil
print("Disabled itemsyndrome.")
disable = false
end

print(delayTicks)

You can copy+paste in the console by right clicking the top, finding mark, highlighting it all, then pressing enter.

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #308 on: August 26, 2013, 04:39:34 pm »

[DFHack]# itemsyndrome force
1                        = 346
2                        = 392
1                        = <material: 0x096a2688>
2                        = <material: 0x096c2688>
150
« Last Edit: August 26, 2013, 04:45:44 pm by narhiril »
Logged

Putnam

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

There are 2 different materials found (346 and 392), but both are the same material. This means... something's wrong. Duped raws, maybe.

narhiril

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

There are 2 different materials found (346 and 392), but both are the same material. This means... something's wrong. Duped raws, maybe.

Good catch, forgot I changed that file name.  However, it's still not working.

[DFHack]# itemsyndrome force
1                        = 346
1                        = <material: 0x08fbf0b8>
150

I haven't had a chance to try it outside of arena mode.

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #311 on: August 26, 2013, 07:55:09 pm »

Yeah, your debug output shows that the syndrome isn't being applied. Let's see here...

Out of a bit of desperation on my part, try putting in the DFHACK_ITEM_SYNDROME syn class.

If that doesn't work, here's an even more verbose debug version of itemsyndrome (next version will have this version with all the debug code put behind a wall that requires you to type "debug" as an argument):

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
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
printall(allInorganics)
    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
printall(allActualInorganics)
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 itemSyndromeMat 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 debug 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 not affected then print ("Creature is not affected.") else print("Creature is affected") 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
print("checking item #" .. itemid .." on unit #" .. _uid)
            if getSyndrome(getMaterial(item)) then
print("item has a syndrome, checking if item is valid for application...")
                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
print("Item itself has a syndrome, checking if item is in correct position and creature is affected")
                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
print("Item has contaminants. Checking for syndromes...")
                for _,contaminant in ipairs(item.contaminants) do
print("Checking contaminant #" .. _ .. " on item #" .. itemid .. " on unit #" .. _uid ..".")
                    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
        itemsyndrome()
    end
end

function itemsyndrome()
    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
callback = nil
dfhack.onStateChange.itemsyndrome = nil
print("Disabled itemsyndrome.")
disable = false
end

print(delayTicks)

narhiril

  • Bay Watcher
  • [DUTY_BOUND]
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #312 on: August 27, 2013, 10:03:52 am »

Yeah, your debug output shows that the syndrome isn't being applied. Let's see here...

Out of a bit of desperation on my part, try putting in the DFHACK_ITEM_SYNDROME syn class.

If that doesn't work, here's an even more verbose debug version of itemsyndrome (next version will have this version with all the debug code put behind a wall that requires you to type "debug" as an argument):

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
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
printall(allInorganics)
    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
printall(allActualInorganics)
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 itemSyndromeMat 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 debug 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 not affected then print ("Creature is not affected.") else print("Creature is affected") 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
print("checking item #" .. itemid .." on unit #" .. _uid)
            if getSyndrome(getMaterial(item)) then
print("item has a syndrome, checking if item is valid for application...")
                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
print("Item itself has a syndrome, checking if item is in correct position and creature is affected")
                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
print("Item has contaminants. Checking for syndromes...")
                for _,contaminant in ipairs(item.contaminants) do
print("Checking contaminant #" .. _ .. " on item #" .. itemid .. " on unit #" .. _uid ..".")
                    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
        itemsyndrome()
    end
end

function itemsyndrome()
    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
callback = nil
dfhack.onStateChange.itemsyndrome = nil
print("Disabled itemsyndrome.")
disable = false
end

print(delayTicks)

[DFHack]# itemsyndrome force
1                        = 346
1                        = <material: 0x0956e838>
checking item #0 on unit #0
150

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: Putnam's DFHack modder's utilities
« Reply #313 on: August 27, 2013, 10:57:38 am »

... found it. Replace this function:

Code: [Select]
local function itemHasSyndrome(item)
    if itemHasNoSubtype(item) or not itemSyndromeMat 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

With this:

Code: [Select]
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

Meph

  • Bay Watcher
    • View Profile
    • worldbicyclist
Re: Putnam's DFHack modder's utilities
« Reply #314 on: August 27, 2013, 11:24:35 am »

So it got broke because one 's' was missing? Respect for finding it.
Logged
::: ☼Meph Tileset☼☼Map Tileset☼- 32x graphic sets with TWBT :::
::: ☼MASTERWORK DF☼ - A comprehensive mod pack now on Patreon - 250.000+ downloads and counting :::
::: WorldBicyclist.com - Follow my bike tours around the world - 148 countries visited :::
Pages: 1 ... 19 20 [21] 22 23 ... 44