v1.4.4
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"itemName" : "chainball",
|
||||
"price" : 500,
|
||||
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "Whomp.",
|
||||
"shortdescription" : "Chain Ball",
|
||||
"tooltipKind" : "base",
|
||||
"twoHanded" : true,
|
||||
|
||||
"inventoryIcon" : "chainballicon.png",
|
||||
"animation" : "chainball.animation",
|
||||
"animationParts" : {
|
||||
"grapple" : "chainball.png"
|
||||
},
|
||||
"animationCustom" : { },
|
||||
"animationScripts" : [
|
||||
"/items/active/effects/renderrope.lua"
|
||||
],
|
||||
|
||||
"scripts" : ["chainball.lua"],
|
||||
|
||||
"ropeOffset" : [0.5, 0.375],
|
||||
"ropeWidth" : 1,
|
||||
"ropeColor" : [150, 150, 150, 255],
|
||||
"ropeFullbright" : false,
|
||||
|
||||
"fireOffset" : [-0.5, 0],
|
||||
"fireDirection" : [-0.5, 0.5],
|
||||
|
||||
"returnSpeed" : 20,
|
||||
"returnDistance" : 3.0,
|
||||
|
||||
"projectileType" : "chainball",
|
||||
"projectileParameters" : {
|
||||
"speed" : 50,
|
||||
|
||||
"orbitParameters" : {
|
||||
"gravityEnabled" : false,
|
||||
"collisionEnabled" : true
|
||||
},
|
||||
"releaseParameters" : {
|
||||
"gravityEnabled" : true,
|
||||
"collisionEnabled" : true
|
||||
}
|
||||
},
|
||||
|
||||
"stances" : {
|
||||
"idle" : {
|
||||
"armRotation" : 20,
|
||||
"weaponRotation" : 0,
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : true
|
||||
},
|
||||
"swingup" : {
|
||||
"armRotation" : 50,
|
||||
"weaponRotation" : -45,
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
},
|
||||
"release" : {
|
||||
"armRotation" : 20,
|
||||
"weaponRotation" : -45,
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
},
|
||||
"retrieve" : {
|
||||
"armRotation" : 0,
|
||||
"weaponRotation" : -45,
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"weapon" : {
|
||||
"default" : "full",
|
||||
"states" : {
|
||||
"full" : {},
|
||||
"empty" : {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parts" : {
|
||||
"grapple" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"offset" : [0.625, 0.625],
|
||||
"rotationGroups" : [ "weapon" ],
|
||||
"rotationCenter" : [0, 0]
|
||||
},
|
||||
|
||||
"partStates" : {
|
||||
"weapon" : {
|
||||
"full" : {
|
||||
"properties" : {
|
||||
"image" : "<partImage>:full"
|
||||
}
|
||||
},
|
||||
"empty" : {
|
||||
"properties" : {
|
||||
"image" : "<partImage>:empty"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"rotationGroups" : {
|
||||
"weapon" : {
|
||||
"angularVelocity" : 0
|
||||
}
|
||||
},
|
||||
|
||||
"sounds" : {
|
||||
"fire" : [ ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [19, 19],
|
||||
"dimensions" : [2, 1],
|
||||
"names" : [
|
||||
["full", "empty"]
|
||||
]
|
||||
}
|
||||
}
|
192
assets/devel/items/active/weapons/chainball/chainball.lua
Normal file
|
@ -0,0 +1,192 @@
|
|||
require "/scripts/vec2.lua"
|
||||
require "/scripts/util.lua"
|
||||
|
||||
function init()
|
||||
self.fireOffset = config.getParameter("fireOffset", {0,0})
|
||||
self.fireDirection = config.getParameter("fireDirection")
|
||||
self.stances = config.getParameter("stances")
|
||||
self.projectileType = config.getParameter("projectileType")
|
||||
self.projectileParameters = config.getParameter("projectileParameters")
|
||||
self.returnSpeed = config.getParameter("returnSpeed", 0)
|
||||
self.returnDistance = config.getParameter("returnDistance", 1)
|
||||
|
||||
self.swingSpeed = {30, 60}
|
||||
self.swingupTime = 1.5
|
||||
self.swingupTimer = 0
|
||||
self.swingRadius = 1.5
|
||||
|
||||
self.releaseAngle = 0.15
|
||||
|
||||
self.pullSpeed = 50
|
||||
self.pullForce = 500
|
||||
self.maxChainLength = 15
|
||||
self.currentChainLength = 0
|
||||
|
||||
self.previousFireMode = "none"
|
||||
self.ropeSegments = {}
|
||||
|
||||
self.ropeOffset = config.getParameter("ropeOffset", self.fireOffset)
|
||||
|
||||
self.aimAngle = 0
|
||||
setStance("idle")
|
||||
end
|
||||
|
||||
function update(dt, fireMode, shiftHeld)
|
||||
self.stanceTimer = math.max(self.stanceTimer - dt, 0)
|
||||
|
||||
checkProjectile()
|
||||
|
||||
if self.stanceName == "idle" then
|
||||
if fireMode == "primary" and self.previousFireMode ~= "primary" then
|
||||
fire()
|
||||
end
|
||||
elseif self.stanceName == "swingup" then
|
||||
if fireMode == "primary" then
|
||||
self.swingupTimer = self.swingupTimer + dt
|
||||
local swingSpeedRatio = math.min(1, self.swingupTimer / self.swingupTime)
|
||||
world.callScriptedEntity(self.projectileId, "updateOrbit", chainSourcePosition(), self.aimDirection * util.lerp(swingSpeedRatio, self.swingSpeed[1], self.swingSpeed[2]))
|
||||
elseif self.previousFireMode == "primary" then
|
||||
-- local releaseAngle = activeItem.aimAngleAndDirection(0, activeItem.ownerAimPosition())
|
||||
world.callScriptedEntity(self.projectileId, "requestRelease", self.aimDirection > 0 and self.releaseAngle or math.pi - self.releaseAngle)
|
||||
self.currentChainLength = self.maxChainLength
|
||||
end
|
||||
elseif self.stanceName == "release" then
|
||||
if fireMode == "primary" or world.callScriptedEntity(self.projectileId, "landed") or chainLength() > self.currentChainLength then
|
||||
setStance("retrieve")
|
||||
end
|
||||
elseif self.stanceName == "retrieve" then
|
||||
self.currentChainLength = math.min(self.currentChainLength, chainLength())
|
||||
if fireMode == "primary" and mcontroller.onGround() then
|
||||
mcontroller.controlModifiers({movementSuppressed=true})
|
||||
world.callScriptedEntity(self.projectileId, "pullChain", chainSourcePosition(), self.pullSpeed, self.pullForce)
|
||||
elseif chainLength() > self.currentChainLength + 0.1 then
|
||||
local pullVector = world.distance(world.entityPosition(self.projectileId), chainSourcePosition())
|
||||
local pullAngle = vec2.angle(pullVector)
|
||||
mcontroller.controlApproachVelocityAlongAngle(pullAngle, world.callScriptedEntity(self.projectileId, "speed"), 5000, true)
|
||||
if mcontroller.onGround() then
|
||||
world.callScriptedEntity(self.projectileId, "pullChain", chainSourcePosition(), 3, 500)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.previousFireMode = fireMode
|
||||
|
||||
updateAim(self.stance.allowRotate, self.stance.allowFlip)
|
||||
buildRopeSegments()
|
||||
end
|
||||
|
||||
function uninit()
|
||||
if self.projectileId and world.entityExists(self.projectileId) then
|
||||
world.callScriptedEntity(self.projectileId, "kill")
|
||||
end
|
||||
end
|
||||
|
||||
function fire()
|
||||
self.released = false
|
||||
self.projectileParameters.orbitDistance = self.swingRadius
|
||||
self.projectileParameters.orbitSpeed = self.aimDirection > 0 and self.swingSpeed[1] or -self.swingSpeed[1]
|
||||
self.projectileParameters.pickupDistance = 2.0
|
||||
local projectileId = world.spawnProjectile(
|
||||
self.projectileType,
|
||||
firePosition(),
|
||||
activeItem.ownerEntityId(),
|
||||
self.fireDirection,
|
||||
false,
|
||||
self.projectileParameters
|
||||
)
|
||||
if projectileId then
|
||||
self.projectileId = projectileId
|
||||
setStance("swingup")
|
||||
self.swingupTimer = 0
|
||||
animator.playSound("fire")
|
||||
end
|
||||
end
|
||||
|
||||
function release()
|
||||
setStance("release")
|
||||
world.callScriptedEntity(self.projectileId, "release")
|
||||
end
|
||||
|
||||
function setStance(stanceName)
|
||||
self.stanceName = stanceName
|
||||
self.stance = self.stances[stanceName]
|
||||
self.stanceTimer = self.stance.duration or 0
|
||||
animator.setAnimationState("weapon", stanceName == "idle" and "full" or "empty")
|
||||
animator.rotateGroup("weapon", util.toRadians(self.stance.weaponRotation))
|
||||
updateAim(self.stance.allowRotate, self.stance.allowFlip)
|
||||
end
|
||||
|
||||
function resetChain()
|
||||
if self.projectileId then
|
||||
if world.entityExists(self.projectileId) then
|
||||
world.callScriptedEntity(self.projectileId, "kill")
|
||||
end
|
||||
self.projectileId = nil
|
||||
end
|
||||
setStance("idle")
|
||||
end
|
||||
|
||||
function checkProjectile()
|
||||
if self.projectileId then
|
||||
if world.entityExists(self.projectileId) then
|
||||
if not self.released then
|
||||
self.released = world.callScriptedEntity(self.projectileId, "released")
|
||||
if self.released then
|
||||
setStance("release")
|
||||
end
|
||||
end
|
||||
else
|
||||
resetChain()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function buildRopeSegments()
|
||||
if self.projectileId and world.entityExists(self.projectileId) then
|
||||
local position = mcontroller.position()
|
||||
local handPosition = vec2.add(position, activeItem.handPosition(self.ropeOffset))
|
||||
activeItem.setScriptedAnimationParameter("p1", handPosition)
|
||||
activeItem.setScriptedAnimationParameter("p2", world.entityPosition(self.projectileId))
|
||||
else
|
||||
activeItem.setScriptedAnimationParameter("p1", nil)
|
||||
activeItem.setScriptedAnimationParameter("p2", nil)
|
||||
end
|
||||
end
|
||||
|
||||
function updateAim(allowRotate, allowFlip)
|
||||
local aimAngle, aimDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
|
||||
|
||||
if allowRotate then
|
||||
self.aimAngle = aimAngle
|
||||
end
|
||||
aimAngle = (self.aimAngle or 0) + util.toRadians(self.stance.armRotation)
|
||||
activeItem.setArmAngle(aimAngle)
|
||||
|
||||
if allowFlip then
|
||||
self.aimDirection = aimDirection
|
||||
end
|
||||
activeItem.setFacingDirection((self.aimDirection or 0))
|
||||
end
|
||||
|
||||
function aimVector()
|
||||
local aimVector = vec2.rotate({1, 0}, self.aimAngle)
|
||||
aimVector[1] = aimVector[1] * self.aimDirection
|
||||
return aimVector
|
||||
end
|
||||
|
||||
function firePosition()
|
||||
local fireOffset = {self.fireOffset[1] * self.aimDirection, self.fireOffset[2]}
|
||||
return vec2.add(mcontroller.position(), activeItem.handPosition(fireOffset))
|
||||
end
|
||||
|
||||
function chainSourcePosition()
|
||||
return vec2.add(mcontroller.position(), activeItem.handPosition(self.ropeOffset))
|
||||
end
|
||||
|
||||
function chainLength()
|
||||
if self.projectileId and world.entityExists(self.projectileId) then
|
||||
return world.magnitude(world.entityPosition(self.projectileId), chainSourcePosition())
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
BIN
assets/devel/items/active/weapons/chainball/chainball.png
Normal file
After Width: | Height: | Size: 320 B |
BIN
assets/devel/items/active/weapons/chainball/chainballicon.png
Normal file
After Width: | Height: | Size: 311 B |
|
@ -0,0 +1,89 @@
|
|||
{
|
||||
"itemName" : "arcsword",
|
||||
"price" : 1200,
|
||||
"level" : 4,
|
||||
"maxStack" : 1,
|
||||
"rarity" : "Rare",
|
||||
"description" : "A ridiculous sword that won't likely make it into the game.",
|
||||
"shortdescription" : "Arcsword",
|
||||
"tooltipKind" : "sword",
|
||||
"category" : "broadsword",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon","melee","broadsword"],
|
||||
|
||||
"inventoryIcon" : "arcsword.png",
|
||||
|
||||
"animation" : "/items/active/weapons/melee/broadsword/combobroadsword.animation",
|
||||
"animationParts" : {
|
||||
"handle" : "",
|
||||
"blade" : "arcsword.png"
|
||||
},
|
||||
"animationCustom" : {
|
||||
"animatedParts" : { "parts" : { "blade" : { "properties" : {
|
||||
"arc1start" : [-0.0625, -0.75],
|
||||
"arc1end" : [-0.0625, 2.75],
|
||||
"arc2start" : [-1.0, -1.25],
|
||||
"arc2end" : [-0.5, 2.75],
|
||||
"arc3start" : [0.875, -1.25],
|
||||
"arc3end" : [0.5, 2.75]
|
||||
}}}},
|
||||
"sounds" : {
|
||||
"fire" : [ "/sfx/melee/swing_broadsword_electric1.ogg", "/sfx/melee/swing_broadsword_electric2.ogg", "/sfx/melee/swing_broadsword_electric3.ogg" ],
|
||||
"fire2" : [ "/sfx/melee/swing_shortsword_electric1.ogg", "/sfx/melee/swing_shortsword_electric2.ogg", "/sfx/melee/swing_shortsword_electric3.ogg" ],
|
||||
"fire3" : [ "/sfx/melee/swing_spear_electric1.ogg", "/sfx/melee/swing_spear_electric2.ogg", "/sfx/melee/swing_spear_electric3.ogg" ]
|
||||
}
|
||||
},
|
||||
"animationScripts" : ["/items/active/effects/lightning.lua"],
|
||||
"scriptedAnimationParameters" : {
|
||||
"lightning" : [
|
||||
// {
|
||||
// "partStartPosition" : ["blade", "arc1start"],
|
||||
// "partEndPosition" : ["blade", "arc1end"],
|
||||
// "color" : [230, 220, 255, 230],
|
||||
// "displacement" : 0.25,
|
||||
// "minDisplacement" : 0.0625,
|
||||
// "forks" : 0,
|
||||
// // "forkAngleRange" : 0.45,
|
||||
// "width" : 1
|
||||
// },
|
||||
{
|
||||
"partStartPosition" : ["blade", "arc2start"],
|
||||
"partEndPosition" : ["blade", "arc2end"],
|
||||
"color" : [230, 220, 255, 230],
|
||||
"displacement" : 0.25,
|
||||
"minDisplacement" : 0.0625,
|
||||
"forks" : 0,
|
||||
// "forkAngleRange" : 0.45,
|
||||
"width" : 1
|
||||
},
|
||||
{
|
||||
"partStartPosition" : ["blade", "arc3start"],
|
||||
"partEndPosition" : ["blade", "arc3end"],
|
||||
"color" : [230, 220, 255, 230],
|
||||
"displacement" : 0.25,
|
||||
"minDisplacement" : 0.0625,
|
||||
"forks" : 0,
|
||||
// "forkAngleRange" : 0.45,
|
||||
"width" : 1
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"scripts" : ["/items/active/weapons/melee/meleeweapon.lua"],
|
||||
|
||||
"elementalType" : "electric",
|
||||
|
||||
"primaryAbilityType" : "broadswordcombo",
|
||||
"primaryAbility" : {
|
||||
"damageConfig" : {
|
||||
"damageSourceKind" : "electricbroadsword",
|
||||
"statusEffects" : ["electrified"]
|
||||
},
|
||||
"fireTime" : 1.0,
|
||||
"baseDps" : 11.5
|
||||
},
|
||||
|
||||
"altAbilityType" : "travelingslash",
|
||||
|
||||
"builder" : "/items/buildscripts/buildunrandweapon.lua"
|
||||
}
|
BIN
assets/devel/items/active/weapons/melee/broadsword/arcsword.png
Normal file
After Width: | Height: | Size: 587 B |
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"itemName" : "smashhammer",
|
||||
"level" : 1,
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "For developer use only",
|
||||
"shortdescription" : "Smash Hammer",
|
||||
"tooltipKind" : "sword",
|
||||
"weaponType" : "Hammer",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon"],
|
||||
|
||||
"inventoryIcon" : "smashhammericon.png",
|
||||
"animation" : "smashhammer.animation",
|
||||
"scripts" : ["smashhammer.lua"]
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"hammer" : {
|
||||
"default" : "smashing",
|
||||
"states" : {
|
||||
"smashing" : {
|
||||
"properties" : {
|
||||
"persistentSound" : "hammertune.ogg"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parts" : {
|
||||
"hammer" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"image" : "smashhammer.png",
|
||||
"offset" : [2, 0],
|
||||
"damageArea" : [[0.25, -1.0], [1.625, -1.0], [1.625, 1.0], [0.25, 1.0]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
function init()
|
||||
self.rotation = 0
|
||||
self.rotationRate = 20.0
|
||||
self.rotationRange = {-0.4, math.pi + 0.2}
|
||||
end
|
||||
|
||||
function update(dt, fireMode, shiftHeld)
|
||||
self.rotation = self.rotation + self.rotationRate * dt
|
||||
if self.rotation < self.rotationRange[1] or self.rotation > self.rotationRange[2] then
|
||||
self.rotationRate = -self.rotationRate
|
||||
self.rotation = self.rotation + self.rotationRate * dt * 2
|
||||
end
|
||||
local damageArea = animator.partPoly("hammer", "damageArea")
|
||||
if damageArea then
|
||||
activeItem.setDamageSources({{
|
||||
poly = damageArea,
|
||||
damage = 50,
|
||||
sourceEntity = activeItem.ownerEntityId(),
|
||||
team = activeItem.ownerTeam(),
|
||||
knockback = 50,
|
||||
rayCheck = true
|
||||
}})
|
||||
end
|
||||
activeItem.setArmAngle(self.rotation)
|
||||
activeItem.setFacingDirection(table.pack(activeItem.aimAngleAndDirection(-1, activeItem.ownerAimPosition()))[2])
|
||||
end
|
After Width: | Height: | Size: 284 B |
After Width: | Height: | Size: 333 B |
After Width: | Height: | Size: 262 B |
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"animationCustom" : {
|
||||
"animatedParts" : { "parts" : {
|
||||
"bayonet" : {
|
||||
"properties" : {
|
||||
"zLevel" : -1,
|
||||
"centered" : true,
|
||||
"offset" : [2.75, -0.25],
|
||||
"image" : "/items/active/weapons/ranged/abilities/generic/bayonet.png"
|
||||
}
|
||||
}
|
||||
}},
|
||||
"sounds" : {
|
||||
"stab" : [ "/sfx/melee/swing_dagger.ogg" ]
|
||||
}
|
||||
},
|
||||
|
||||
"ability" : {
|
||||
"type" : "bayonet",
|
||||
"scripts" : []
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
function setupAbility(altAbilityConfig)
|
||||
local knockbackAttack = altAbilityConfig
|
||||
|
||||
function knockbackAttack.init()
|
||||
-- sb.logInfo("Initializing knockbackAttack")
|
||||
end
|
||||
|
||||
function knockbackAttack.update(dt, fireMode, shiftHeld)
|
||||
if fireMode == "alt"
|
||||
and storage.fireTimer == 0
|
||||
and not world.pointTileCollision(firePosition())
|
||||
and status.overConsumeResource("energy", knockbackAttack.energyCost) then
|
||||
|
||||
storage.fireTimer = knockbackAttack.cooldown -- TODO: maybe use separate cooldown?
|
||||
-- TODO: appropriate projectile
|
||||
animator.setAnimationState("firing", "fire", true)
|
||||
animator.setPartTag("muzzleFlash", "variant", math.random(1, 3))
|
||||
animator.playSound("knockback")
|
||||
animator.burstParticleEmitter("knockback")
|
||||
self.recoilTimer = config.getParameter("recoilTime", 0.08)
|
||||
mcontroller.addMomentum(vec2.mul(aimVector(), -knockbackAttack.momentum))
|
||||
-- TODO: knock back enemies
|
||||
end
|
||||
end
|
||||
|
||||
return knockbackAttack
|
||||
end
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"animationCustom" : {
|
||||
"sounds" : {
|
||||
"knockback" : [ "/sfx/gun/grenadeblast1.ogg", "/sfx/gun/grenadeblast2.ogg", "/sfx/gun/grenadeblast3.ogg" ]
|
||||
},
|
||||
"particleEmitters" : {
|
||||
"knockback" : {
|
||||
"emissionRate" : 10.0,
|
||||
"particles" : [
|
||||
{
|
||||
"particle" : {
|
||||
"type" : "animated",
|
||||
"animation" : "/animations/smoke/smoke.animation",
|
||||
"timeToLive" : 0.8,
|
||||
"initialVelocity" : [10.0, 0.0],
|
||||
"finalVelocity" : [1.0, 2.0],
|
||||
"approach" : [15, 10],
|
||||
"variance" : {
|
||||
"position" : [0, 0.5],
|
||||
"initialVelocity" : [5.0, 3.0],
|
||||
"timeToLive" : 0.2
|
||||
}
|
||||
},
|
||||
"offset" : [2.75, 0.125],
|
||||
"count" : 2
|
||||
},
|
||||
{
|
||||
"particle" : {
|
||||
"type" : "animated",
|
||||
"animation" : "/animations/mediumflame/mediumflame.animation",
|
||||
"timeToLive" : 0.6,
|
||||
"initialVelocity" : [10.0, 0.0],
|
||||
"finalVelocity" : [1.0, 2.0],
|
||||
"approach" : [15, 7],
|
||||
"variance" : {
|
||||
"position" : [0, 0.5],
|
||||
"initialVelocity" : [5.0, 3.0],
|
||||
"timeToLive" : 0.2
|
||||
}
|
||||
},
|
||||
"offset" : [2.75, 0.125],
|
||||
"count" : 4
|
||||
},
|
||||
{
|
||||
"particle" : {
|
||||
"type" : "ember",
|
||||
"color" : [240, 230, 70, 255],
|
||||
"light" : [160, 120, 70],
|
||||
"fade" : 0.9,
|
||||
"initialVelocity" : [20, 0.0],
|
||||
"finalVelocity" : [0, -10.0],
|
||||
"approach" : [10, 20],
|
||||
"timeToLive" : 0.6,
|
||||
"layer" : "middle",
|
||||
"variance" : {
|
||||
"position" : [0, 0.5],
|
||||
"size" : 0.5,
|
||||
"initialVelocity" : [10.0, 4.0],
|
||||
"timeToLive" : 0.2
|
||||
}
|
||||
},
|
||||
"offset" : [2.75, 0.125],
|
||||
"count" : 10
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"ability" : {
|
||||
"type" : "knockback",
|
||||
"scripts" : ["/items/active/weapons/ranged/abilities/shotgun/knockbackattack.lua"],
|
||||
"cooldown" : 2.0,
|
||||
"energyCost" : 30,
|
||||
"momentum" : 20
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [96, 48],
|
||||
"dimensions" : [3, 1],
|
||||
|
||||
"names" : [
|
||||
[ "1", "2", "3" ]
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
require "/scripts/poly.lua"
|
||||
require "/scripts/vec2.lua"
|
||||
|
||||
function setupAbility(altAbilityConfig)
|
||||
local vacuum = WeaponAbility:new()
|
||||
|
||||
function vacuum:init()
|
||||
self.cooldownTimer = 0
|
||||
self:reset()
|
||||
end
|
||||
|
||||
function vacuum:update(dt, fireMode, shiftHeld)
|
||||
WeaponAbility.update(self, dt, fireMode, shiftHeld)
|
||||
|
||||
self.cooldownTimer = math.max(0, self.cooldownTimer - self.dt)
|
||||
|
||||
if self.fireMode == "alt"
|
||||
and not self.active
|
||||
and self.cooldownTimer == 0
|
||||
and not status.resourceLocked("energy") then
|
||||
|
||||
self:setState(self.fire)
|
||||
end
|
||||
end
|
||||
|
||||
function vacuum:fire()
|
||||
self.weapon:setStance(self.stances.fire)
|
||||
-- self.weapon.aimAngle = 0
|
||||
-- self.weapon:updateAim()
|
||||
animator.setAnimationState("vacuum", "active")
|
||||
animator.playSound("vacuumStart")
|
||||
animator.playSound("vacuumLoop", -1)
|
||||
|
||||
local vacuumPoint = {
|
||||
type = "RadialForceRegion",
|
||||
center = animator.partPoint("vacuumCone", "vacuumPoint"),
|
||||
targetRadialVelocity = self.pointSpeed,
|
||||
outerRadius = 1.5,
|
||||
innerRadius = 0.5,
|
||||
controlForce = self.pointForce
|
||||
}
|
||||
|
||||
self.active = true
|
||||
|
||||
while self.fireMode == "alt" and status.overConsumeResource("energy", self.energyUsage * self.dt) do
|
||||
mcontroller.controlModifiers({runningSuppressed = true})
|
||||
|
||||
local forceVector = vec2.rotate(self.coneSpeed, self.weapon.aimAngle)
|
||||
forceVector[1] = forceVector[1] * self.weapon.aimDirection
|
||||
|
||||
local vacuumConeTop = {
|
||||
type = "DirectionalForceRegion",
|
||||
polyRegion = animator.partPoly("vacuumCone", "vacuumPolyTop"),
|
||||
xTargetVelocity = forceVector[1],
|
||||
yTargetVelocity = -forceVector[2],
|
||||
controlForce = self.coneForce
|
||||
}
|
||||
local vacuumConeBottom = {
|
||||
type = "DirectionalForceRegion",
|
||||
polyRegion = animator.partPoly("vacuumCone", "vacuumPolyBottom"),
|
||||
xTargetVelocity = forceVector[1],
|
||||
yTargetVelocity = forceVector[2],
|
||||
controlForce = self.coneForce
|
||||
}
|
||||
activeItem.setItemForceRegions({vacuumConeTop, vacuumConeBottom, vacuumPoint})
|
||||
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
activeItem.setItemForceRegions({})
|
||||
|
||||
animator.setAnimationState("vacuum", "idle")
|
||||
animator.stopAllSounds("vacuumLoop")
|
||||
|
||||
self.cooldownTimer = self.cooldownTime
|
||||
|
||||
self.active = false
|
||||
end
|
||||
|
||||
function vacuum:reset()
|
||||
animator.setAnimationState("vacuum", "idle")
|
||||
animator.stopAllSounds("vacuumLoop")
|
||||
activeItem.setItemForceRegions({})
|
||||
self.active = false
|
||||
end
|
||||
|
||||
function vacuum:uninit()
|
||||
self:reset()
|
||||
end
|
||||
|
||||
return vacuum
|
||||
end
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"animationCustom" : {
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"vacuum" : {
|
||||
"default" : "idle",
|
||||
"states" : {
|
||||
"idle" : { },
|
||||
"active" : {
|
||||
"frames" : 3,
|
||||
"cycle" : 0.3,
|
||||
"mode" : "loop"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parts" : {
|
||||
"vacuumCone" : {
|
||||
"properties" : {
|
||||
"zLevel" : -1,
|
||||
"centered" : true,
|
||||
"offset" : [6.0, 0.0],
|
||||
"transformationGroups" : [ "muzzle" ],
|
||||
"vacuumPolyTop" : [ [-4.5, 0], [-4.5, 1.5], [6.0, 4.0], [6.0, 0] ],
|
||||
"vacuumPolyBottom" : [ [-4.5, -1.5], [-4.5, 0], [6.0, 0], [6.0, -4.0] ],
|
||||
"vacuumPoint" : [-5.0, 0.25]
|
||||
},
|
||||
"partStates" : {
|
||||
"vacuum" : {
|
||||
"idle" : {
|
||||
"properties" : {
|
||||
"image" : ""
|
||||
}
|
||||
},
|
||||
"active" : {
|
||||
"properties" : {
|
||||
"image" : "/items/active/weapons/ranged/abilities/vacuum/vacuum.png:<frame>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sounds" : {
|
||||
"vacuumStart" : [ ],
|
||||
"vacuumLoop" : [ ]
|
||||
}
|
||||
},
|
||||
|
||||
"ability" : {
|
||||
"type" : "vacuum",
|
||||
"scripts" : ["/items/active/weapons/ranged/abilities/vacuum/vacuum.lua"],
|
||||
|
||||
"cooldownTime" : 0.5,
|
||||
|
||||
"coneSpeed" : [-20, 5],
|
||||
"coneForce" : 400,
|
||||
"pointSpeed" : -10,
|
||||
"pointForce" : 500,
|
||||
|
||||
"energyUsage" : 20,
|
||||
|
||||
"stances" : {
|
||||
"fire" : {
|
||||
"armRotation" : 0,
|
||||
"weaponRotation" : 0,
|
||||
"twoHanded" : true,
|
||||
|
||||
"allowRotate" : true,
|
||||
"allowFlip" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"animationCustom" : {
|
||||
"sounds" : {
|
||||
"altFire" : [ "/sfx/gun/blowgun1.ogg", "/sfx/gun/blowgun2.ogg", "/sfx/gun/blowgun3.ogg" ]
|
||||
},
|
||||
"particleEmitters" : {
|
||||
"altMuzzleFlash" : {
|
||||
"active" : false,
|
||||
"emissionRate" : 8,
|
||||
"transformationGroups" : ["muzzle"],
|
||||
"offsetRegion" : [0, 0, 0, 0],
|
||||
"particles" : [ ]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"ability" : {
|
||||
"type" : "vacuumsphere",
|
||||
"scripts" : ["/items/active/weapons/ranged/abilities/altfire.lua"],
|
||||
|
||||
"elementalProjectiles" : {
|
||||
"physical" : "vacuumsphereprimer",
|
||||
"fire" : "vacuumsphereprimer",
|
||||
"electric" : "vacuumsphereprimer",
|
||||
"ice" : "vacuumsphereprimer",
|
||||
"poison" : "vacuumsphereprimer"
|
||||
},
|
||||
"projectileParameters" : {},
|
||||
"projectileCount" : 1,
|
||||
"inaccuracy" : 0,
|
||||
"baseDps" : 0,
|
||||
"energyUsageMultiplier" : 0.5,
|
||||
"fireTime" : 2.0,
|
||||
"fireType" : "auto",
|
||||
|
||||
"stances" : {
|
||||
"fire" : {
|
||||
"duration" : 0.15,
|
||||
"armRotation" : 5,
|
||||
"weaponRotation" : 5,
|
||||
"twoHanded" : true,
|
||||
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
},
|
||||
"cooldown" : {
|
||||
"duration" : 0.15,
|
||||
"armRotation" : 5,
|
||||
"weaponRotation" : 5,
|
||||
"twoHanded" : true,
|
||||
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"itemName" : "delaygun",
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "Meh, I'll kill you later.",
|
||||
"shortdescription" : "Test Delay Rifle",
|
||||
"tooltipKind" : "gun",
|
||||
"weaponType" : "Delay Rifle",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon"],
|
||||
|
||||
"inventoryIcon" : "delaygun.png",
|
||||
|
||||
"animation" : "delaygun.animation",
|
||||
"animationParts" : {
|
||||
"gun" : "delaygun.png",
|
||||
"muzzleFlash" : "muzzleflash.png"
|
||||
},
|
||||
"animationCustom" : {
|
||||
"animatedParts" : { "parts" : {
|
||||
"gun" : { "properties" : {
|
||||
"offset" : [0.75, 0.125]
|
||||
}},
|
||||
"muzzleFlash" : { "properties" : {
|
||||
"offset" : [4.0, 0.375]
|
||||
}}
|
||||
}},
|
||||
"sounds" : {
|
||||
"fire" : [ "/sfx/gun/ar6.ogg" ]
|
||||
}
|
||||
},
|
||||
"fireOffset" : [3.625, 0.375],
|
||||
"aimOffset" : 0, // fireOffset[2] - gun offset - 0.25
|
||||
|
||||
"scripts" : ["delaygun.lua"],
|
||||
|
||||
"level" : 5,
|
||||
"fireTime" : 0.3,
|
||||
"inaccuracy" : 0.01,
|
||||
|
||||
"projectileType" : "delaybullet",
|
||||
"projectileParameters" : {
|
||||
"power" : 3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"firing" : {
|
||||
"default" : "off",
|
||||
"states" : {
|
||||
"off" : {},
|
||||
"fire" : {
|
||||
"frames" : 2,
|
||||
"cycle" : 0.07,
|
||||
"mode" : "transition",
|
||||
"transition" : "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parts" : {
|
||||
"gun" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"image" : "<partImage>",
|
||||
"offset" : [0.5, 0.125]
|
||||
}
|
||||
},
|
||||
"muzzleFlash" : {
|
||||
"properties" : {
|
||||
"zLevel" : -1,
|
||||
"centered" : true,
|
||||
"offset" : [3.625, 0.375],
|
||||
"fullbright" : true
|
||||
},
|
||||
|
||||
"partStates" : {
|
||||
"firing" : {
|
||||
"off" : {
|
||||
"properties" : {
|
||||
"image" : ""
|
||||
}
|
||||
},
|
||||
"fire" : {
|
||||
"properties" : {
|
||||
"image" : "<partImage>:<variant>.<frame>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"lights" : {
|
||||
"muzzleFlash" : {
|
||||
"active" : false,
|
||||
"position" : [3.25, 0.25],
|
||||
"color" : [60, 60, 0]
|
||||
}
|
||||
},
|
||||
|
||||
"sounds" : {
|
||||
"fire" : [ ]
|
||||
}
|
||||
}
|
101
assets/devel/items/active/weapons/ranged/delaygun/delaygun.lua
Normal file
|
@ -0,0 +1,101 @@
|
|||
require "/scripts/vec2.lua"
|
||||
|
||||
function init()
|
||||
-- scale damage and calculate energy cost
|
||||
self.pType = config.getParameter("projectileType")
|
||||
self.pParams = config.getParameter("projectileParameters", {})
|
||||
if not self.pParams.power then
|
||||
local projectileConfig = root.projectileConfig(self.pType)
|
||||
self.pParams.power = projectileConfig.power
|
||||
end
|
||||
self.pParams.power = self.pParams.power * root.evalFunction("weaponDamageLevelMultiplier", config.getParameter("level", 1))
|
||||
self.energyPerShot = 3 * self.pParams.power
|
||||
|
||||
self.fireOffset = config.getParameter("fireOffset")
|
||||
updateAim()
|
||||
|
||||
storage.fireTimer = storage.fireTimer or 0
|
||||
self.recoilTimer = 0
|
||||
|
||||
animator.setPartTag("muzzleFlash", "variant", "1")
|
||||
activeItem.setCursor("/cursors/reticle0.cursor")
|
||||
|
||||
self.activeBullets = {}
|
||||
end
|
||||
|
||||
function activate(fireMode, shiftHeld)
|
||||
if fireMode == "alt" then
|
||||
triggerBullets()
|
||||
end
|
||||
end
|
||||
|
||||
function update(dt, fireMode, shiftHeld)
|
||||
updateAim()
|
||||
updateBullets()
|
||||
|
||||
storage.fireTimer = math.max(storage.fireTimer - dt, 0)
|
||||
self.recoilTimer = math.max(self.recoilTimer - dt, 0)
|
||||
|
||||
if fireMode == "primary"
|
||||
and storage.fireTimer == 0
|
||||
and not world.pointTileCollision(firePosition())
|
||||
and status.overConsumeResource("energy", self.energyPerShot) then
|
||||
|
||||
storage.fireTimer = config.getParameter("fireTime", 1.0)
|
||||
fire()
|
||||
end
|
||||
|
||||
activeItem.setRecoil(self.recoilTimer > 0)
|
||||
animator.setLightActive("muzzleFlash", self.recoilTimer > 0)
|
||||
end
|
||||
|
||||
function fire()
|
||||
self.pParams.powerMultiplier = activeItem.ownerPowerMultiplier()
|
||||
local bulletId = world.spawnProjectile(
|
||||
self.pType,
|
||||
firePosition(),
|
||||
activeItem.ownerEntityId(),
|
||||
aimVector(),
|
||||
false,
|
||||
self.pParams
|
||||
)
|
||||
if bulletId then
|
||||
self.activeBullets[#self.activeBullets + 1] = bulletId
|
||||
end
|
||||
animator.setAnimationState("firing", "fire", true)
|
||||
animator.setPartTag("muzzleFlash", "variant", math.random(1, 3))
|
||||
animator.playSound("fire")
|
||||
self.recoilTimer = config.getParameter("recoilTime", 0.08)
|
||||
end
|
||||
|
||||
function updateAim()
|
||||
self.aimAngle, self.aimDirection = activeItem.aimAngleAndDirection(config.getParameter("aimOffset"), activeItem.ownerAimPosition())
|
||||
activeItem.setArmAngle(self.aimAngle)
|
||||
activeItem.setFacingDirection(self.aimDirection)
|
||||
end
|
||||
|
||||
function updateBullets()
|
||||
local newBullets = {}
|
||||
for i, bullet in ipairs(self.activeBullets) do
|
||||
if world.entityExists(bullet) then
|
||||
newBullets[#newBullets + 1] = bullet
|
||||
end
|
||||
end
|
||||
self.activeBullets = newBullets
|
||||
end
|
||||
|
||||
function triggerBullets()
|
||||
for i, bullet in ipairs(self.activeBullets) do
|
||||
world.callScriptedEntity(bullet, "trigger")
|
||||
end
|
||||
end
|
||||
|
||||
function firePosition()
|
||||
return vec2.add(mcontroller.position(), activeItem.handPosition(self.fireOffset))
|
||||
end
|
||||
|
||||
function aimVector()
|
||||
local aimVector = vec2.rotate({1, 0}, self.aimAngle + sb.nrand(config.getParameter("inaccuracy", 0), 0))
|
||||
aimVector[1] = aimVector[1] * self.aimDirection
|
||||
return aimVector
|
||||
end
|
BIN
assets/devel/items/active/weapons/ranged/delaygun/delaygun.png
Normal file
After Width: | Height: | Size: 350 B |
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [15, 15],
|
||||
"dimensions" : [2, 3],
|
||||
|
||||
"names" : [
|
||||
[ "1.1", "1.2" ],
|
||||
[ "2.1", "2.2" ],
|
||||
[ "3.1", "3.2" ]
|
||||
]
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 379 B |
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"itemName" : "guidedrocketlauncher",
|
||||
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "It's time to rock some wicked trick shots.",
|
||||
"shortdescription" : "Guided Rocket Launcher",
|
||||
"tooltipKind" : "gun",
|
||||
"weaponType" : "Gun",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon"],
|
||||
|
||||
"inventoryIcon" : "guidedrocketlauncher.png",
|
||||
"animation" : "guidedrocketlauncher.animation",
|
||||
"animationCustom" : { },
|
||||
"scripts" : ["guidedrocketlauncher.lua"],
|
||||
"fireOffset" : [2.0, 1.0],
|
||||
|
||||
"level" : 6,
|
||||
"fireTime" : 2.0,
|
||||
"inaccuracy" : 0.02,
|
||||
"projectileType" : "guidedrocket",
|
||||
"projectileParameters" : {
|
||||
"power" : 12
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"reload" : {
|
||||
"default" : "ready",
|
||||
"states" : {
|
||||
"ready" : {},
|
||||
"reload" : {
|
||||
"frames" : 4,
|
||||
"cycle" : 1.0,
|
||||
"mode" : "transition",
|
||||
"transition" : "ready"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parts" : {
|
||||
"gun" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"image" : "guidedrocketlauncher.png",
|
||||
"offset" : [-0.75, 0.75]
|
||||
}
|
||||
},
|
||||
"reloadLights" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"offset" : [-0.5, 0.875],
|
||||
"zLevel" : 1,
|
||||
"fullbright" : true
|
||||
},
|
||||
|
||||
"partStates" : {
|
||||
"reload" : {
|
||||
"ready" : {
|
||||
"properties" : {
|
||||
"image" : "reloadlights.png:ready"
|
||||
}
|
||||
},
|
||||
"reload" : {
|
||||
"properties" : {
|
||||
"image" : "reloadlights.png:reload.<frame>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"particleEmitters" : {
|
||||
"fireParticles" : {
|
||||
"emissionRate" : 10.0,
|
||||
"particles" : [
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"sounds" : {
|
||||
"fire" : [ "/sfx/gun/rocket1.ogg" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
require "/scripts/vec2.lua"
|
||||
|
||||
function init()
|
||||
-- scale damage and calculate energy cost
|
||||
self.pType = config.getParameter("projectileType")
|
||||
self.pParams = config.getParameter("projectileParameters", {})
|
||||
if not self.pParams.power then
|
||||
local projectileConfig = root.projectileConfig(self.pType)
|
||||
self.pParams.power = projectileConfig.power
|
||||
end
|
||||
self.pParams.power = self.pParams.power * root.evalFunction("weaponDamageLevelMultiplier", config.getParameter("level", 1))
|
||||
self.energyPerShot = 3 * self.pParams.power
|
||||
|
||||
self.fireOffset = config.getParameter("fireOffset")
|
||||
updateAim()
|
||||
|
||||
storage.fireTimer = storage.fireTimer or 0
|
||||
self.recoilTimer = 0
|
||||
|
||||
animator.setAnimationRate(1 / config.getParameter("fireTime", 1.0))
|
||||
|
||||
self.activeRockets = {}
|
||||
updateCursor()
|
||||
end
|
||||
|
||||
function update(dt, fireMode, shiftHeld)
|
||||
updateAim()
|
||||
|
||||
storage.fireTimer = math.max(storage.fireTimer - dt, 0)
|
||||
self.recoilTimer = math.max(self.recoilTimer - dt, 0)
|
||||
|
||||
if fireMode ~= "none"
|
||||
and storage.fireTimer <= 0
|
||||
and not world.pointTileCollision(firePosition())
|
||||
and status.overConsumeResource("energy", self.energyPerShot) then
|
||||
|
||||
storage.fireTimer = config.getParameter("fireTime", 1.0)
|
||||
fire()
|
||||
end
|
||||
|
||||
activeItem.setRecoil(self.recoilTimer > 0)
|
||||
|
||||
updateRockets()
|
||||
updateCursor()
|
||||
end
|
||||
|
||||
function updateCursor()
|
||||
if #self.activeRockets > 0 then
|
||||
activeItem.setCursor("/cursors/chargeready.cursor")
|
||||
else
|
||||
activeItem.setCursor("/cursors/reticle0.cursor")
|
||||
end
|
||||
end
|
||||
|
||||
function uninit()
|
||||
for i, rocket in ipairs(self.activeRockets) do
|
||||
world.callScriptedEntity(rocket, "setTarget", nil)
|
||||
end
|
||||
end
|
||||
|
||||
function fire()
|
||||
self.pParams.powerMultiplier = activeItem.ownerPowerMultiplier()
|
||||
local rocketId = world.spawnProjectile(
|
||||
self.pType,
|
||||
firePosition(),
|
||||
activeItem.ownerEntityId(),
|
||||
aimVector(),
|
||||
false,
|
||||
self.pParams
|
||||
)
|
||||
if rocketId then
|
||||
self.activeRockets[#self.activeRockets + 1] = rocketId
|
||||
end
|
||||
animator.setAnimationState("reload", "reload", true)
|
||||
animator.burstParticleEmitter("fireParticles")
|
||||
animator.playSound("fire")
|
||||
self.recoilTimer = config.getParameter("recoilTime", 0.12)
|
||||
end
|
||||
|
||||
function updateAim()
|
||||
self.aimAngle, self.aimDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
|
||||
activeItem.setArmAngle(self.aimAngle)
|
||||
activeItem.setFacingDirection(self.aimDirection)
|
||||
end
|
||||
|
||||
function updateRockets()
|
||||
local newRockets = {}
|
||||
for i, rocket in ipairs(self.activeRockets) do
|
||||
if world.entityExists(rocket) then
|
||||
newRockets[#newRockets + 1] = rocket
|
||||
end
|
||||
end
|
||||
self.activeRockets = newRockets
|
||||
|
||||
for i, rocket in ipairs(self.activeRockets) do
|
||||
world.callScriptedEntity(rocket, "setTarget", activeItem.ownerAimPosition())
|
||||
end
|
||||
end
|
||||
|
||||
function firePosition()
|
||||
return vec2.add(mcontroller.position(), activeItem.handPosition(self.fireOffset))
|
||||
end
|
||||
|
||||
function aimVector()
|
||||
local aimVector = vec2.rotate({1, 0}, self.aimAngle + sb.nrand(config.getParameter("inaccuracy", 0), 0))
|
||||
aimVector[1] = aimVector[1] * self.aimDirection
|
||||
return aimVector
|
||||
end
|
After Width: | Height: | Size: 456 B |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [10, 3],
|
||||
"dimensions" : [1, 5],
|
||||
|
||||
"names" : [
|
||||
[ "reload.1" ],
|
||||
[ "reload.2" ],
|
||||
[ "reload.3" ],
|
||||
[ "reload.4" ],
|
||||
[ "ready" ]
|
||||
]
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 221 B |
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"itemName" : "metagun",
|
||||
"level" : 1,
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "It might be a little too meta.",
|
||||
"shortdescription" : "Meta Gun",
|
||||
"tooltipKind" : "gun",
|
||||
"weaponType" : "Gun",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon"],
|
||||
|
||||
"inventoryIcon" : "metagunicon.png",
|
||||
"animation" : "metagun.animation",
|
||||
"animationCustom" : {},
|
||||
"scripts" : ["metagun.lua"],
|
||||
|
||||
"fireTime" : 0.2,
|
||||
"fireOffset" : [4.5, 0.5],
|
||||
"projectileType" : "delayedplasmaball",
|
||||
"projectileParameters" : {}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"firing" : {
|
||||
"default" : "off",
|
||||
"states" : {
|
||||
"off" : {},
|
||||
"fire" : {
|
||||
"frames" : 2,
|
||||
"cycle" : 0.1,
|
||||
"mode" : "transition",
|
||||
"transition" : "cooldown",
|
||||
"properties" : {
|
||||
"immediateSound" : "/sfx/gun/ar1.ogg"
|
||||
},
|
||||
"frameProperties" : {
|
||||
"stateNudge" : [ [-0.125, 0], [0, 0] ]
|
||||
}
|
||||
},
|
||||
"cooldown" : {
|
||||
"cycle" : 0.1,
|
||||
"mode" : "transition",
|
||||
"transition" : "fire"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parts" : {
|
||||
"gun" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"image" : "metagun.png",
|
||||
"offset" : [1.8, 0.5]
|
||||
}
|
||||
},
|
||||
"muzzleFlash" : {
|
||||
"properties" : {
|
||||
"zLevel" : 1,
|
||||
"centered" : true,
|
||||
"offset" : [5.0, 0.625]
|
||||
},
|
||||
|
||||
"partStates" : {
|
||||
"firing" : {
|
||||
"off" : {
|
||||
"properties" : {
|
||||
"image" : ""
|
||||
}
|
||||
},
|
||||
"fire" : {
|
||||
"properties" : {
|
||||
"image" : "muzzleflash.png:<variant>.<frame>"
|
||||
}
|
||||
},
|
||||
"cooldown" : {
|
||||
"properties" : {
|
||||
"image" : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
assets/devel/items/active/weapons/ranged/metagun/metagun.lua
Normal file
|
@ -0,0 +1,95 @@
|
|||
require "/scripts/vec2.lua"
|
||||
|
||||
function init()
|
||||
-- sb.logInfo("Initializing metagun")
|
||||
|
||||
-- self.recoil = 0
|
||||
-- self.recoilRate = 0
|
||||
|
||||
self.fireOffset = config.getParameter("fireOffset")
|
||||
updateAim()
|
||||
|
||||
self.active = false
|
||||
storage.fireTimer = storage.fireTimer or 0
|
||||
|
||||
animator.setPartTag("muzzleFlash", "variant", "1")
|
||||
end
|
||||
|
||||
function uninit()
|
||||
-- sb.logInfo("Uninitializing metagun")
|
||||
end
|
||||
|
||||
function update(dt, fireMode, shiftHeld)
|
||||
-- sb.logInfo("Updating metagun with fireMode %s and shiftHeld %s", fireMode, shiftHeld)
|
||||
|
||||
updateAim()
|
||||
|
||||
if fireMode == "none" then
|
||||
stopFiring()
|
||||
end
|
||||
|
||||
storage.fireTimer = math.max(storage.fireTimer - dt, 0)
|
||||
|
||||
-- if self.active then
|
||||
-- self.recoilRate = 0
|
||||
-- else
|
||||
-- self.recoilRate = math.max(1, self.recoilRate + (10 * dt))
|
||||
-- end
|
||||
-- self.recoil = math.max(self.recoil - dt * self.recoilRate, 0)
|
||||
|
||||
if self.active and storage.fireTimer <= 0 then
|
||||
if animator.animationState("firing") == "off" then
|
||||
animator.setAnimationState("firing", "fire")
|
||||
end
|
||||
animator.setPartTag("muzzleFlash", "variant", math.random(1, 3))
|
||||
storage.fireTimer = config.getParameter("fireTime", 1.0)
|
||||
|
||||
if not world.pointTileCollision(firePosition()) then
|
||||
world.spawnProjectile(
|
||||
config.getParameter("projectileType"),
|
||||
firePosition(),
|
||||
activeItem.ownerEntityId(),
|
||||
aimVector(),
|
||||
false,
|
||||
config.getParameter("projectileParameters", {})
|
||||
)
|
||||
-- self.recoil = self.recoil + 0.5
|
||||
else
|
||||
animator.setAnimationState("firing", "off")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function activate(fireMode, shiftHeld)
|
||||
-- sb.logInfo("Activating metagun with fireMode %s and shiftHeld %s", fireMode, shiftHeld)
|
||||
|
||||
if not self.active then
|
||||
startFiring()
|
||||
end
|
||||
end
|
||||
|
||||
function startFiring()
|
||||
self.active = true
|
||||
end
|
||||
|
||||
function stopFiring()
|
||||
self.active = false
|
||||
animator.setAnimationState("firing", "off")
|
||||
end
|
||||
|
||||
function updateAim()
|
||||
self.aimAngle, self.aimDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
|
||||
self.aimAngle = self.aimAngle -- + self.recoil * 0.3
|
||||
activeItem.setArmAngle(self.aimAngle)
|
||||
activeItem.setFacingDirection(self.aimDirection)
|
||||
end
|
||||
|
||||
function firePosition()
|
||||
return vec2.add(mcontroller.position(), activeItem.handPosition(self.fireOffset))
|
||||
end
|
||||
|
||||
function aimVector()
|
||||
local aimVector = vec2.rotate({1, 0}, self.aimAngle + sb.nrand(config.getParameter("inaccuracy", 0), 0))
|
||||
aimVector[1] = aimVector[1] * self.aimDirection
|
||||
return aimVector
|
||||
end
|
BIN
assets/devel/items/active/weapons/ranged/metagun/metagun.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/devel/items/active/weapons/ranged/metagun/metagunicon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [15, 15],
|
||||
"dimensions" : [2, 3],
|
||||
|
||||
"names" : [
|
||||
[ "1.1", "1.2" ],
|
||||
[ "2.1", "2.2" ],
|
||||
[ "3.1", "3.2" ]
|
||||
]
|
||||
}
|
||||
}
|
BIN
assets/devel/items/active/weapons/ranged/metagun/muzzleflash.png
Normal file
After Width: | Height: | Size: 379 B |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [10, 3],
|
||||
"dimensions" : [1, 5],
|
||||
|
||||
"names" : [
|
||||
[ "reload.1" ],
|
||||
[ "reload.2" ],
|
||||
[ "reload.3" ],
|
||||
[ "reload.4" ],
|
||||
[ "ready" ]
|
||||
]
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 221 B |
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"itemName" : "testrocket",
|
||||
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "Fwoosh... pchoom!",
|
||||
"shortdescription" : "Rocket Lawnchair",
|
||||
"tooltipKind" : "gun",
|
||||
"weaponType" : "Gun",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon"],
|
||||
|
||||
"inventoryIcon" : "testrocket.png",
|
||||
"animation" : "testrocket.animation",
|
||||
"animationCustom" : {},
|
||||
"scripts" : ["testrocket.lua"],
|
||||
"fireOffset" : [2.0, 1.0],
|
||||
|
||||
"level" : 6,
|
||||
"fireTime" : 2.0,
|
||||
"inaccuracy" : 0.02,
|
||||
"projectileType" : "rocketshell",
|
||||
"projectileParameters" : {
|
||||
"power" : 12
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
"animatedParts" : {
|
||||
"stateTypes" : {
|
||||
"reload" : {
|
||||
"default" : "ready",
|
||||
"states" : {
|
||||
"ready" : {},
|
||||
"reload" : {
|
||||
"frames" : 4,
|
||||
"cycle" : 1.0,
|
||||
"mode" : "transition",
|
||||
"transition" : "ready"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parts" : {
|
||||
"gun" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"image" : "testrocket.png",
|
||||
"offset" : [-0.75, 0.75]
|
||||
}
|
||||
},
|
||||
"reloadLights" : {
|
||||
"properties" : {
|
||||
"centered" : true,
|
||||
"offset" : [-0.5, 0.875],
|
||||
"zLevel" : 1,
|
||||
"fullbright" : true
|
||||
},
|
||||
|
||||
"partStates" : {
|
||||
"reload" : {
|
||||
"ready" : {
|
||||
"properties" : {
|
||||
"image" : "reloadlights.png:ready"
|
||||
}
|
||||
},
|
||||
"reload" : {
|
||||
"properties" : {
|
||||
"image" : "reloadlights.png:reload.<frame>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"particleEmitters" : {
|
||||
"fireParticles" : {
|
||||
"emissionRate" : 10.0,
|
||||
"particles" : [
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
},
|
||||
{
|
||||
"particle" : "rocketbarrelpuff",
|
||||
"offset" : [2, 0.75]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"sounds" : {
|
||||
"fire" : [ "/sfx/gun/rocket_shot.ogg" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
require "/scripts/vec2.lua"
|
||||
|
||||
function init()
|
||||
-- scale damage and calculate energy cost
|
||||
self.pType = config.getParameter("projectileType")
|
||||
self.pParams = config.getParameter("projectileParameters", {})
|
||||
if not self.pParams.power then
|
||||
local projectileConfig = root.projectileConfig(self.pType)
|
||||
self.pParams.power = projectileConfig.power
|
||||
end
|
||||
self.pParams.power = self.pParams.power * root.evalFunction("weaponDamageLevelMultiplier", config.getParameter("level", 1))
|
||||
self.energyPerShot = 3 * self.pParams.power
|
||||
|
||||
self.fireOffset = config.getParameter("fireOffset")
|
||||
updateAim()
|
||||
|
||||
storage.fireTimer = storage.fireTimer or 0
|
||||
self.recoilTimer = 0
|
||||
|
||||
animator.setAnimationRate(1 / config.getParameter("fireTime", 1.0))
|
||||
end
|
||||
|
||||
function update(dt, fireMode, shiftHeld)
|
||||
updateAim()
|
||||
|
||||
storage.fireTimer = math.max(storage.fireTimer - dt, 0)
|
||||
self.recoilTimer = math.max(self.recoilTimer - dt, 0)
|
||||
|
||||
if fireMode ~= "none"
|
||||
and storage.fireTimer <= 0
|
||||
and not world.pointTileCollision(firePosition())
|
||||
and status.overConsumeResource("energy", self.energyPerShot) then
|
||||
|
||||
storage.fireTimer = config.getParameter("fireTime", 1.0)
|
||||
fire()
|
||||
end
|
||||
|
||||
activeItem.setRecoil(self.recoilTimer > 0)
|
||||
end
|
||||
|
||||
function fire()
|
||||
self.pParams.powerMultiplier = activeItem.ownerPowerMultiplier()
|
||||
world.spawnProjectile(
|
||||
self.pType,
|
||||
firePosition(),
|
||||
activeItem.ownerEntityId(),
|
||||
aimVector(),
|
||||
false,
|
||||
self.pParams
|
||||
)
|
||||
animator.setAnimationState("reload", "reload", true)
|
||||
animator.burstParticleEmitter("fireParticles")
|
||||
animator.playSound("fire")
|
||||
self.recoilTimer = config.getParameter("recoilTime", 0.12)
|
||||
end
|
||||
|
||||
function updateAim()
|
||||
self.aimAngle, self.aimDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
|
||||
activeItem.setArmAngle(self.aimAngle)
|
||||
activeItem.setFacingDirection(self.aimDirection)
|
||||
end
|
||||
|
||||
function firePosition()
|
||||
return vec2.add(mcontroller.position(), activeItem.handPosition(self.fireOffset))
|
||||
end
|
||||
|
||||
function aimVector()
|
||||
local aimVector = vec2.rotate({1, 0}, self.aimAngle + sb.nrand(config.getParameter("inaccuracy", 0), 0))
|
||||
aimVector[1] = aimVector[1] * self.aimDirection
|
||||
return aimVector
|
||||
end
|
After Width: | Height: | Size: 456 B |
BIN
assets/devel/items/active/weapons/whip/chainlink.png
Normal file
After Width: | Height: | Size: 218 B |
BIN
assets/devel/items/active/weapons/whip/chainlink2.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
assets/devel/items/active/weapons/whip/chainlink3.png
Normal file
After Width: | Height: | Size: 180 B |
223
assets/devel/items/active/weapons/whip/superwhipcrack.lua
Normal file
|
@ -0,0 +1,223 @@
|
|||
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
|
109
assets/devel/items/active/weapons/whip/testwhip.activeitem
Normal file
|
@ -0,0 +1,109 @@
|
|||
{
|
||||
"itemName" : "testwhip",
|
||||
"level" : 3,
|
||||
"maxStack" : 1,
|
||||
"rarity" : "legendary",
|
||||
"description" : "Get cracking!",
|
||||
"shortdescription" : "Test Whip",
|
||||
"tooltipKind" : "sword",
|
||||
"weaponType" : "Whip",
|
||||
"twoHanded" : true,
|
||||
"itemTags" : ["weapon"],
|
||||
|
||||
"inventoryIcon" : "testwhip.png:idle",
|
||||
"animation" : "whip.animation",
|
||||
"animationParts" : {
|
||||
"weapon" : "testwhip.png",
|
||||
"weaponFullbright" : ""
|
||||
},
|
||||
"animationCustom" : {
|
||||
"particleEmitters" : { "crack" : { "particles" : [ ]}},
|
||||
"sounds" : {
|
||||
"swing" : [ "/sfx/melee/swing_dagger.ogg" ],
|
||||
"crack" : [ "/sfx/gun/pistol1.ogg" ]
|
||||
}
|
||||
},
|
||||
"animationScripts" : [
|
||||
"/items/active/effects/chain.lua"
|
||||
],
|
||||
|
||||
"chain" : {
|
||||
"startOffset" : [0.625, 0.125],
|
||||
"length" : [3, 15],
|
||||
"segmentImage" : "/items/active/weapons/whip/chainlink3.png",
|
||||
"segmentSize" : 0.375
|
||||
},
|
||||
|
||||
"scripts" : [ "whip.lua" ],
|
||||
|
||||
"primaryAbility" : {
|
||||
"scripts" : ["/items/active/weapons/whip/superwhipcrack.lua"],
|
||||
"class" : "SuperWhipCrack",
|
||||
|
||||
"fireTime" : 1.0,
|
||||
"chainDps" : 10.0,
|
||||
"crackDps" : 20.0,
|
||||
|
||||
"damageConfig" : {
|
||||
"statusEffects" : [ ],
|
||||
"damageSourceKind" : "lash",
|
||||
"timeoutGroup" : "primary",
|
||||
"timeout" : 0.3
|
||||
},
|
||||
|
||||
"projectileType" : "whipcrackphysical",
|
||||
"projectileConfig" : {},
|
||||
"stances" : {
|
||||
"idle" : {
|
||||
"armRotation" : -90,
|
||||
"weaponRotation" : 0,
|
||||
"weaponRotationCenter" : [0.0, 0.0],
|
||||
"weaponOffset" : [-0.375, 0.625],
|
||||
|
||||
"allowRotate" : true,
|
||||
"allowFlip" : true
|
||||
},
|
||||
"windup" : {
|
||||
"duration" : 0.07,
|
||||
"armRotation" : 100,
|
||||
"weaponRotation" : 0,
|
||||
"weaponRotationCenter" : [0.0, 0.0],
|
||||
"weaponOffset" : [-0.375, 0.625],
|
||||
|
||||
"allowRotate" : true,
|
||||
"allowFlip" : true
|
||||
},
|
||||
"extend" : {
|
||||
"duration" : 0.07,
|
||||
"armRotation" : 0,
|
||||
"weaponRotation" : -90,
|
||||
"weaponRotationCenter" : [0.0, 0.0],
|
||||
"weaponOffset" : [-0.25, 0.875],
|
||||
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
},
|
||||
"swing" : {
|
||||
"armRotation" : 0,
|
||||
"weaponRotation" : -90,
|
||||
"weaponRotationCenter" : [0.0, 0.0],
|
||||
"weaponOffset" : [-0.25, 0.875],
|
||||
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
},
|
||||
"fire" : {
|
||||
"duration" : 0.1,
|
||||
"armRotation" : 0,
|
||||
"weaponRotation" : -90,
|
||||
"weaponRotationCenter" : [0.0, 0.0],
|
||||
"weaponOffset" : [-0.25, 0.875],
|
||||
|
||||
"allowRotate" : false,
|
||||
"allowFlip" : false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"builder" : "/items/buildscripts/buildwhip.lua"
|
||||
}
|
11
assets/devel/items/active/weapons/whip/testwhip.frames
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"frameGrid" : {
|
||||
"size" : [32, 32],
|
||||
"dimensions" : [4, 2],
|
||||
|
||||
"names" : [
|
||||
[ "idle", "windup.1", "windup.2", "windup.3" ],
|
||||
[ "extend.1", "extend.2", "extend.3", "fire" ]
|
||||
]
|
||||
}
|
||||
}
|
BIN
assets/devel/items/active/weapons/whip/testwhip.png
Normal file
After Width: | Height: | Size: 881 B |