223 lines
7.1 KiB
Lua
223 lines
7.1 KiB
Lua
require "/scripts/util.lua"
|
|
require "/items/active/weapons/weapon.lua"
|
|
|
|
-- whip primary attack plus swinging from torches like a boss
|
|
SuperWhipCrack = WeaponAbility:new()
|
|
|
|
function SuperWhipCrack:init()
|
|
self.damageConfig.baseDamage = self.chainDps * self.fireTime
|
|
|
|
self.weapon:setStance(self.stances.idle)
|
|
animator.setAnimationState("attack", "idle")
|
|
activeItem.setScriptedAnimationParameter("chains", nil)
|
|
|
|
self.cooldownTimer = self:cooldownTime()
|
|
|
|
self.weapon.onLeaveAbility = function()
|
|
self.weapon:setStance(self.stances.idle)
|
|
end
|
|
|
|
self.projectileConfig = self.projectileConfig or {}
|
|
|
|
self.chain = config.getParameter("chain")
|
|
|
|
self.anchorObjects = config.getParameter("anchorObjects", {"torch"})
|
|
self.anchor = nil
|
|
|
|
self.snapDistance = config.getParameter("snapDistance", 3.0)
|
|
end
|
|
|
|
-- Ticks on every update regardless if this is the active ability
|
|
function SuperWhipCrack:update(dt, fireMode, shiftHeld)
|
|
WeaponAbility.update(self, dt, fireMode, shiftHeld)
|
|
|
|
self.cooldownTimer = math.max(0, self.cooldownTimer - self.dt)
|
|
|
|
if self.fireMode == "primary" and self:canStartAttack() then
|
|
self:setState(self.windup)
|
|
self.fireHeld = true
|
|
elseif self.fireMode ~= "primary" and self.fireHeld then
|
|
self.fireHeld = false
|
|
self:disconnect()
|
|
end
|
|
end
|
|
|
|
function SuperWhipCrack:canStartAttack()
|
|
return not self.weapon.currentAbility and self.cooldownTimer == 0
|
|
end
|
|
|
|
-- State: windup
|
|
function SuperWhipCrack:windup()
|
|
self.weapon:setStance(self.stances.windup)
|
|
|
|
animator.setAnimationState("attack", "windup")
|
|
|
|
util.wait(self.stances.windup.duration)
|
|
|
|
self:setState(self.extend)
|
|
end
|
|
|
|
-- State: extend
|
|
function SuperWhipCrack:extend()
|
|
self.weapon:setStance(self.stances.extend)
|
|
|
|
animator.setAnimationState("attack", "extend")
|
|
animator.playSound("swing")
|
|
|
|
util.wait(self.stances.extend.duration)
|
|
|
|
if self.fireHeld then
|
|
self.anchor = self:findAnchor()
|
|
end
|
|
|
|
if self.anchor then
|
|
animator.setAnimationState("attack", "fire")
|
|
self:setState(self.swing)
|
|
else
|
|
animator.setAnimationState("attack", "fire")
|
|
self:setState(self.fire)
|
|
end
|
|
end
|
|
|
|
-- State: swing
|
|
function SuperWhipCrack:swing()
|
|
self.weapon:setStance(self.stances.swing)
|
|
self.weapon:updateAim()
|
|
|
|
self.cooldownTimer = self:cooldownTime()
|
|
|
|
while self.anchor do
|
|
if world.entityExists(self.anchor) then
|
|
local chainEndPos = vec2.add(world.entityPosition(self.anchor), {0.5, 0.5})
|
|
local chainStartPos = vec2.add(mcontroller.position(), activeItem.handPosition(self.chain.startOffset))
|
|
if not world.lineCollision(chainStartPos, chainEndPos) then
|
|
local aimVector = world.distance(chainEndPos, chainStartPos)
|
|
local swingAngle = vec2.angle(aimVector)
|
|
if not mcontroller.onGround() then
|
|
mcontroller.controlApproachVelocityAlongAngle(swingAngle, 0, 1000, true)
|
|
else
|
|
mcontroller.controlModifiers({movementSuppressed = true})
|
|
end
|
|
|
|
if self.weapon.aimDirection < 0 then
|
|
self.weapon.aimAngle = vec2.angle({-aimVector[1], aimVector[2]})
|
|
else
|
|
self.weapon.aimAngle = swingAngle
|
|
end
|
|
self.weapon:updateAim()
|
|
|
|
self.chain.endPosition = chainEndPos
|
|
activeItem.setScriptedAnimationParameter("chains", {self.chain})
|
|
|
|
coroutine.yield()
|
|
else
|
|
self:disconnect()
|
|
end
|
|
else
|
|
self:disconnect()
|
|
end
|
|
end
|
|
end
|
|
|
|
function SuperWhipCrack:disconnect()
|
|
self.anchor = nil
|
|
animator.setAnimationState("attack", "idle")
|
|
self.chain.endPosition = nil
|
|
activeItem.setScriptedAnimationParameter("chains", nil)
|
|
end
|
|
|
|
-- State: fire
|
|
function SuperWhipCrack:fire()
|
|
self.weapon:setStance(self.stances.fire)
|
|
self.weapon:updateAim()
|
|
|
|
local chainStartPos = vec2.add(mcontroller.position(), activeItem.handPosition(self.chain.startOffset))
|
|
local chainLength = world.magnitude(chainStartPos, activeItem.ownerAimPosition())
|
|
chainLength = math.min(self.chain.length[2], math.max(self.chain.length[1], chainLength))
|
|
|
|
self.chain.endOffset = vec2.add(self.chain.startOffset, {chainLength, 0})
|
|
local collidePoint = world.lineCollision(chainStartPos, vec2.add(mcontroller.position(), activeItem.handPosition(self.chain.endOffset)))
|
|
if collidePoint then
|
|
chainLength = world.magnitude(chainStartPos, collidePoint) - 0.25
|
|
if chainLength < self.chain.length[1] then
|
|
animator.setAnimationState("attack", "idle")
|
|
return
|
|
else
|
|
self.chain.endOffset = vec2.add(self.chain.startOffset, {chainLength, 0})
|
|
end
|
|
end
|
|
|
|
local chainEndPos = vec2.add(mcontroller.position(), activeItem.handPosition(self.chain.endOffset))
|
|
|
|
activeItem.setScriptedAnimationParameter("chains", {self.chain})
|
|
|
|
animator.resetTransformationGroup("endpoint")
|
|
animator.translateTransformationGroup("endpoint", self.chain.endOffset)
|
|
animator.burstParticleEmitter("crack")
|
|
animator.playSound("crack")
|
|
|
|
self.projectileConfig.power = self:crackDamage()
|
|
self.projectileConfig.powerMultiplier = activeItem.ownerPowerMultiplier()
|
|
|
|
local projectileAngle = vec2.withAngle(self.weapon.aimAngle)
|
|
if self.weapon.aimDirection < 0 then projectileAngle[1] = -projectileAngle[1] end
|
|
|
|
world.spawnProjectile(
|
|
self.projectileType,
|
|
chainEndPos,
|
|
activeItem.ownerEntityId(),
|
|
projectileAngle,
|
|
false,
|
|
self.projectileConfig
|
|
)
|
|
|
|
util.wait(self.stances.fire.duration, function()
|
|
if self.damageConfig.baseDamage > 0 then
|
|
self.weapon:setDamage(self.damageConfig, {self.chain.startOffset, {self.chain.endOffset[1] + 0.75, self.chain.endOffset[2]}}, self.fireTime)
|
|
end
|
|
end)
|
|
|
|
animator.setAnimationState("attack", "idle")
|
|
activeItem.setScriptedAnimationParameter("chains", nil)
|
|
|
|
self.cooldownTimer = self:cooldownTime()
|
|
end
|
|
|
|
function SuperWhipCrack:cooldownTime()
|
|
return self.fireTime - (self.stances.windup.duration + self.stances.extend.duration + self.stances.fire.duration)
|
|
end
|
|
|
|
function SuperWhipCrack:uninit(unloaded)
|
|
self.weapon:setDamage()
|
|
activeItem.setScriptedAnimationParameter("chains", nil)
|
|
end
|
|
|
|
function SuperWhipCrack:chainDamage()
|
|
return (self.chainDps * self.fireTime) * config.getParameter("damageLevelMultiplier")
|
|
end
|
|
|
|
function SuperWhipCrack:crackDamage()
|
|
return (self.crackDps * self.fireTime) * config.getParameter("damageLevelMultiplier")
|
|
end
|
|
|
|
function SuperWhipCrack:findAnchor()
|
|
local objectsNearCursor = world.objectQuery(activeItem.ownerAimPosition(), 5, {boundMode = "metaboundbox", order = "nearest"})
|
|
if #objectsNearCursor > 0 then
|
|
local objectName = world.entityName(objectsNearCursor[1])
|
|
local anchorValid = false
|
|
for _, anchorObject in pairs(self.anchorObjects) do
|
|
if anchorObject == objectName then
|
|
anchorValid = true
|
|
break
|
|
end
|
|
end
|
|
if anchorValid then
|
|
local pos = vec2.add(world.entityPosition(objectsNearCursor[1]), {0.5, 0.5})
|
|
local distToCursor = world.magnitude(pos, activeItem.ownerAimPosition())
|
|
local distToHand = world.magnitude(pos, vec2.add(mcontroller.position(), activeItem.handPosition(self.chain.startOffset)))
|
|
if distToCursor <= self.snapDistance and distToHand <= self.chain.length[2] and distToHand >= self.chain.length[1] then
|
|
return objectsNearCursor[1]
|
|
end
|
|
end
|
|
end
|
|
end
|