Lots of tweaks.

develop
expwnent 2014-07-09 06:21:52 -04:00
parent 1ce38f3e3a
commit a8f810cc3b
24 changed files with 76 additions and 783 deletions

34
NEWS

@ -21,35 +21,29 @@ DFHack future
syndrome-util.lua
makes it easier to deal with unit syndromes
scripts/
forumdwarves.lua
forum-dwarves.lua
helps copies df viewscreens to a file
fullheal.lua
full-heal.lua
fully heals a unit
removewear.lua
remove-wear.lua
removes wear from all items in the fort
repeat.lua
repeatedly calls a script or a plugin
ShowUnitSyndromes.rb
shows syndromes affecting units and other relevant info
skillChange.lua
changes the skill of a unit
Spawnunit.lua
creates units!
skillroll.lua
invokes dfhack commands based on random chances
teleport.lua
teleports units
scripts/devel/
printArgs.lua
print-args.lua
scripts/fix/
blooddel.lua
blood-del.lua
makes it so civs don't bring barrels full of blood ichor or goo
feeding-timers.lua
reset the feeding timers of all units
growthbug.lua
growth-bug.lua
fixes the growth bug
scripts/gui/
hackWish.lua
hack-wish.lua
creates items out of any material
unit-info-viewer.lua
displays information about units
@ -60,18 +54,15 @@ DFHack future
forces events: caravan, migrants, diplomat, megabeast, curiousbeast, mischievousbeast, flier, siege, nightcreature
item-trigger.lua
triggers commands based on equipping, unequipping, and wounding units with items
itemsyndrome.lua
adds and removes syndromes to units when they equip and unequip items
interaction-trigger.lua
triggers commands when interactions happen
invader-item-destroyer.lua
destroys invaders' items when they die
moddable-gods.lua
standardized version of Putnam's moddable gods script
moddableGods.lua
makes raw moddable gods possible
projectileExpansion.lua
adds extra functionality to projectiles
outside-only.lua
register buildings as outside only or inside only
replaces outsideOnly plugin
projectile-trigger.lua
standardized version of projectileExpansion
reaction-trigger.lua
@ -97,10 +88,7 @@ DFHack future
New plugins:
Misc improvements:
new script in utils.lua for standardized argument processing
outside-only
now buildings have to be registered as inside or outside only, and it checks periodically to see when buildings change outsideness
converted from plugin to script
new function in utils.lua for standardized argument processing
Removed
digmat.rb: digFlood does the same functionality with less FPS impact

@ -1,5 +1,6 @@
-- lua/plugins/repeatUtil.lua
-- author expwnent
-- tools for registering callbacks periodically
-- vaguely based on a script by Putnam
local _ENV = mkmodule("repeat-util")

@ -14,7 +14,7 @@ function findUnitSyndrome(unit,syn_id)
return nil
end
--usage: syndrome.ResetPolicy.DoNothing, syndrome.ResetPolicy.ResetDuration, etc
--usage: syndromeUtil.ResetPolicy.DoNothing, syndromeUtil.ResetPolicy.ResetDuration, etc
ResetPolicy = ResetPolicy or utils.invert({
"DoNothing",
"ResetDuration",
@ -37,7 +37,7 @@ function eraseSyndrome(unit,syndromeId,oldestFirst)
end
local syndromes = unit.syndromes.active
for i=i1,iN,d do
if syndromes[i].type == syndromeId then
if syndromes[i]['type'] == syndromeId then
syndromes:erase(i)
return true
end
@ -52,7 +52,8 @@ function eraseSyndromes(unit,syndromeId)
end
return count
end
--target is a df.unit, syndrome is a df.syndrome, resetPolicy is one of syndrome.ResetPolicy
--target is a df.unit, syndrome is a df.syndrome, resetPolicy is one of syndromeUtil.ResetPolicy
--if the target has an instance of the syndrome already, the reset policy takes effect
--returns true if the unit did not have the syndrome before calling and false otherwise
function infectWithSyndrome(target,syndrome,resetPolicy)

@ -1,9 +1,10 @@
--printArgs.lua
--print-args.lua
--author expwnent
--prints all the arguments on their own line with quotes around them. useful for debugging
local args = {...}
print("printArgs")
print("print-args")
for _,arg in ipairs(args) do
print("'"..arg.."'")
end

@ -1,4 +1,4 @@
--blooddel.lua
--blood-del.lua
--makes it so that civs won't come with barrels full of blood, ichor, or goo
--author Urist Da Vinci
--edited by expwnent

@ -1,17 +1,25 @@
--growthbug: units only grow when the current tick is 0 mod 10, so only 1/10 units will grow naturally. this script periodically sets the birth time of each unit so that it will grow
--to run periodically, use "repeat -time 2 months -command fix/growthBug now". see repeat.lua for details
-- author expwnent
--growth-bug.lua: units only grow when the current tick is 0 mod 10, so only 1/10 units will grow naturally. this script periodically sets the birth time of each unit so that it will grow
--to run periodically, use "repeat -time 2 months -command fix/growth-bug -now". see repeat.lua for details
--author expwnent
local args = {...}
if args[1] ~= nil then
print("fix/growthbug usage")
print(" fix/growthbug")
local utils = require 'utils'
validArgs = validArgs or utils.invert({
'help',
'now'
})
local args = utils.processArgs({...}, validArgs)
if args.help or not next(args) then
print("fix/growth-bug usage")
print(" fix/growth-bug")
print(" fix the growth bug for all units on the map")
print(" fix/growthbug help")
print(" fix/growth-bug -help")
print(" print this help message")
print(" repeat -time [n] [years/months/ticks/days/etc] -command fix/growthbug")
print(" repeat -time [n] [years/months/ticks/days/etc] -command fix/growth-bug now")
print(" run this script every n time units")
print(" repeat -cancel fix/growthbug")
print(" repeat -cancel fix/growth-bug")
print(" stop automatically running this script")
end
@ -19,8 +27,8 @@ local count = 0
for _,unit in ipairs(df.global.world.units.all) do
local offset = unit.relations.birth_time % 10;
if offset ~= 0 then
count = count+1
unit.relations.birth_time = unit.relations.birth_time - offset
count = count+1
end
end
print("Fixed growth bug for "..count.." units.")

@ -1,3 +1,4 @@
-- scripts/forum-dwarves.lua
-- Save a copy of a text screen for the DF forums. Use 'forumdwarves help' for more details.
-- original author: Caldfir
-- edited by expwnent

@ -1,4 +1,4 @@
--fullheal.lua
--full-heal.lua
--author Kurik Amudnil, Urist DaVinci
--edited by expwnent
@ -12,16 +12,16 @@ for _,arg in ipairs(args) do
elseif tonumber(arg) then
unit = df.unit.find(tonumber(arg))
elseif arg == 'help' or arg == '-help' or arg == '-h' then
print('fullheal: heal a unit completely from anything, optionally including death.')
print(' fullheal [unitId]')
print('full-heal: heal a unit completely from anything, optionally including death.')
print(' full-heal [unitId]')
print(' heal the unit with the given id')
print(' fullheal -r [unitId]')
print(' full-heal -r [unitId]')
print(' heal the unit with the given id and bring them back from death if they are dead')
print(' fullheal')
print(' full-heal')
print(' heal the currently selected unit')
print(' fullheal -r')
print(' full-heal -r')
print(' heal the currently selected unit and bring them back from death if they are dead')
print(' fullheal help')
print(' full-heal help')
print(' print this help message')
return
end

@ -1,4 +1,4 @@
-- hackWish.lua
-- hack-wish.lua
-- Allows for script-based wishing.
-- author Putnam
-- edited by expwnent
@ -249,3 +249,4 @@ else
hackWish(unit)
end
end

@ -4,13 +4,13 @@
local utils = require 'utils'
validArgs = --[[validArgs or]] utils.invert({
validArgs = validArgs or utils.invert({
'help',
'creator',
'material',
'item',
'creature',
'caste',
-- 'creature',
-- 'caste',
'matchingGloves',
'matchingShoes'
})
@ -38,6 +38,10 @@ arguments:
specify the itemdef of the item to be created
examples:
WEAPON:ITEM_WEAPON_PICK
-matchingShoes
create two of this item
-matchingGloves
create two of this item, and set handedness appropriately
]])
return
end

@ -26,6 +26,8 @@ local args = utils.processArgs({...}, validArgs)
if next(args) == nil or args.help then
print([[force usage
arguments:
-help
print this help message
-eventType event
specify the type of the event to trigger
examples:

@ -90,7 +90,7 @@ end
--TODO: delete corpses?
end]]
validArgs = --[[validArgs or]] utils.invert({
validArgs = validArgs or utils.invert({
'clear',
'help',
'allRaces',
@ -113,6 +113,10 @@ end
if args.help then
print([[scripts/modtools/invader-item-destroyer.lua usage
arguments:
-help
print this help message
-clear
reset all registered data
-allEntities [true/false]
set whether it should delete items from invaders from any civ
-allItems [true/false]

@ -1,7 +1,7 @@
--scripts/modtools/attack-trigger.lua
--author expwnent
--based on itemsyndrome by Putnam
--triggers scripts when a unit attacks another with a weapon type, a weapon of a particular material
--triggers scripts when a unit attacks another with a weapon type, a weapon of a particular material, or a weapon contaminated with a particular material, or when a unit equips/unequips a particular item type, an item of a particular material, or an item contaminated with a particular material
local eventful = require 'plugins.eventful'
local utils = require 'utils'

@ -1,223 +0,0 @@
-- itemsyndrome.lua
-- author: Putnam
-- edited by expwnent
-- 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.
eventful=eventful or require("plugins.eventful")
syndromeUtil = syndromeUtil or require("syndromeUtil")
local function printItemSyndromeHelp()
print("Arguments (non case-sensitive):")
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.')
print(' "transformReEquipOn/TransformReEquipOff": toggles transformation auto-reequip.')
end
itemsyndromedebug=false
local args = {...}
for k,v in ipairs(args) do
v=v:lower()
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
if v == "transformreequipon" then transformationReEquip = true end
if v == "transformreequipoff" then transformationReEquip = false end
end
local function getMaterial(item)
--What does this line mean?
local material = dfhack.matinfo.decode(item) and dfhack.matinfo.decode(item) or false
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 syndromeIsDfHackSyndrome(syndrome)
for k,v in ipairs(syndrome.syn_class) do
if v.value=="DFHACK_ITEM_SYNDROME" then
if itemsyndromedebug then print('Syndrome is DFHack syndrome, checking if creature is affected...') end
return true
end
end
if itemsyndromedebug then print('Syndrome is not DFHack syndrome. Cancelling.') end
return false
end
local function itemHasNoSubtype(item)
return item:getSubtype()==-1
end
local function itemHasSyndrome(item)
if itemHasNoSubtype(item) or not itemSyndromeMats then return nil end
local allItemSyndromes={}
for _,material in ipairs(itemSyndromeMats) do
for __,syndrome in ipairs(material.syndrome) do
if syndrome.syn_name == item.subtype.name then table.insert(allItemSyndromes,syndrome) end
end
end
return #allItemSyndromes>0 and allItemSyndromes or false
end
local function getValidPositions(syndrome)
local returnTable={AffectsHauler=false,AffectsStuckins=false,IsArmorOnly=false,IsWieldedOnly=false,OnlyAffectsStuckins=false}
for k,v in ipairs(syndrome.syn_class) do
if v.value:find('DFHACK') then
if v.value=="DFHACK_AFFECTS_HAULER" then returnTable.AffectsHauler=true end
if v.value=="DFHACK_AFFECTS_STUCKIN" then returnTable.AffectsStuckins=true end
if v.value=="DFHACK_STUCKINS_ONLY" then returnTable.OnlyAffectsStuckins=true end
if v.value=="DFHACK_WIELDED_ONLY" then returnTable.IsWieldedOnly=true end
if v.value=="DFHACK_ARMOR_ONLY" then returnTable.IsArmorOnly=true end
end
end
return returnTable
end
local function itemIsInValidPosition(item_inv, syndrome)
local item = getValidPositions(syndrome)
if not item_inv then print("You shouldn't see this error! At all! Putnam f'd up! Tell him off!") return false end
local isInValidPosition=not ((item_inv.mode == 0 and not item.AffectsHauler) or (item_inv.mode == 7 and not item.AffectsStuckins) or (item_inv.mode ~= 2 and item.IsArmorOnly) or (item_inv.mode ~=1 and item.IsWieldedOnly) or (item_inv.mode ~=7 and item.OnlyAffectsStuckins))
if itemsyndromedebug then print(isInValidPosition and 'Item is in correct position.' or 'Item is not in correct position.') end
return isInValidPosition
end
local function syndromeIsTransformation(syndrome)
for _,effect in ipairs(syndrome.ce) do
if df.creature_interaction_effect_body_transformationst:is_instance(effect) 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 syndromeIsOnUnequip(syndrome)
for k,v in ipairs(syndrome.syn_class) do
if v.value:upper()=='DFHACK_ON_UNEQUIP' then return true end
end
return false
end
local function addOrRemoveSyndromeDepending(unit,old_equip,new_equip,syndrome)
local item_inv=new_equip or old_equip
if not syndromeIsDfHackSyndrome(syndrome) then
return
end
local equippedOld = itemIsInValidPosition(old_equip,syndrome)
local equippedNew = itemIsInValidPosition(new_equip,syndrome)
if equippedOld == equippedNew then
return
end
local isOnEquip = not syndromeIsOnUnequip(syndrome)
local apply = (isOnEquip and equippedNew) or (not isOnEquip and not equippedNew)
if apply then
syndromeUtil.infectWithSyndrome(unit,syndrome,syndromeUtil.ResetPolicy.ResetDuration)
else
syndromeUtil.eraseSyndrome(unit,syndrome)
end
end
eventful.enableEvent(eventful.eventType.INVENTORY_CHANGE,5)
eventful.onInventoryChange.itemsyndrome=function(unit_id,item_id,old_equip,new_equip)
local item = df.item.find(item_id)
--if not item then return false end
if not item then
return
end
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
local itemMaterial=getMaterial(item)
local function manageSyndromes(syndromes)
for k,syndrome in ipairs(syndromes) do
if itemsyndromedebug then print("item has a syndrome, checking if syndrome is valid for application...") end
if syndromeIsTransformation(syndrome) then
--unitInventory = rememberInventory(unit)
rememberInventory(unit)
transformation = true
end
addOrRemoveSyndromeDepending(unit,old_equip,new_equip,syndrome)
end
end
if itemMaterial then
manageSyndromes(itemMaterial.syndrome)
end
local itemSyndromes = itemHasSyndrome(item)
if itemSyndromes then
if itemsyndromedebug then print("Item itself has a syndrome, checking if item is in correct position and creature is affected") end
manageSyndromes(itemSyndromes)
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
local contaminantMaterial=getMaterial(contaminant)
if contaminantMaterial then
manageSyndromes(contaminantMaterial.syndrome)
end
end
end
if transformation and transformationReEquip then dfhack.timeout(2,"ticks",function() moveAllToInventory(unit,unitInventory) end) end
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

@ -1,153 +0,0 @@
-- moddableGods.lua
-- Sets player-defined gods to correct civilizations.
-- author: Putnam
-- edited by expwnent
--[[Here's an example of how to make a god:
[CREATURE:SHEOGORATH]
[DOES_NOT_EXIST]
[MALE]
[NAME:jovial man:Daedra:madness] "Sheogorath, madness god." "Often depicted as a jovial man"
[CASTE_NAME:Sheogorath:Sheogorath:Sheogorath]
[DESCRIPTION:The Daedric Prince of madness.]
[CREATURE_CLASS:DFHACK_GOD]
[SPHERE:MUSIC]
[SPHERE:ART]
[SPHERE:CHAOS]
]]
local function getCreatureClasses(creatureRaw)
local creatureClasses = {}
for _,caste in ipairs(creatureRaw.caste) do
for k,class in ipairs(caste.creature_class) do
table.insert(creatureClasses,class.value)
end
end
return creatureClasses
end
local function deityIsOfSpecialCreature(creatureRaw)
for k,class in ipairs(getCreatureClasses(creatureRaw)) do
if class=="DFHACK_GOD" then return true end
end
return false
end
local function scriptAlreadyRunOnThisWorld()
local figures = df.global.world.history.figures
for i=#figures-1,0,-1 do --goes through the table backwards because the particular hist figs involved are probably going to be the last
local figure = figures[i]
if not df.isnull(figure.flags) and figure.flags.deity and deityIsOfSpecialCreature(df.global.world.raws.creatures.all[figure.race]) then
return true
end
end
return false
end
local function findAGod()
for k,fig in ipairs(df.global.world.history.figures) do
if fig.flags.deity then
return fig
end
end
return nil
end
local function putListOfAllSpecialCreatureGodsTogether()
local specialCreatures = {}
for k,creatureRaw in ipairs(df.global.world.raws.creatures.all) do
if deityIsOfSpecialCreature(creatureRaw) then
table.insert(specialCreatures,{creatureRaw,k})
end
end
return specialCreatures
end
local function stringStarts(String,Start)
return string.sub(String,1,string.len(Start))==Start
end
local function getRacesOfGod(god)
local civList={}
for k,class in ipairs(getCreatureClasses(god)) do
if stringStarts(class,"WORSHIP_ENTITY_") then
table.insert(civList,string.sub(class,15))
end
end
return civList
end
local function entityIsInGodsDomain(entity,entityRacesTable)
for k,v in ipairs(entityRacesTable) do
if v==entity.entity_raw.code then
return true
end
end
return false
end
local function setUpTemplate(godFig,templateGod)
godFig.appeared_year=-1
godFig.born_year=-1
godFig.born_seconds=-1
godFig.curse_year=-1
godFig.curse_seconds=-1
godFig.old_year=-1
godFig.old_seconds=-1
godFig.died_year=-1
godFig.died_seconds=-1
godFig.name.has_name=true
godFig.breed_id=-1
godFig.flags:assign(templateGod.flags)
godFig.id = df.global.hist_figure_next_id
godFig.info = df.historical_figure_info:new()
godFig.info.spheres={new=true}
godFig.info.secret=df.historical_figure_info.T_secret:new()
end
local function setUpGod(god,godID,templateGod)
local godFig = df.historical_figure:new()
setUpTemplate(godFig,templateGod)
godFig.sex=god.caste[0].gender
godFig.race=godID
godFig.name.first_name=god.caste[0].caste_name[2] --the adjectival form of the caste_name is used for the god's name, E.G, [CASTE_NAME:god:god:armok]
for k,v in ipairs(god.sphere) do --assigning spheres
godFig.info.spheres:insert('#',v)
end
df.global.world.history.figures:insert('#',godFig)
df.global.hist_figure_next_id=df.global.hist_figure_next_id+1
return godFig
end
--[[this function isn't really working right now so it's dummied out
function setGodAsOfficialDeityOfItsParticularEntity(god,godFig)
local entityRaces=getRacesOfGod(god)
for k,entity in ipairs(df.global.world.entities.all) do
if entityIsInGodsDomain(entity,entityRaces) then
entity.unknown1b.worship:insert('#',godFig.id)
end
end
end
]]
local function moddableGods()
if scriptAlreadyRunOnThisWorld() then
print("Already run on world...")
return false
end
local gods = putListOfAllSpecialCreatureGodsTogether()
local templateGod=findAGod()
for k,v in ipairs(gods) do --creature raws first
local god = v[1]
local godID = v[2]
local godFig = setUpGod(god,godID,templateGod)
--setGodAsOfficialDeityOfItsParticularEntity(god,godFig)
end
end
dfhack.onStateChange.letThereBeModdableGods = function(state)
if state == SC_WORLD_LOADED and df.global.gamemode~=3 then --make sure that the gods show up only after the rest of the histfigs do
moddableGods()
end
end

@ -1,6 +1,7 @@
--scripts/modtools/projectile-trigger.lua
--author expwnent
--based on Putnam's projectileExpansion
--TODO: trigger based on contaminants
local eventful = require 'plugins.eventful'
local utils = require 'utils'

@ -1,190 +0,0 @@
-- projectileExpansion.lua
-- author: Putnam
-- edited by expwnent
-- Adds extra functionality to projectiles. Use the argument "disable" (minus quotes) to disable.
local syndromeUtil = require("syndromeUtil")
local events=require "plugins.eventful"
local flowtypes = {
miasma = 0,
mist = 1,
mist2 = 2,
dust = 3,
lavaMist = 4,
smoke = 5,
dragonFire = 6,
fireBreath = 7,
web = 8,
undirectedGas = 9,
undirectedVapor = 10,
oceanWave = 11,
seaFoam = 12
}
local function posIsEqual(pos1,pos2)
if pos1.x ~= pos2.x or pos1.y ~= pos2.y or pos1.z ~= pos2.z then return false end
return true
end
local function getMaterial(item)
if not dfhack.matinfo.decode(item) then return nil end
local matinfo = dfhack.matinfo.decode(item)
return matinfo and matinfo.material
-- return dfhack.matinfo.decode(item).material
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 removeItem(item)
item.flags.garbage_collect = true
end
local function findInorganicWithName(matString)
for inorganicID,material in ipairs(df.global.world.raws.inorganics) do
if material.id == matString then return inorganicID end
end
return nil
end
local function getScriptFromMaterial(material)
local commandStart
local commandEnd
local reactionClasses = material.reaction_class
for classNumber,reactionClass in ipairs(reactionClasses) do
if reactionClass.value == "\\COMMAND" then commandStart = classNumber end
if reactionClass.value == "\\ENDCOMMAND" then commandEnd = classNumber break end
end
local script = {}
if commandStart and commandEnd then
for i = commandStart+1, commandEnd-1, 1 do
table.insert(script,reactionClasses[i].value)
end
end
return script
end
local function getUnitHitByProjectile(projectile)
for uid,unit in ipairs(df.global.world.units.active) do
if posIsEqual(unit.pos,projectile.cur_pos) then return uid,unit end
end
return nil
end
local function matCausesSyndrome(material)
for _,reactionClass in ipairs(material.reaction_class) do
if reactionClass.value == "DFHACK_CAUSES_SYNDROME" then return true end --the syndrome is the syndrome local to the projectile material
end
return false
end
projectileExpansionFlags = projectilExpansionFlags or {
matWantsSpecificInorganic = 0,
matWantsSpecificSize = 50000,
matCausesDragonFire = false,
matCausesMiasma = false,
matCausesMist = false,
matCausesMist2 = false,
matCausesDust = false,
matCausesLavaMist = false,
matCausesSmoke = false,
matCausesFireBreath = false,
matCausesWeb = false,
matCausesUndirectedGas = false,
matCausesUndirectedVapor = false,
matCausesOceanWave = false,
matCausesSeaFoam = false,
matHasScriptAttached = false,
matCausesSyndrome = false,
returnLocation = false,
matDisappearsOnHit = false
}
local function getProjectileExpansionFlags(material)
local matName = nil
for k,reactionClass in ipairs(material.reaction_class) do
if debugProjExp then print("checking reaction class #" .. k .. "...",reactionClass.value) end
if string.find(reactionClass.value,"DFHACK") then
if debugProjExp then print("DFHack reaction class found!") end
if reactionClass.value == "DFHACK_SPECIFIC_MAT" then matName = material.reaction_class[k+1].value end
if reactionClass.value == "DFHACK_FLOW_SIZE" then projectileExpansionFlags.matWantsSpecificSize = tonumber(material.reaction_class[k+1].value) end
if reactionClass.value == "DFHACK_CAUSES_SYNDROME" then projectileExpansionFlags.matCausesSyndrome = true end
if reactionClass.value == "DFHACK_DRAGONFIRE" then projectileExpansionFlags.matCausesDragonFire = true end
if reactionClass.value == "DFHACK_MIASMA" then projectileExpansionFlags.matCausesMiasma = true end
if reactionClass.value == "DFHACK_MIST" then projectileExpansionFlags.matCausesMist = true end
if reactionClass.value == "DFHACK_MIST2" then projectileExpansionFlags.matCausesMist2 = true end
if reactionClass.value == "DFHACK_DUST" then projectileExpansionFlags.matCausesDust = true end
if reactionClass.value == "DFHACK_LAVAMIST" then projectileExpansionFlags.matCausesLavaMist = true end
if reactionClass.value == "DFHACK_SMOKE" then projectileExpansionFlags.matCausesSmoke = true end
if reactionClass.value == "DFHACK_FIREBREATH" then projectileExpansionFlags.matCausesFireBreath = true end
if reactionClass.value == "DFHACK_WEB" then projectileExpansionFlags.matCausesWeb = true end
if reactionClass.value == "DFHACK_GAS_UNDIRECTED" then projectileExpansionFlags.matCausesUndirectedGas = true end
if reactionClass.value == "DFHACK_VAPOR_UNDIRECTED" then projectileExpansionFlags.matCausesUndirectedVapor = true end
if reactionClass.value == "DFHACK_OCEAN_WAVE" then projectileExpansionFlags.matCausesOceanWave = true end
if reactionClass.value == "DFHACK_SEA_FOAM" then projectileExpansionFlags.matCausesSeaFoam = true end
if reactionClass.value == "DFHACK_DISAPPEARS" then projectileExpansionFlags.matDisappearsOnHit = true end
end
if reactionClass.value == "\\COMMAND" then projectileExpansionFlags.matHasScriptAttached = true end
end
if matName then projectileExpansionFlags.matWantsSpecificInorganic = findInorganicWithName(matName) end
return projectileExpansionFlags
end
debugProjExp=false
events.onProjItemCheckImpact.expansion=function(projectile)
if debugProjExp then print("Thwack! Projectile item hit. Running projectileExpansion.") end
if projectile then
if debugProjExp then print("Found the item. Working on it.") end
local material = getMaterial(projectile.item)
if not material then return nil end
local projectileExpansionFlags=getProjectileExpansionFlags(material)
if debugProjExp then print(projectileExpansionFlags) printall(projectileExpansionFlags) end
local syndrome = getSyndrome(material)
local emissionMat = projectileExpansionFlags.matWantsSpecificInorganic --defaults to iron
local flowSize = projectileExpansionFlags.matWantsSpecificSize --defaults to 50000
if projectileExpansionFlags.matCausesDragonFire then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.dragonFire,0,0,flowSize) end
if projectileExpansionFlags.matCausesMiasma then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.miasma,0,0,flowSize) end
if projectileExpansionFlags.matCausesMist then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.mist,0,0,flowSize) end
if projectileExpansionFlags.matCausesMist2 then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.mist2,0,0,flowSize) end
if projectileExpansionFlags.matCausesDust then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.dust,0,emissionMat,flowSize) end
if projectileExpansionFlags.matCausesLavaMist then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.lavaMist,0,emissionMat,flowSize) end
if projectileExpansionFlags.matCausesSmoke then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.smoke,0,0,flowSize) end
if projectileExpansionFlags.matCausesFireBreath then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.fireBreath,0,0,flowSize) end
if projectileExpansionFlags.matCausesWeb then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.web,0,emissionMat,flowSize) end
if projectileExpansionFlags.matCausesUndirectedGas then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.undirectedGas,0,emissionMat,flowSize) end
if projectileExpansionFlags.matCausesUndirectedVapor then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.undirectedVapor,0,emissionMat,flowSize) end
if projectileExpansionFlags.matCausesOceanWave then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.oceanWave,0,0,flowSize) end
if projectileExpansionFlags.matCausesSeaFoam then dfhack.maps.spawnFlow(projectile.cur_pos,flowtypes.seaFoam,0,0,flowSize) end
if projectileExpansionFlags.matHasScriptAttached or projectileExpansionFlags.matCausesSyndrome then
local uid,unit = getUnitHitByProjectile(projectile)
if projectileExpansionFlags.matHasScriptAttached then
local script = getScriptFromMaterial(material)
for k,v in ipairs(script) do
if script[k] == "\\UNIT_HIT_ID" then script[k] = unit.id end
if script[k] == "\\LOCATION" then
script[k] = projectile.cur_pos.x
table.insert(script,projectile.cur_pos.y,k+1)
table.insert(script,projectile.cur_pos.z,k+2)
end
end
dfhack.run_script(table.unpack(script))
end
if projectileExpansionFlags.matCausesSyndrome then syndromeUtil.infectWithSyndrome(unit,syndrome.id) end
end
--if projectileExpansionFlags.matDisappearsOnHit then dfhack.items.remove(projectile) end
end
return true
end
if ... ~= "disable" then
print("Enabled projectileExpansion.")
else
events.onProjItemCheckImpact.expansion = nil
print("Disabled projectileExpansion.")
end

@ -1,4 +1,4 @@
-- reaction-trigger-transition.lua
-- scripts/modtools/reaction-trigger-transition.lua
-- author expwnent
-- prints useful things to the console and a file to help modders transition from autoSyndrome to reaction-trigger
-- this script is basically an apology for breaking backward compatibiility

@ -148,7 +148,7 @@ eventful.onJobCompleted.reactionTrigger = function(job)
end
eventful.enableEvent(eventful.eventType.JOB_COMPLETED,0) --0 is necessary to catch cancelled jobs and not trigger them
validArgs = utils.invert({
validArgs = validArgs or utils.invert({
'help',
'clear',
'reactionName',

@ -1,97 +0,0 @@
-- shapechange.lua
-- transforms unit (by number) into another creature, choice given to user. Syntax is: unitID tickamount maxsize namefilter. A size of 0 is ignored. A length of 0 is also ignored. If no filter, all units will be sorted. A filter of ALL will also work with all units.
-- author Putnam
-- edited by expwnent
--shapechange gui [unitId] [duration] [maxsize] [namefilter]
--shapechange manual [unitId] [creature name] [caste name] [duration]
local dialog = require('gui.dialogs')
local script = require('gui.script')
function transform(target,race,caste,length)
if target==nil then
qerror("Not a valid target")
end
local defaultRace = target.enemy.normal_race
local defaultCaste = target.enemy.normal_caste
target.enemy.normal_race = race --that's it???
target.enemy.normal_caste = caste; --that's it!
if length and length>0 then dfhack.timeout(length,'ticks',function() target.enemy.normal_race = defaultRace target.enemy.normal_caste = defaultCaste end) end
end
function getBodySize(caste)
return caste.body_size_1[#caste.body_size_1-1]
end
function selectCreature(unitID,length,size,filter) --taken straight from here, but edited so I can understand it better: https://gist.github.com/warmist/4061959/... again. Also edited for syndromeTrigger, but in a completely different way.
size = size or 0
filter = filter or "all"
length = length or 2400
local creatures=df.global.world.raws.creatures.all
local tbl={}
local tunit=df.unit.find(unitID)
for cr_k,creature in ipairs(creatures) do
for ca_k,caste in ipairs(creature.caste) do
local name=caste.caste_name[0]
if name=="" then name="?" end
if (not filter or string.find(name,filter) or string.lower(filter)=="all") and (not size or size>getBodySize(caste) or size<1 and not creature.flags.DOES_NOT_EXIST) then table.insert(tbl,{name,nil,cr_k,ca_k}) end
end
end
table.sort(tbl,function(a,b) return a[1]<b[1] end)
local f=function(name,C)
transform(tunit,C[3],C[4],length)
end
script.start(function()
local ok =
script.showYesNoPrompt(
"Just checking","Do you want "
.. dfhack.TranslateName(dfhack.units.getVisibleName(tunit))
.. " to transform into a creature of size below "..NEWLINE
.. (not not size and size>1 and size or "infinity")
.. " ("
.. size/(getBodySize(df.creature_raw.find(tunit.race).caste[tunit.caste]))*100
.. "% of current size) for "
..length
.." ticks ("
..length/1200
.." days, ~"
..length/df.global.enabler.fps
.." seconds)?",
COLOR_LIGHTRED
)
if ok then dialog.showListPrompt("Creature Selection","Choose creature:",COLOR_WHITE,tbl,f) end
end)
end
local args = {...}
--unit id, length, size, filter
if args[1] == 'gui' then
selectCreature(tonumber(args[2]),tonumber(args[3]),tonumber(args[4]),args[5])
else
local race-- = df.creature_raw.find(args[3])
local raceIndex
for index,raceCandidate in ipairs(df.global.world.raws.creatures.all) do
if raceCandidate.creature_id == args[3] then
raceIndex = index
race = raceCandidate
break
end
end
local caste
local casteIndex
if race then
for index,casteCandidate in ipairs(race.caste) do
if casteCandidate.caste_id == args[4] then
caste = casteCandidate
casteIndex = index
break
end
end
end
if not race or not caste then
print("shapechange error: couldn't find " .. args[3] .. " " .. args[4])
return
end
transform(df.unit.find(tonumber(args[2])), raceIndex, casteIndex, args[5] and tonumber(args[5]))
end

@ -1,6 +1,8 @@
--scripts/modtools/skill-change.lua
--author expwnent
--based on skillChange.lua by Putnam
--TODO: update skill level once experience increases/decreases
--TODO: skill rust?
local utils = require 'utils'

@ -1,59 +0,0 @@
-- skillroll.lua
-- Allows skills to activate lua scripts.
-- author Putnam
-- edited by expwnent
--[[Example usage:
...syndrome stuff...
[SYN_CLASS:\COMMAND][SYN_CLASS:modtools/skillroll][SYN_CLASS:\WORKER_ID] For autoSyndrome/syndromeTrigger.
[SYN_CLASS:MELEE_COMBAT] Can use any skill, including NONE (no bonus)
[SYN_CLASS:20] Rolls uniformly from 1 to 20 inclusive. Skill will be weighted to this value.
[SYN_CLASS:DICEROLL_1] If diceroll ends up as one...
[SYN_CLASS:kill][SYN_CLASS:\SKILL_UNIT_ID] Theoretical kill-given-unit-id command; slayrace doesn't do so.
[SYN_CLASS:DICEROLL_10] If diceroll is between 1 and 10 (2-10, inclusive)...
[SYN_CLASS:modtools/force][SYN_CLASS:migrants][SYN_CLASS:player] Force migrants.
[SYN_CLASS:DICEROLL_19] If diceroll is between 10 and 19 (11-19, inclusive)...
[SYN_CLASS:fullheal][SYN_CLASS:\SKILL_UNIT_ID] Fully heals unit.
[SYN_CLASS:DICEROLL_20] If diceroll is at least 20...
[SYN_CLASS:modtools/shapechange][SYN_CLASS:\SKILL_UNIT_ID] Turns unit into any creature permanently.
or from the console
modtools/skillroll workerId MELEE_COMBAT 20 DICEROLL_1 kill workerId DICEROLL_10 modtools/force migrants player DICEROLL_19 fullheal workerId DICEROLL_20 modtools/shapechange workerId
]]
local args={...}
if args[1]=='dryrun' then
unit=df.global.world.units.all[0]
end
local unit = unit or df.unit.find(args[1])
rando=rando or dfhack.random.new()
local roll=rando:random(tonumber(args[3]))
if args[2] ~= 'NONE' then
local result=roll+(dfhack.units.getEffectiveSkill(unit,df.job_skill[args[2]])*(tonumber(args[3])/20))
result = result%1<.5 and math.floor(result) or math.ceil(result)
roll = result
end
local i=4
local command={}
local scriptIsFinished
repeat
local arg=args[i]
if arg:find('DICEROLL') then
local dicerollnumber=tonumber(arg:match('%d+')) --yes this is truly naive as hell; I imagine if you put DICEROLL3%moa5oam3 it'll return 353.
if dicerollnumber>=roll then
repeat
i=i+1
if i<=#args and (not args[i]:find('DICEROLL')) then
if args[i]~='\\SKILL_UNIT_ID' then table.insert(command,args[i]) else table.insert(command,args[1]) end
end
until i>#args or args[i]:find('DICEROLL')
dfhack.run_command(table.unpack(command))
scriptIsFinished=true
else
i=i+1
end
else
i=i+1
end
until i>#args or scriptIsFinished

@ -4,7 +4,7 @@
local utils = require 'utils'
validArgs = --[[validArgs or]] utils.invert({
validArgs = validArgs or utils.invert({
'help',
'material',
'flowType',

@ -1,3 +1,4 @@
-- scripts/remove-wear.lua
-- Resets all items in your fort to 0 wear
-- original author: Laggy
-- edited by expwnent
@ -5,13 +6,13 @@
local args = {...}
if args[1] == 'help' then
print([[removewear - this script removes wear from all items, or from individual ones
print([[remove-wear - this script removes wear from all items, or from individual ones
removewear all
remove-wear all
remove wear from all items
removewear n1 n2 n3 ...
remove-wear n1 n2 n3 ...
remove wear from items with the given ids. order does not matter
repeat -time 2 months -command removewear all
repeat -time 2 months -command remove-wear all
remove wear from all items every 2 months. see repeat.lua for details
]])
do return end
@ -23,7 +24,7 @@ elseif args[1] == 'all' then
count = count+1
end
end
print('removewear removed wear from '..count..' objects')
print('remove-wear removed wear from '..count..' objects')
else
local argIndex = 1
local isCompleted = {}