Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --projectile-mod--
- --creates smoke and modifies various properties of any projectile based on ammo and weapon properties
- --author Grimlocke
- --based on scripts by zaporozhets
- --who on turn based his work on scripts by expwnent and Putnam
- local usage = [====[
- modtools/projectile-mod
- ===========================
- Creates smoke and modifies various properties of any projectile, based on ammunition, weapon or material.
- -clear
- unregister all entries
- -list
- list current ammo/weapons/material entries and their values
- -ammoType, -weaponType or -materialType
- register projectile, weapon or material with subtype (eg ITEM_AMMO_BOLTS) or full material token (INORGANIC:IRON or CREATURE_MAT:DWARF:LIVER). Applies to ANY projectile subtype or material, and anything used as a ranged weapon (including non-weapon item set as bow_id).
- if ammo, weapons or materials have the same value defined, they will either be added, multiplied or overwritten with the following precedence: ammo > weapon > material
- valid arguments:
- -deviation - max number of tiles at 50 tiles distance. Additive, decreases with weapon/ammo item quality if qualityScale is > 0.
- -range - minimum range, maximum range. projectile will not hit targets until minimum range is reached, and drop from the air triggering any impact effects at max range. defined as [ min max ] or just max (no brackets) to keep default minrange behaviour.
- -falloff - projectile velocity is multiplied by this every 4 tiles of distance flown. 1 is constant speed (default behavior), below 1 has speed drop over distance, above 1 accelerates the projectile.
- gravitates towards 1 depending on ammo item quality and qualityscale. Falloff stops happening at qualityScale 2 and masterwork quality. Strange things start happening beyond that number.
- -hitrateAdd - 0(default) to 100, adds or substracts hitrate. increases with firer skill. Stacks additively, increases with weapon/ammo item quality if qualityScale is > 0.
- -velocity - multiplies the projectile velocity, can exceed weapons max velocity. Stacks multiplicatively, increases with weapon/ammo item quality if qualityScale is > 0.
- -qualityScale - multiplier, scales accuracy, hitrate and velocity with item quality. 0 for no scaling, 1 for default scaling. Accepts fractions and values higher than 1. Additive, does nothing on materials.
- -breakChance - 0 to 1(default), chance for the projectile to break. Multiplicative.
- -piercing - true/false, sets true if no argument. whether or not a projectile will pass through targets to hit another. causes projectiles to hit one target multiple times, may be a bug. Overrides by precedence.
- -deleteMe - true/false, sets true if no argument. if set with no argument, deletes projectile on impact. if set with a number, deletes it at that range without triggering impact effects. Overrides by precedence.
- -setType - TYPE:SUBTYPE, transform projectile(s) into this item. Changing item type not currently supported. Overrides by precedence.
- -setMat - change the projectile's material. Overrides by precedence.
- -shotCount - spawn extra projectiles if > 1, no theoretical limit the number. Multiplicative, rounds downwards.
- -shotRof - if set, each extra shot is fired with this many ticks delay. if not set, all shots fire at once. Overrides by precedence.
- -rofMult - multiplies baseRof and altRof, multiply rate of fire. Multiplicative.
- -weaponType only values
- -baseRof - delay in ticks between shots and firer skill scaling defaults are 80 and 1, skill scaling can be a fraction and more than 1.
- -altRof - delay in ticks, interval and firer skill scaling. each shot in the number for interval will take this long instead. defaults for interval skill scaling are 2 and 1 respectively.
- -windupRof - multiplier, shot-until-woundup, ticks per winddown. multiplies fire delay. delay gravitates towards 1 each shot until the second value is reached, and steps back by 1 shot each delay.
- -trailFlow or -impactFlow
- add flow effects to projectiles during flight or at impact. arguments is [ ammo/weapon/material subtype/materialtoken ] or just subtype, which will default to ammo trigger.
- multiple of each can be added with seperate commands, define flows AFTER the above properties, as they will override the entry for the same ammo/weapon/material.
- valid arguments:
- -minmaxint - minimum range, maximum range and interval. flow triggers within range, at the specified interval of tiles flown.
- minimum and interval default to 1, so a range of 1-20 can be set as [ 1 20 1 ], [ 1 20 ], or just 20.
- -flowType TODO
- -flowMat - set flow material if the flow type permits it.
- -volume - pretty self-explanatory.
- -conical - multiply volume by distance flown and this multiplier.
- -expand - if set, the flow will expand drift out to more than 1 tile.
- -direction - works on fire and dragonfire (type 6 and 7) only, sets direction for the flow to the direction of the projectile.
- examples:
- make arrows less accurate, have a 50% break chance and lose 6% speed each 4 tiles. also fires 20% faster.
- -ammoType ITEM_AMMO_ARROWS -deviation 2 -breakChance 0.5 -falloff 0.94 -rofMult 1.2
- a slower, more accurate crossbow. firer skill only increase fire rate by half as much as normal. make steel hit harder and more durable.
- -weaponType ITEM_WEAPON_CROSSBOW_ARBALEST \-deviation -1 -hitrateAdd 6 -velocity 1.2 -baseRof [ 145 0.5 ] -breakChance 1.33
- -materialType INORGANIC:STEEL -breakChance 0.64 -velocity 1.2 -deviation \-1
- make shot of 8 pellets that are deleted after impact and produce smoke for 3 tiles that expands and increases in volume over distance
- -ammoType ITEM_AMMO_GUN_20MM_SHOT -deviation 5 -hitrateAdd 5 -velocity 0.6 -deleteMe -subtype AMMO:ITEM_AMMO_GUN_SHOT -shotCount 8
- -trailFlow ITEM_AMMO_GUN_20MM_SHOT -minmaxint 3 -flowType 5 -volume 6 -expand -conical 1
- a rocket that starts slow but flies faster and faster, hits a single target multiple times (faking explosive effect), turns into a different mat, produces smoke each 2 tiles and a dragonfire explosion. quality only matters half as much in deviation/velocity/hirate as normal. it explodes after traveling 20 tiles.
- -ammoType ITEM_AMMO_ROCKET -velocity 0.5 -falloff 1.2 -piercing 1 -deleteMe -range 20 -setMat INORGANIC:EXPLOSIVE_MAT -qualityScale 0.5
- -trailFlow [ ammo ITEM_AMMO_ROCKET ] -minmaxint [ 0 20 2 ] -flowType 5 -volume 20 -expand
- -impactFlow [ ammo ITEM_AMMO_ROCKET ] -flowType 6 -volume 30 -expand
- make a minigun, because why not. each shot produces 3 projectiles at a 5 tick delay, has a 5 tick delay itself and every shot in 20 (so 60 projectiles) has a 500 tick delay. Only the last delay is decreased with firer skill. delays are multiplied by 6, multiplier decreases to 1 at the 8th shot, and winds back down by 1 each 40 ticks. add a material for incendiery ammo for good measure.
- -weaponType ITEM_WEAPON_MINIGUN -deviation 5 -hitrateAdd 10 -qualityScale 1.4 -baseRof [ 5 0 ] -altRof [ 500 20 ] -windupRof [ 6 8 40 ]
- -ammoType ITEM_AMMO_MINIGUN_AMMO -deleteMe -falloff 0.85 -shotCount 3 -shotRof [ 5 0 ]
- -materialType INORGANIC:AP-I -velocity 0.67 -piercing
- -impactFlow material INORGANIC:AP-I -flowType 6 -volume 10
- ]====]
- local eventful = require 'plugins.eventful'
- local utils = require 'utils'
- ammoProperties = ammoProperties or {}
- weaponProperties = weaponProperties or {}
- materialProperties = materialProperties or {}
- persistTable = persistTable or {}
- noInit = noInit or false
- local validArgs = utils.invert({
- 'help',
- 'clear',
- 'list',
- 'weaponType',
- 'ammoType',
- 'materialType',
- 'deviation',
- 'hitrateAdd',
- 'qualityScale',
- 'breakChance',
- 'velocity',
- 'falloff',
- 'range',
- 'piercing',
- 'deleteMe',
- 'setItem',
- 'setMat',
- 'shotCount',
- 'shotRof',
- 'rofMult',
- 'baseRof',
- 'altRof',
- 'windupRof',
- 'trailFlow',
- 'impactFlow',
- 'minmaxint',
- 'flowType',
- 'flowMat',
- 'volume',
- 'conical',
- 'expand',
- 'direction'
- })
- local args = utils.processArgs({...}, validArgs)
- if args.ammoType or args.weaponType or args.materialType then
- local things = { {args.ammoType, ammoProperties}, {args.weaponType, weaponProperties}, {args.materialType, materialProperties} }
- for _,propsStr in pairs(things) do
- if propsStr[1] then
- propsStr[2][propsStr[1]] = { deviation = tonumber(args.deviation),
- hitrate = tonumber(args.hitrateAdd),
- breakChance = tonumber(args.breakChance),
- velocity = tonumber(args.velocity),
- falloff = tonumber(args.falloff),
- qualityScale = tonumber(args.qualityScale),
- shotCount = tonumber(args.shotCount),
- rofMult = tonumber(args.rofMult)
- }
- if args.range then propsStr[2][propsStr[1]].range = { tonumber(args.range[1]) or 0, tonumber(args.range[2]) or tonumber(args.range) } end
- if args.setItem then propsStr[2][propsStr[1]].setItem = { dfhack.items.findType(args.setItem), dfhack.items.findSubtype(args.setItem) } end
- if args.setMat then propsStr[2][propsStr[1]].setMat = { dfhack.matinfo.find(args.setMat)['type'], dfhack.matinfo.find(args.setMat).index } end
- if args.piercing then propsStr[2][propsStr[1]].piercing = true end
- if args.shotRof then propsStr[2][propsStr[1]].shotRof = { tonumber(args.shotRof[1]) or tonumber(args.shotRof), tonumber(args.shotRof[2]) or 1 } end
- if args.piercing then propsStr[2][propsStr[1]].piercing = true end
- if args.deleteMe then propsStr[2][propsStr[1]].deleteMe = tonumber(args.deleteMe)
- if not propsStr[2][propsStr[1]].deleteMe then propsStr[2][propsStr[1]].deleteMe = -1 end
- end
- if args.weaponType then
- if args.baseRof then propsStr[2][propsStr[1]].baseRof = { tonumber(args.baseRof[1]) or tonumber(args.baseRof), tonumber(args.baseRof[2]) or 1 } end
- if args.altRof then propsStr[2][propsStr[1]].altRof = { tonumber(args.altRof[1]) or tonumber(args.altRof), tonumber(args.altRof[2]) or 2, tonumber(args.altRof[3]) or 1 } end
- if args.windupRof then propsStr[2][propsStr[1]].windupRof = { tonumber(args.windupRof[1]) or tonumber(args.windupRof), tonumber(args.windupRof[2]) or 10, tonumber(args.windupRof[3]) or 40 } end
- end
- if noInit then return end
- end
- end
- end
- if args.trailFlow or args.impactFlow then
- local propsStr = {}
- if args.trailFlow then
- propsStr = {args.trailFlow[1] or 'ammo', args.trailFlow[2] or args.trailFlow, 'trailFlows'}
- else
- propsStr = {args.impactFlow[1] or 'ammo', args.impactFlow[2] or args.impactFlow, 'impactFlows'}
- end
- if propsStr[1] == 'ammo' then propsStr[1] = ammoProperties end
- if propsStr[1] == 'weapon' then propsStr[1] = weaponProperties end
- if propsStr[1] == 'material' then propsStr[1] = materialProperties end
- propsStr[1][propsStr[2]] = propsStr[1][propsStr[2]] or {}
- propsStr[1][propsStr[2]][propsStr[3]] = propsStr[1][propsStr[2]][propsStr[3]] or {}
- local path = propsStr[1][propsStr[2]][propsStr[3]]
- path[#path + 1] = {flowType = tonumber(args.flowType),
- volume = tonumber(args.volume),
- conical = tonumber(args.conical) or 0,
- flowQuality = tonumber(args.flowQuality) or 1,
- expand = args.expand,
- direction = args.direction,
- }
- if args.trailFlow then
- if not args.minmaxint then
- path[#path].minmaxint = { 0, 666, 1 }
- else
- path[#path].minmaxint = { tonumber(args.minmaxint[1]) or 0, tonumber(args.minmaxint[2]) or tonumber(args.minmaxint) or 666, tonumber(args.minmaxint[3]) or 1 }
- end
- end
- if args.flowMat then
- path[#path].flowMat = { dfhack.matinfo.find(args.flowMat)['type'], dfhack.matinfo.find(args.flowMat).index }
- else
- path[#path].flowMat = { -1, -1 }
- end
- if noInit then return end
- end
- if args.clear then
- ammoProperties = {}
- weaponProperties = {}
- materialProperties = {}
- persistTable = {}
- noInit = false
- return
- end
- if args.list then
- local allthethings = { Ammo = ammoProperties, Weapon = weaponProperties, Material = materialProperties }
- for rer,ere in pairs(allthethings) do
- print("- "..rer.." Entries:")
- for rer,ere in pairs(ere) do
- print(" "..rer..":")
- for rer,ere in pairs(ere) do
- print(" "..rer,ere)
- end
- print()
- end
- print()
- end
- return
- end
- if args.help then
- print(usage)
- return
- end
- eventful.enableEvent(eventful.eventType.UNLOAD, 1)
- eventful.onUnload.blam = function()
- ammoProperties = {}
- weaponProperties = {}
- materialProperties = {}
- persistTable = {}
- noInit = false
- end
- eventful.onProjItemCheckMovement.blam = function(projectile)
- if projectile.distance_flown == 0 then
- if not projectile.firer or persistTable[projectile.bow_id] and persistTable[projectile.bow_id][projectile.item.id] then
- return --from whence thou came!
- elseif projectile.item:getSubtype() == -1 and
- not materialProperties[dfhack.matinfo.decode(projectile.item):getToken()] and
- not weaponProperties[df.item.find(projectile.bow_id).subtype.id] then
- return
- elseif not ammoProperties[projectile.item.subtype.id] and
- not materialProperties[dfhack.matinfo.decode(projectile.item):getToken()] and
- not weaponProperties[df.item.find(projectile.bow_id).subtype.id] then
- return
- else
- local props = {}
- local mode = 1
- persistTable[projectile.bow_id] = persistTable[projectile.bow_id] or {}
- props = initProps(projectile, props)
- persistTable[projectile.bow_id][projectile.item.id] = props
- for rer,func in ipairs(persistTable[projectile.bow_id][projectile.item.id].funcTable[mode]) do
- func(projectile, persistTable[projectile.bow_id][projectile.item.id], mode)
- end
- end
- elseif persistTable[projectile.bow_id] and persistTable[projectile.bow_id][projectile.item.id] then
- local mode = 2
- if projectile.distance_flown >= projectile.fall_threshold then mode = 3 end
- for rer,func in ipairs(persistTable[projectile.bow_id][projectile.item.id].funcTable[mode]) do
- func(projectile, persistTable[projectile.bow_id][projectile.item.id], mode)
- end
- end
- end
- eventful.onProjItemCheckImpact.blam = function(projectile)
- if not persistTable[projectile.bow_id] or not persistTable[projectile.bow_id][projectile.item.id] then
- return
- else
- local mode = 3
- for rer,func in ipairs(persistTable[projectile.bow_id][projectile.item.id].funcTable[mode]) do
- func(projectile, persistTable[projectile.bow_id][projectile.item.id], mode)
- end
- end
- end
- function initProps(projectile, props)
- --need some fields defined for things not to throw their cookies over finding a nil value
- props = { deviation = 0, hitrate = 0, velocity = 1, shotCount = 1, rofMult = 1, bowId = projectile.bow_id, firerId = projectile.firer.id }
- props.funcTable = { {fireMod}, {}, {} }
- props.originPos = xyz2pos(projectile.origin_pos.x, projectile.origin_pos.y, projectile.origin_pos.z)
- props.targetPos = xyz2pos(projectile.target_pos.x, projectile.target_pos.y, projectile.target_pos.z)
- if projectile.item.quality then props.quality = projectile.item.quality end
- local propertyTables = { {}, {}, {} }
- propertyTables[1] = materialProperties[dfhack.matinfo.decode(projectile.item):getToken()] or {}
- propertyTables[2] = weaponProperties[df.item.find(projectile.bow_id).subtype.id] or {}
- if projectile.item:getSubtype() > -1 then propertyTables[3] = ammoProperties[projectile.item.subtype.id] or {} end
- for propertyType,propertyTable in ipairs(propertyTables) do
- for field,value in pairs(propertyTable) do
- --Values that need to be multiplied or added
- if field == "deviation" or field == "hitrate" then
- if not props[field] then props[field] = value else props[field] = props[field] + value end
- elseif field == "velocity" or field == "falloff" or field == "breakChance" or field == "shotCount" or field == "rofMult" then
- if not props[field] then props[field] = value else props[field] = props[field] * value end
- --All other values will override the previous
- else
- props[field] = value
- end
- end
- end
- props.qualityScale = { propertyTables[1].qualityscale or 1, propertyTables[2].qualityscale or 1, propertyTables[3].qualityscale or 1 }
- if props.baseRof or props.altRof or props.rofMult ~= 1 then
- props.funcTable[1][#props.funcTable[1] + 1] = weaponRof
- if not persistTable[projectile.bow_id].weaponProps and projectile.bow_id > -1 then
- persistTable[projectile.bow_id].weaponProps = { increment = 1, windup = 0, baseRof = props.baseRof, altRof = props.altRof, windupRof = props.windupRof }
- end
- end
- if props.setMat then props.funcTable[1][#props.funcTable[1] + 1] = setMat end
- if props.shotCount >= 2 or props.setItem then props.funcTable[1][#props.funcTable[1] + 1] = multiInit end
- if props.deleteMe == 0 then props.funcTable[1][#props.funcTable[1] + 1] = terminate end
- if props.falloff then props.funcTable[2][#props.funcTable[2] + 1] = falloff end
- if props.trailFlows then props.funcTable[2][#props.funcTable[2] + 1] = spawnFlow end
- if props.deleteMe > 0 then props.funcTable[2][#props.funcTable[2] + 1] = terminate end
- if props.impactFlows then props.funcTable[3][#props.funcTable[3] + 1] = spawnFlow end
- props.funcTable[3][#props.funcTable[3] + 1] = terminate
- --print("Blam! "..dfhack.items.getSubtypeDef(props.setItem[1],props.setItem[2]).id.." id:"..props.projectile.id.." from:"..df.item.find(projectile.bow_id).subtype.id, "V:"..props.projectile.unk22, "dev:"..props.deviation.."@"..props.distance)
- --print(projectile.item.subtype.id, for rer,ere in pairs(props) do print(rer,ere) end, print()
- return props
- end
- function fireMod(projectile, props, mode)
- props.totalQuality = props.qualityScale[1] * ( props.qualityScale[2] * df.item.find(projectile.bow_id).quality + props.qualityScale[3] * projectile.item.quality )
- projectile.hit_rating = math.floor(projectile.hit_rating + props.hitrate + props.totalQuality)
- props.hitrate = projectile.hit_rating
- projectile.unk22 = math.floor(projectile.unk22 * props.velocity * (1 + props.totalQuality / 50))
- props.velocity = projectile.unk22
- if props.deviation ~= 0 then
- --Devided deviation by target max distance on x,y,z, relevant in case of cannons and a few AI targeting edge cases. If below 0, sets it to 0.
- props.distance = math.max(math.abs(projectile.origin_pos.x - projectile.target_pos.x),math.abs(projectile.origin_pos.y - projectile.target_pos.y),math.abs(projectile.origin_pos.z - projectile.target_pos.z))
- props.deviation = math.max(0, math.floor(0.5 + props.deviation / (1 + props.totalQuality / 25) / (50 / props.distance)))
- projectile.target_pos.x = projectile.target_pos.x + math.random(-props.deviation, props.deviation)
- projectile.target_pos.y = projectile.target_pos.y + math.random(-props.deviation, props.deviation)
- end
- if props.range then
- projectile.min_hit_distance = math.max(props.range[1], projectile.min_hit_distance)
- projectile.fall_threshold = math.min(props.range[2], projectile.fall_threshold)
- projectile.min_ground_distance = props.range[2] - 1
- end
- props.range = { projectile.min_hit_distance, projectile.fall_threshold }
- if props.breakChance then projectile.flags.no_impact_destroy = math.floor((1 - props.breakChance) / math.random(0, 1)) end
- if props.falloff then props.falloff = props.falloff - (1 - props.falloff) * (props.qualityScale[3] * projectile.item.quality / 10) end -- Gravitate to 1 depending on ammo quality * qualityScale
- if props.piercing then projectile.flags.piercing = props.piercing end
- end
- function weaponRof(projectile, props, mode)
- if projectile.firer then
- local weaponProps = persistTable[projectile.bow_id].weaponProps or {baseRof = {80, 1}}
- local windupMult
- if weaponProps.windupRof then windupMult = windupRof(weaponProps, 1) else windupMult = 1 end
- if not weaponProps.altRof then
- projectile.firer.counters.think_counter = math.floor(weaponProps.baseRof[1] * props.rofMult * windupMult / (1 + (80 / projectile.firer.counters.think_counter - 1) * weaponProps.baseRof[2]))
- elseif weaponProps.increment < weaponProps.altRof[2] then
- weaponProps.increment = weaponProps.increment + 1
- projectile.firer.counters.think_counter = math.floor(weaponProps.baseRof[1] * props.rofMult * windupMult / (1 + (80 / projectile.firer.counters.think_counter - 1) * weaponProps.baseRof[2]))
- else
- weaponProps.increment = 1
- projectile.firer.counters.think_counter = math.floor(weaponProps.altRof[1] * props.rofMult * windupMult / (1 + (80 / projectile.firer.counters.think_counter - 1) * weaponProps.altRof[3]))
- end
- end
- end
- function windupRof(weaponProps, mode)
- if mode == 1 then
- local windupMult = 1 + (weaponProps.windupRof[1] - 1) * (weaponProps.windupRof[2] - math.min(weaponProps.windupRof[2],weaponProps.windup)) / weaponProps.windupRof[2]
- if weaponProps.windup == 0 then
- dfhack.timeout(weaponProps.windupRof[3],'ticks',function() windupRof(weaponProps, 2) end)
- end
- weaponProps.windup = math.min(weaponProps.windup + 1, weaponProps.windupRof[2] + 1)
- return windupMult
- end
- weaponProps.windup = weaponProps.windup - 1
- if weaponProps.windup > 0 then
- dfhack.timeout(weaponProps.windupRof[3],'ticks',function() windupRof(weaponProps, 2) end)
- end
- end
- function setMat(projectile, props, mode)
- projectile.item:setMaterial(props.setMat[1])
- projectile.item:setMaterialIndex(props.setMat[2])
- end
- function multiInit(projectile, props, mode)
- local firer = df.unit.find(props.firerId)
- if not props.setMat then props.setMat = { projectile.item.mat_type, projectile.item.mat_index } end
- if not props.setItem then props.setItem = { projectile.item:getType(), projectile.item:getSubtype() }
- else
- props.shotCount = props.shotCount + 1
- props.funcTable[1][#props.funcTable[1] + 1] = terminate
- end
- if props.shotCount >= 2 then
- if not props.shotRof then
- multiShot(props, mode, firer)
- else
- local weaponProps = persistTable[projectile.bow_id].weaponProps
- local windupMult
- if weaponProps.windupRof then windupMult = windupRof(weaponProps, 1) end
- local rof = props.shotRof[1]
- if firer.counters.think_counter > 0 then
- rof = rof * props.rofMult / (1 + (80 / firer.counters.think_counter - 1) * props.shotRof[2])
- end
- if props.funcTable[1][#props.funcTable[1]] == terminate then
- multiShot(props, mode, firer, rof, weaponProps)
- else
- if weaponProps.windupRof then windupMult = windupRof(weaponProps, 1) else windupMult = 1 end
- if firer.counters.think_counter > 0 then firer.counters.think_counter = math.floor(firer.counters.think_counter + 0.5 + rof * windupMult) end
- dfhack.timeout(math.floor(0.5 + rof * windupMult),'ticks',function() multiShot(props, mode, firer, rof, weaponProps) end)
- end
- end
- end
- end
- function multiShot(props, mode, firer, rof, weaponProps)
- if firer.flags2.killed == true then return end
- local projectileItem = df.item.find(dfhack.items.createItem(props.setItem[1], props.setItem[2], props.setMat[1], props.setMat[2], firer))
- local projectile = dfhack.items.makeProjectile(projectileItem)
- projectile.origin_pos = props.originPos
- projectile.prev_pos = props.originPos
- projectile.cur_pos = props.originPos
- projectile.target_pos = xyz2pos(props.targetPos.x + math.random(-props.deviation, props.deviation), props.targetPos.y + math.random(-props.deviation, props.deviation), props.targetPos.z)
- projectile.flags.piercing = props.piercing
- projectile.min_hit_distance = props.range[1]
- projectile.fall_threshold = props.range[2]
- projectile.min_ground_distance = props.range[2] - 1
- projectile.hit_rating = props.hitrate
- projectile.unk22 = props.velocity
- projectile.bow_id = props.bowId
- projectile.firer = firer
- if props.quality then projectile.item.quality = props.quality end
- projectile.distance_flown = 0
- projectile.fall_counter = 0
- projectile.fall_delay = 0
- props.shotCount = props.shotCount - 1
- persistTable[props.bowId][projectileItem.id] = props
- if props.shotCount >= 2 then
- if not rof then
- multiShot(props, mode, firer)
- else
- local windupMult = 1
- if weaponProps.windupRof then windupMult = windupRof(weaponProps, 1) end
- if firer ~= df.unit.find(0) then firer.counters.think_counter = math.floor(0.5 + firer.counters.think_counter + rof * windupMult) end
- dfhack.timeout(math.floor(0.5 + rof * windupMult),'ticks',function() multiShot(props, mode, firer, rof, weaponProps) end)
- end
- end
- end
- function falloff(projectile, props, mode)
- if projectile.distance_flown % 4 == 0 then
- --print("id:"..projectile.item.id.." @"..projectile.distance_flown, "V:"..projectile.unk22, "fall:"..props.falloff)
- projectile.unk22 = math.floor(projectile.unk22 * props.falloff)
- end
- end
- function spawnFlow(projectile, props, mode)
- if mode == 2 then mode = "trailFlows" else mode = "impactFlows" end
- for _,flow in ipairs(props[mode]) do
- if mode == "trailFlows" then
- if projectile.distance_flown < tonumber(flow.minmaxint[1]) or projectile.distance_flown > tonumber(flow.minmaxint[2]) or projectile.distance_flown % flow.minmaxint[3] ~= 0 then
- return
- end
- end
- local volume = math.floor(flow.volume * (1 + flow.flowQuality * projectile.item.quality) * (1 + flow.conical * projectile.distance_flown))
- local flowski = dfhack.maps.spawnFlow(projectile.cur_pos, flow.flowType, flow.flowMat[1], flow.flowMat[2], volume)
- if not flow.direction then
- flowski.dest = xyz2pos(flowski.pos.x, flowski.pos.y, flowski.pos.z)
- else
- --determine distance per axis, devide all by largest distance to get the direction, increase by a factor of the volume and apply to cur_position.
- local xyzdelta = { x = projectile.target_pos.x - projectile.origin_pos.x, y = projectile.target_pos.y - projectile.origin_pos.y, z = projectile.target_pos.z - projectile.origin_pos.z }
- local flowreach = math.max(math.abs(xyzdelta.x), math.abs(xyzdelta.y), math.abs(xyzdelta.z)) / 0.3 * volume
- xyzdelta = { x = math.floor(projectile.cur_pos.x + xyzdelta.x / flowreach), y = math.floor(projectile.cur_pos.y + xyzdelta.y / flowreach), z = math.floor(projectile.cur_pos.z + xyzdelta.z / flowreach) }
- flowski.dest = xyz2pos(xyzdelta.x, xyzdelta.y, xyzdelta.z)
- end
- if not flow.expand then flowski.expanding = false end
- end
- end
- function terminate(projectile, props, mode)
- if mode < 3 or props.deleteMe == -1 then
- projectile.flags.to_be_deleted = true
- projectile.item.flags.garbage_collect = true
- end
- props = nil
- end
- noInit = true
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement