Skip to content

Instantly share code, notes, and snippets.

@Putnam3145
Last active December 29, 2015 03:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Putnam3145/7609116 to your computer and use it in GitHub Desktop.
Save Putnam3145/7609116 to your computer and use it in GitHub Desktop.
Itemsyndrome for DFHack-0.34.11-r3.
-- Checks for inventory changes and applies or removes syndromes that items or their materials have. Use "disable" (minus quotes) to disable and "help" to get help.
local args = {...}
local function printItemSyndromeHelp()
print("Arguments:")
print(' "help": displays this dialogue.')
print(" ")
print(' "disable": disables the script.')
print(" ")
print(' "debugon/debugoff": debug mode.')
print(" ")
print(' "contaminantson/contaminantsoff": toggles searching for contaminants.')
print(' Disabling speeds itemsyndrome up greatly.')
end
function processArgs(args)
for k,v in ipairs(args) do
v=string.lower(v)
if v == "help" then printItemSyndromeHelp() return end
if v == "debugon" then itemsyndromedebug = true end
if v == "debugoff" then itemsyndromedebug = false end
if v == "contaminantson" then itemsyndromecontaminants = true end
if v == "contaminantsoff" then itemsyndromecontaminants = false end
end
end
processArgs(args)
local function getMaterial(item)
local material = dfhack.matinfo.decode(item)
if not material then return nil end
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 but impertinent, 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
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 subtypedItemTypes =
{
df.item_armorst,
df.item_weaponst,
df.item_helmst,
df.item_shoesst,
df.item_shieldst,
df.item_glovest,
df.item_pantsst,
df.item_toolst,
df.item_siegeammost,
df.item_ammost,
df.item_trapcompst,
df.item_instrumentst,
df.item_toyst}
for _,v in ipairs(subtypedItemTypes) do
if v:is_instance(item) 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 eraseSyndrome(target,syn_id)
for i=#target.syndromes.active-1,0,-1 do
if target.syndromes.active[i].type==syn_id then target.syndromes.active:erase(i) end
end
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 addOrRemoveSyndromeDepending(unit,item_inv,syndrome)
if item_inv and syndromeIsDfHackSyndrome(syndrome) and creatureIsAffected(unit,syndrome) and itemIsInValidPosition(item_inv, syndrome) then
assignSyndrome(unit,syndrome.id)
else
eraseSyndrome(unit,syndrome.id)
end
end
eventful=require('plugins.eventful')
eventful.enableEvent(eventful.eventType.INVENTORY_CHANGE,5)
local function checkAndAddSyndrome(unit_id,new_equip,item_id)
local item = df.item.find(item_id)
local unit = df.unit.find(unit_id)
if unit.flags1.dead then return false end
if itemsyndromedebug then print("Checking unit #" .. unit_id) end
local transformation = false
if itemsyndromedebug then print("checking item #" .. item_id .." on unit #" .. unit_id) 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))
if syndromeIsTransformation(syndrome) then
unitInventory = rememberInventory(unit)
transformation = true
end
addOrRemoveSyndromeDepending(unit,new_equip,syndrome)
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
addOrRemoveSyndromeDepending(unit,new_equip,syndrome)
end
if itemsyndromecontaminants and 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 #" .. item_id .. " on unit #" .. unit_id ..".") end
if getSyndrome(getMaterial(contaminant)) then
local syndrome = getSyndrome(getMaterial(contaminant))
if syndromeIsTransformation(syndrome) then
unitInventory = rememberInventory(unit)
transformation =true
end
addOrRemoveSyndromeDepending(unit,new_equip,syndrome)
end
end
end
if transformation then dfhack.timeout(2,"ticks",function() moveAllToInventory(unit,unitInventory) end) end
end
eventful.onInventoryChange.itemsyndrome=function(unit_id,item_id,old_equip,new_equip)
checkAndAddSyndrome(unit_id,new_equip,item_id)
end
dfhack.onStateChange.itemsyndrome=function(code)
if code==SC_WORLD_LOADED then
itemSyndromeMatIDs = findItemSyndromeInorganic()
if itemSyndromeMatIDs then itemSyndromeMats = getAllItemSyndromeMats(itemSyndromeMatIDs) end
end
end
if disable then
eventful.onInventoryChange.itemsyndrome=nil
print("Disabled itemsyndrome.")
disable = false
else
print("Enabled itemsyndrome.")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment