Hey there, i'm currently trying to create a melee weapon that can cycle between elements similarly to the Adaptable Crossbow. The problem i'm running into is that I have it mostly finished - the sword cycles properly between elements on a right click, and emits the correct particles and such when being slashed, but seems to always apply physical damage no matter which element it has been switched to. As i'm rather unfamiliar with more involved code-work, I decided to ask for help here. Here's the json file for the item: { "itemName" : "isn_prism_blade", "price" : 7500, "level" : 4, "maxStack" : 1, "rarity" : "Legendary", "description" : "Focuses a short ray of deadly light through a prism.", "shortdescription" : "Prism Blade", "tooltipKind" : "sword", "category" : "broadsword", "twoHanded" : true, "itemTags" : ["weapon","melee","broadsword"], "inventoryIcon" : "isn_prism_blade.png", "animation" : "/items/active/weapons/melee/broadsword/combobroadsword.animation", "animationParts" : { "handle" : "", "blade" : "isn_prism_blade.png" }, "animationCustom" : { "sounds" : { "typeswitch" : [ "/sfx/objects/ancientlightplatform_on.ogg" ] } }, "scripts" : ["/items/active/weapons/melee/meleeweapon.lua"], "elementalType" : "physical", "projectileOffset" : [0,0], "primaryAbilityType" : "isn_prism_blade_lmb", "builder" : "/items/buildscripts/buildunrandweapon.lua" } The json file for the weaponability it uses: { "animationParts" : { }, "animationCustom" : { "sounds" : { "fire" : [ "/sfx/melee/mech_energysword_swing1.ogg" ], "fire2" : [ "/sfx/melee/mech_energysword_swing2.ogg" ], "fire3" : [ "/sfx/melee/mech_energysword_swing3.ogg" ] } }, "ability" : { "name" : "Prism Combo Slash", "type" : "isn_prism_blade_lmb", "scripts" : ["/items/active/isn_prism_blade/isn_prism_blade.lua"], "class" : "PrismCombo", "comboSteps" : 3, "flashTime" : 0.15, "flashDirectives" : "fade=FFFFFFFF=0.15", "swooshOffsetRegions" : [ [0.75, 0.0, 4.25, 5.0], [3.0, -0.5, 6.5, 2.0], [1.5, -1.0, 5.5, 1.0] ], // cooldown time multiplier for steps after the first, compounded per combo step "comboSpeedFactor" : 0.8, "edgeTriggerGrace" : 0.1, "fireTime" : 0.8, "baseDps" : 7.0, "damageConfig" : { "damageSourceKind" : "broadsword", "statusEffects" : [ ], "knockbackMode" : "facing", "timeout" : 0.5 }, "stepDamageConfig" : [ { "baseDamageFactor" : 1.0, "knockback" : 15 }, { "baseDamageFactor" : 0.5, "knockback" : 10 }, { "baseDamageFactor" : 1.0, "knockback" : 25 } ], "stances" : { "idle" : { "armRotation" : -90, "weaponRotation" : -10, "allowRotate" : false, "allowFlip" : true }, "windup1" : { "duration" : 0.05, "armRotation" : 90, "weaponRotation" : -10, "twoHanded" : true, "allowRotate" : false, "allowFlip" : true }, "preslash1" : { "duration" : 0.025, "armRotation" : 55, "weaponRotation" : -45, "twoHanded" : true, "allowRotate" : false, "allowFlip" : false }, "fire1" : { "duration" : 0.075, "armRotation" : -45, "weaponRotation" : -55, "twoHanded" : true, "allowRotate" : false, "allowFlip" : false }, "wait1" : { "duration" : 0.05, "armRotation" : -45, "weaponRotation" : -55, "allowRotate" : false, "allowFlip" : true, "twoHanded" : true }, "windup2" : { "duration" : 0.05, "armRotation" : -15, "weaponRotation" : -60, "weaponOffset" : [0, 0], "twoHanded" : true, "allowFlip" : true, "allowRotate" : false }, "fire2" : { "duration" : 0.1, "armRotation" : -150, "weaponRotation" : 55, "weaponOffset" : [0, 0], "twoHanded" : true, "allowFlip" : true, "allowRotate" : false }, "wait2" : { "duration" : 0.05, "armRotation" : -150, "weaponRotation" : 55, "weaponOffset" : [0, 0], "allowRotate" : false, "allowFlip" : true, "twoHanded" : true }, "windup3" : { "duration" : 0.05, "armRotation" : -150, "weaponRotation" : 55, "twoHanded" : true, "allowRotate" : false, "allowFlip" : true }, "fire3" : { "duration" : 0.03, "armRotation" : 0, "weaponRotation" : -90, "twoHanded" : true, "allowRotate" : false, "allowFlip" : true } } } } And the lua file the weaponability runs on: -- Melee primary ability PrismCombo = WeaponAbility:new() function PrismCombo:init() self.comboStep = 1 self.scriptdamageconfig = self.damageConfig self.energyUsage = self.energyUsage or 0 self:computeDamageAndCooldowns() self.weapon:setStance(self.stances.idle) self.edgeTriggerTimer = 0 self.flashTimer = 0 self.cooldownTimer = self.cooldowns[1] self.animKeyPrefix = self.animKeyPrefix or "" self.clickprevention = false self.flashtime = 0 self.weapon.onLeaveAbility = function() self.weapon:setStance(self.stances.idle) end end -- Ticks on every update regardless if this is the active ability function PrismCombo:update(dt, fireMode, shiftHeld) WeaponAbility.update(self, dt, fireMode, shiftHeld) if self.cooldownTimer > 0 then self.cooldownTimer = math.max(0, self.cooldownTimer - self.dt) if self.cooldownTimer == 0 then self:readyFlash() end end if self.flashTimer > 0 then self.flashTimer = math.max(0, self.flashTimer - self.dt) if self.flashTimer == 0 then animator.setGlobalTag("bladeDirectives", "") end end self.edgeTriggerTimer = math.max(0, self.edgeTriggerTimer - dt) if self.lastFireMode ~= (self.activatingFireMode or self.abilitySlot) and fireMode == (self.activatingFireMode or self.abilitySlot) then self.edgeTriggerTimer = self.edgeTriggerGrace end self.lastFireMode = fireMode if not self.weapon.currentAbility and self:shouldActivate() then self:setState(self.windup) end if self.fireMode == "alt" then if self.clickprevention == false then animator.playSound("typeswitch") animator.setGlobalTag("bladeDirectives", "fade=FFFFFFFF=0.3") self.flashtime = 5 if self.scriptdamageconfig.damageSourceKind == "broadsword" then self.scriptdamageconfig.damageSourceKind = "firebroadsword" self.elementalType = "fire" self.weapon.elementalType = "fire" elseif self.scriptdamageconfig.damageSourceKind == "firebroadsword" then self.scriptdamageconfig.damageSourceKind = "icebroadsword" self.elementalType = "ice" self.weapon.elementalType = "ice" elseif self.scriptdamageconfig.damageSourceKind == "icebroadsword" then self.scriptdamageconfig.damageSourceKind = "poisonbroadsword" self.elementalType = "poison" self.weapon.elementalType = "poison" elseif self.scriptdamageconfig.damageSourceKind == "poisonbroadsword" then self.scriptdamageconfig.damageSourceKind = "electricbroadsword" self.elementalType = "electric" self.weapon.elementalType = "electric" else self.scriptdamageconfig.damageSourceKind = "broadsword" self.elementalType = "physical" self.weapon.elementalType = "physical" end end self.clickprevention = true else self.clickprevention = false end self.flashtime = self.flashtime - 1 if self.flashtime < 1 then animator.setGlobalTag("bladeDirectives", "") end end -- State: windup function PrismCombo:windup() local stance = self.stances["windup"..self.comboStep] self.weapon:setStance(stance) self.edgeTriggerTimer = 0 if stance.hold then while self.fireMode == (self.activatingFireMode or self.abilitySlot) do coroutine.yield() end else util.wait(stance.duration) end if self.energyUsage then status.overConsumeResource("energy", self.energyUsage) end if self.stances["preslash"..self.comboStep] then self:setState(self.preslash) else self:setState(self.fire) end end -- State: wait -- waiting for next combo input function PrismCombo:wait() local stance = self.stances["wait"..(self.comboStep - 1)] self.weapon:setStance(stance) util.wait(stance.duration, function() if self:shouldActivate() then self:setState(self.windup) return end end) self.cooldownTimer = math.max(0, self.cooldowns[self.comboStep - 1] - stance.duration) self.comboStep = 1 end -- State: preslash -- brief frame in between windup and fire function PrismComboreslash() local stance = self.stances["preslash"..self.comboStep] self.weapon:setStance(stance) self.weapon:updateAim() util.wait(stance.duration) self:setState(self.fire) end -- State: fire function PrismCombo:fire() local stance = self.stances["fire"..self.comboStep] self.weapon:setStance(stance) self.weapon:updateAim() local animStateKey = self.animKeyPrefix .. (self.comboStep > 1 and "fire"..self.comboStep or "fire") animator.setAnimationState("swoosh", animStateKey) animator.playSound(animStateKey) local swooshKey = self.animKeyPrefix .. (self.elementalType or self.weapon.elementalType) .. "swoosh" animator.setParticleEmitterOffsetRegion(swooshKey, self.swooshOffsetRegions[self.comboStep]) animator.burstParticleEmitter(swooshKey) util.wait(stance.duration, function() local damageArea = partDamageArea("swoosh") self.weapon:setDamage(self.stepDamageConfig[self.comboStep], damageArea) end) if self.comboStep < self.comboSteps then self.comboStep = self.comboStep + 1 self:setState(self.wait) else self.cooldownTimer = self.cooldowns[self.comboStep] self.comboStep = 1 end end function PrismCombo:shouldActivate() if self.cooldownTimer == 0 and (self.energyUsage == 0 or not status.resourceLocked("energy")) then if self.comboStep > 1 then return self.edgeTriggerTimer > 0 else return self.fireMode == (self.activatingFireMode or self.abilitySlot) end end end function PrismCombo:readyFlash() animator.setGlobalTag("bladeDirectives", self.flashDirectives) self.flashTimer = self.flashTime end function PrismCombo:computeDamageAndCooldowns() local attackTimes = {} for i = 1, self.comboSteps do local attackTime = self.stances["windup"..i].duration + self.stances["fire"..i].duration if self.stances["preslash"..i] then attackTime = attackTime + self.stances["preslash"..i].duration end table.insert(attackTimes, attackTime) end self.cooldowns = {} local totalAttackTime = 0 local totalDamageFactor = 0 for i, attackTime in ipairs(attackTimes) do self.stepDamageConfig = util.mergeTable(copy(self.scriptdamageconfig), self.stepDamageConfig) self.stepDamageConfig.timeoutGroup = "primary"..i local damageFactor = self.stepDamageConfig.baseDamageFactor self.stepDamageConfig.baseDamage = damageFactor * self.baseDps * self.fireTime totalAttackTime = totalAttackTime + attackTime totalDamageFactor = totalDamageFactor + damageFactor local targetTime = totalDamageFactor * self.fireTime local speedFactor = 1.0 * (self.comboSpeedFactor ^ i) table.insert(self.cooldowns, (targetTime - totalAttackTime) * speedFactor) end end function PrismCombo:uninit() self.weapon:setDamage() end Any help you can offer is greatly appreciated. =)
Aha, I managed to fix it on my own. Turns out I was thinking along the right lines altering the damageconfig, but was altering the wrong one. Broadswords that swing in a combo have a seperate damageconfig for each slash that needs to have its damagesource changed to the new element, like so: This line in init gives me easier access to the first step's damageconfig: self.stepone = self.stepDamageConfig[1] Then in the code that changes elements, I do this: self.stepone.damageSourceKind = "firebroadsword" Et voila, the first slash now does fire elemental damage. You could also probably set up a sword that does different elemental damage on each swing with this too, if you wanted.