This commit is contained in:
Aria 2025-03-21 22:23:30 +11:00
commit 9c94d113d3
Signed by untrusted user who does not match committer: aria
GPG key ID: 19AB7AA462B8AB3B
10260 changed files with 1237388 additions and 0 deletions

View file

@ -0,0 +1,12 @@
{
"itemName" : "dronecontroller",
"level" : 1,
"rarity" : "rare",
"description" : "Some kinda weird and janky thing.",
"shortdescription" : "Drone Controller",
"twoHanded" : true,
"inventoryIcon" : "dronecontroller.png",
"animation" : "dronecontroller.animation",
"scripts" : ["dronecontroller.lua"]
}

View file

@ -0,0 +1,38 @@
{
"animatedParts" : {
"stateTypes" : {
"heldItem" : {
"default" : "drone",
"states" : {
"drone" : { },
"controller" : { }
}
}
},
"parts" : {
"heldItem" : {
"properties" : {
"centered" : true
},
"partStates" : {
"heldItem" : {
"drone" : {
"properties" : {
"image" : "/projectiles/activeitems/drone/drone.png:0",
"offset" : [0.0, 0.0]
}
},
"controller" : {
"properties" : {
"image" : "dronecontroller.png",
"offset" : [0.5, 0.5]
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,110 @@
require "/scripts/vec2.lua"
function init()
updateDrone()
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)
updateDrone()
updateAim()
updateControl(fireMode)
end
function activate(fireMode, shiftHeld)
if storage.droneId == nil then
launchDrone()
else
self.controlPosition = world.distance(activeItem.ownerAimPosition(), mcontroller.position())
self.droneControlPosition = world.entityPosition(storage.droneId)
end
end
function launchDrone()
local launchAngle = vec2.rotate({1, 0}, self.aimAngle)
launchAngle[1] = launchAngle[1] * self.aimDirection
storage.droneId = world.spawnProjectile(
"drone",
mcontroller.position(),
activeItem.ownerEntityId(),
launchAngle,
false,
{}
)
end
function updateDrone()
if storage.droneId and not (world.entityExists(storage.droneId) and world.callScriptedEntity(storage.droneId, "isDrone")) then
storage.droneId = nil
end
activeItem.setCameraFocusEntity(storage.droneId)
if storage.droneId then
animator.setAnimationState("heldItem", "controller")
else
animator.setAnimationState("heldItem", "drone")
activeItem.setCursor(nil)
end
end
function updateAim()
self.aimAngle, self.aimDirection = activeItem.aimAngleAndDirection(0, activeItem.ownerAimPosition())
if storage.droneId then
activeItem.setArmAngle(0)
else
activeItem.setArmAngle(self.aimAngle)
end
activeItem.setFacingDirection(self.aimDirection)
end
function updateControl(fireMode)
if fireMode ~= "primary" then
self.controlPosition = nil
end
if storage.droneId and self.controlPosition then
local newControlPosition = world.distance(activeItem.ownerAimPosition(), mcontroller.position())
world.callScriptedEntity(storage.droneId, "controlTo", vec2.add(self.droneControlPosition, vec2.sub(newControlPosition, self.controlPosition)))
end
-- if storage.droneId and self.controlPosition then
-- local newControlPosition = world.distance(activeItem.ownerAimPosition(), mcontroller.position())
-- world.callScriptedEntity(storage.droneId, "control", vec2.sub(newControlPosition, self.controlPosition))
-- self.controlPosition = newControlPosition
-- end
-- if storage.droneId and self.controlPosition then
-- local newControlPosition = world.distance(activeItem.ownerAimPosition(), mcontroller.position())
-- local controlOffset = vec2.sub(newControlPosition, self.controlPosition)
-- if vec2.mag(controlOffset) > 1 then
-- if math.abs(controlOffset[1]) > math.abs(controlOffset[2]) then
-- if controlOffset[1] > 0 then
-- world.callScriptedEntity(storage.droneId, "control", {1, 0})
-- activeItem.setCursor("/cursors/joystickright.cursor")
-- else
-- world.callScriptedEntity(storage.droneId, "control", {-1, 0})
-- activeItem.setCursor("/cursors/joystickleft.cursor")
-- end
-- else
-- if controlOffset[2] > 0 then
-- world.callScriptedEntity(storage.droneId, "control", {0, 1})
-- activeItem.setCursor("/cursors/joystickup.cursor")
-- else
-- world.callScriptedEntity(storage.droneId, "control", {0, -1})
-- activeItem.setCursor("/cursors/joystickdown.cursor")
-- end
-- end
-- else
-- activeItem.setCursor("/cursors/joystick.cursor")
-- end
-- elseif storage.droneId then
-- activeItem.setCursor("/cursors/joystick.cursor")
-- end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

View file

@ -0,0 +1,24 @@
{
"itemName" : "gnaremoob",
"level" : 1,
"maxStack" : 1,
"rarity" : "legendary",
"description" : "A ridiculous take on a classic.",
"shortdescription" : "Gnaremoob",
"tooltipKind" : "sword",
"weaponType" : "Boomerang",
"twoHanded" : true,
"inventoryIcon" : "gnaremoob.png",
"animation" : "gnaremoob.animation",
"scripts" : ["gnaremoob.lua"],
"windupTime" : 0.3,
"minFlyTime" : 0.3,
"flySpeed" : 80,
"controlForce" : 35,
"spinRate" : 15.0,
"snapDistance" : 1.5,
"flyCollisionPoly" : [ [-0.75, -1.0], [-0.35, -1.5], [0.35, -1.5], [0.75, -1.0], [0.75, 0.65], [0.35, 1.22], [-0.35, 1.22], [-0.75, 0.65] ]
}

View file

@ -0,0 +1,18 @@
{
"animatedParts" : {
"parts" : {
"gnaremoob" : {
"properties" : {
"centered" : true,
"image" : "gnaremoob.png",
"offset" : [0.5, 1.0],
"rotationGroup" : "gnaremoob"
}
}
}
},
"rotationGroups" : {
"gnaremoob" : {}
}
}

View file

@ -0,0 +1,90 @@
require "/scripts/vec2.lua"
function init()
self.aimAndDir = table.pack(activeItem.aimAngleAndDirection(-1, activeItem.ownerAimPosition()))
idle()
end
function uninit()
mcontroller.setRotation(0)
end
function update(dt, fireMode, shiftHeld)
if self.state == "idle" then
self.aimAndDir = table.pack(activeItem.aimAngleAndDirection(-1, activeItem.ownerAimPosition()))
activeItem.setArmAngle(self.aimAndDir[1])
activeItem.setFacingDirection(self.aimAndDir[2])
if fireMode == "primary" then
windup()
end
end
if self.state == "windup" then
self.stateTimer = math.max(0, self.stateTimer - dt)
if self.stateTimer == 0 then
flyout()
end
end
if self.state == "flyout" then
self.stateTimer = math.max(0, self.stateTimer - dt)
if (self.stateTimer > 0 or not mcontroller.isColliding()) and vec2.mag(mcontroller.velocity()) > 0.1 then
mcontroller.controlParameters({
gravityEnabled=false,
collisionPoly=config.getParameter("flyCollisionPoly"),
standingPoly=config.getParameter("flyCollisionPoly"),
crouchingPoly=config.getParameter("flyCollisionPoly")
})
mcontroller.controlModifiers({movementSuppressed=true})
mcontroller.controlApproachVelocity({0, 0}, config.getParameter("controlForce"))
self.rotation = self.rotation - config.getParameter("spinRate") * dt * self.aimAndDir[2]
mcontroller.setRotation(self.rotation)
else
flyback()
end
end
if self.state == "flyback" then
if world.magnitude(mcontroller.position(), self.returnPosition) > config.getParameter("snapDistance") then
mcontroller.controlParameters({gravityEnabled=false,collisionEnabled=false})
mcontroller.controlModifiers({movementSuppressed=true})
local toTargetVelocity = vec2.mul(vec2.norm(world.distance(self.returnPosition, mcontroller.position())), config.getParameter("flySpeed"))
mcontroller.controlApproachVelocity(toTargetVelocity, config.getParameter("controlForce"))
self.rotation = self.rotation - config.getParameter("spinRate") * dt * self.aimAndDir[2]
mcontroller.setRotation(self.rotation)
else
mcontroller.setVelocity({0, 0})
idle()
end
end
end
function idle()
self.state = "idle"
self.rotation = 0
mcontroller.setRotation(self.rotation)
activeItem.setTwoHandedGrip(false)
end
function windup()
self.state = "windup"
self.stateTimer = config.getParameter("windupTime")
activeItem.setArmAngle(self.aimAndDir[1] + 1.2)
end
function flyout()
self.state = "flyout"
self.stateTimer = config.getParameter("minFlyTime")
self.returnPosition = mcontroller.position()
local toTargetVelocity = vec2.rotate({config.getParameter("flySpeed"), 0}, self.aimAndDir[1])
toTargetVelocity[1] = toTargetVelocity[1] * self.aimAndDir[2]
mcontroller.setVelocity(toTargetVelocity)
activeItem.setTwoHandedGrip(true)
activeItem.setArmAngle(0)
end
function flyback()
self.state = "flyback"
activeItem.setTwoHandedGrip(true)
mcontroller.setVelocity(vec2.mul(mcontroller.velocity(), -1))
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

View file

@ -0,0 +1,40 @@
{
"itemName" : "slimehandgrapple",
"price" : 1000,
"inventoryIcon" : "slimehandgrappleicon.png",
"rarity" : "Legendary",
"maxStack" : 1,
"description" : "Sticky, stretchy, undeniably handy!",
"shortdescription" : "Slime Hand Grapple",
"category" : "Tool",
"fireTime" : 0,
"twoHanded" : false,
"scripts" : ["/items/active/grapplinghooks/grapplinghook.lua"],
"animationScripts" : ["/items/active/effects/renderrope.lua"],
"animation" : "slimehandgrapple.animation",
"fireOffset" : [0, 0.3],
"ropeOffset" : [-0.5, 0.3],
"consumeOnUse" : false,
"projectileType" : "grapplehook",
"projectileParameters" : {
"speed" : 100,
"timeToLive" : 0.25
},
"ropeWidth" : 1.0,
"ropeColor" : [120, 80, 30, 255],
"reelInDistance" : 3.5,
"reelOutLength" : 50,
"breakLength" : 60,
"reelSpeed" : 15,
"controlForce" : 1000,
"groundLagTime" : 0.2
}

View file

@ -0,0 +1,13 @@
{
"animatedParts" : {
"parts" : {
"rope" : {
"properties" : {
"centered" : false,
"image" : "slimehandgrapple.png",
"offset" : [-0.6, -0.5]
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

View file

@ -0,0 +1,31 @@
{
"itemName" : "iceaxe",
"price" : 250,
"inventoryIcon" : "iceaxebig.png",
"rarity" : "Rare",
"maxStack" : 1,
"description" : "An Ice Axe used for climbing.",
"shortdescription" : "Ice Axe",
"category" : "Tool",
"fireTime" : 0.0,
"twoHanded" : false,
"handPosition" : [-2.5, -2.0],
"minLength" : 2.0,
"maxLength" : 2.0,
"hardMaxLength" : 10.0,
"baseLineSegLength" : 10.0,
"launchSpeed" : 0.2,
"windRate" : 0.2,
"energyConsumeRateAnchored" : 0.0,
"energyConsumeRateWinding" : 0.0,
"hookImage" : "/items/tools/iceaxehook.png",
"handleImage" : "/items/tools/iceaxe.png",
"hookOffset" : [-0.5, -1],
"primaryLineColors" : [ [181, 181, 181, 0],
[181, 181, 181, 0] ],
"altLineColors" : [ [181, 181, 181, 0],
[181, 181, 181, 0] ],
"stretchable" : false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

View file

@ -0,0 +1,31 @@
{
"itemName" : "swingingvine",
"price" : 5,
"inventoryIcon" : "swingingvineicon.png",
"rarity" : "Rare",
"maxStack" : 1,
"description" : "Swing around as much as you like!",
"shortdescription" : "Swinging Vine",
"category" : "Tool",
"fireTime" : 0.0,
"twoHanded" : false,
"handPosition" : [-2.5, -2.0],
"minLength" : 0.25,
"maxLength" : 30,
"hardMaxLength" : 33,
"baseLineSegLength" : 4,
"launchSpeed" : 1.5,
"windRate" : 0.05,
"energyConsumeRateAnchored" : 0.8,
"energyConsumeRateWinding" : 0.0,
"hookImage" : "/items/tools/vinehook.png",
"handleImage" : "/items/tools/vinehandle.png",
"hookOffset" : [-0.5, -1],
"primaryLineColors" : [ [72, 130, 47, 255],
[72, 130, 47, 255] ],
"altLineColors" : [ [72, 130, 47, 255],
[72, 130, 47, 255] ],
"stretchable" : false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

View file

@ -0,0 +1,12 @@
{
"frameGrid" : {
"size" : [15, 15],
"dimensions" : [2, 3],
"names" : [
[ "1.1", "1.2" ],
[ "2.1", "2.2" ],
[ "3.1", "3.2" ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

View file

@ -0,0 +1,17 @@
{
"itemName" : "partypopper",
"level" : 1,
"rarity" : "Legendary",
"category" : "toy",
"description" : "It's party time!",
"shortdescription" : "Party Popper",
"twoHanded" : true,
"inventoryIcon" : "partypoppericon.png",
"animation" : "partypopper.animation",
"animationCustom" : {},
"scripts" : ["partypopper.lua"],
"fireTime" : 2.0,
"fireOffset" : [1.0, 0.0]
}

View file

@ -0,0 +1,237 @@
{
"animatedParts" : {
"stateTypes" : {
"firing" : {
"default" : "off",
"states" : {
"off" : {
"properties" : {
"particleEmittersOff" : [ "confetti" ]
}
},
"fire" : {
"frames" : 2,
"cycle" : 0.1,
"mode" : "transition",
"transition" : "confetti",
"properties" : {
"immediateSound" : "/sfx/gun/grenadeblast1.ogg",
"particleEmittersOff" : [ "confetti" ]
},
"frameProperties" : {
"stateNudge" : [ [-0.125, 0], [0, 0] ]
}
},
"confetti" : {
"cycle" : 0.2,
"mode" : "transition",
"transition" : "off",
"properties" : {
"particleEmittersOn" : [ "confetti" ]
}
}
}
}
},
"parts" : {
"gun" : {
"properties" : {
"centered" : true,
"image" : "partypopper.png",
"offset" : [0.0, 0.0]
}
},
"muzzleFlash" : {
"properties" : {
"zLevel" : 1,
"centered" : true,
"offset" : [2.0, 0.0]
},
"partStates" : {
"firing" : {
"off" : {
"properties" : {
"image" : ""
}
},
"fire" : {
"properties" : {
"image" : "muzzleflash.png:<variant>.<frame>"
}
},
"confetti" : {
"properties" : {
"image" : ""
}
}
}
}
}
}
},
"particleEmitters" : {
"confetti" : {
"emissionRate" : 500.0,
"emissionRateVariance" : 0.0,
"active" : true,
"particles" : [
{
// Red, drifting
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [255, 0, 0, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 9.0],
"finalVelocity" : [0.0, -5.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [2, 2.0]
}
}
},
{
// Red, falling fast
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [255, 0, 0, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 7.0],
"finalVelocity" : [0.0, -50.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [5, 2.0]
}
}
},
{
// Green, drifting
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [0, 255, 0, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 9.0],
"finalVelocity" : [0.0, -5.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [2, 2.0]
}
}
},
{
// Green, falling fast
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [0, 255, 0, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 7.0],
"finalVelocity" : [0.0, -50.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [5, 2.0]
}
}
},
{
// Blue, drifting
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [0, 0, 255, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 9.0],
"finalVelocity" : [0.0, -5.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [2, 2.0]
}
}
},
{
// Blue, falling fast
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [0, 0, 255, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 7.0],
"finalVelocity" : [0.0, -50.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [5, 2.0]
}
}
},
{
// White, drifting
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [255, 255, 255, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 9.0],
"finalVelocity" : [0.0, -5.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [2, 2.0]
}
}
},
{
// White, falling fast
"particle" : {
"type" : "ember",
"position" : [1.0, 0],
"size" : 2.0,
"color" : [255, 255, 255, 255],
"light" : [50, 50, 50],
"fade" : 0.9,
"initialVelocity" : [0.0, 7.0],
"finalVelocity" : [0.0, -50.0],
"approach" : [0, 20],
"timeToLive" : 5,
"layer" : "middle",
"variance" : {
"initialVelocity" : [5, 2.0]
}
}
}
]
}
}
}

View file

@ -0,0 +1,83 @@
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()
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
self.recoil = math.pi/2 - self.aimAngle
activeItem.setArmAngle(math.pi/2)
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)
end
self.active = false
end
function activate(fireMode, shiftHeld)
-- sb.logInfo("Activating metagun with fireMode %s and shiftHeld %s", fireMode, shiftHeld)
self.active = true
end
function updateAim()
self.aimAngle, self.aimDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
self.aimAngle = self.aimAngle + self.recoil
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
function holdingItem()
return true
end
function recoil()
return false
end
function outsideOfHand()
return false
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

View file

@ -0,0 +1,56 @@
{
"itemName" : "testshield",
"price" : 100,
"maxStack" : 1,
"rarity" : "common",
"description" : "There's something special between us.",
"shortdescription" : "Test Shield",
"tooltipKind" : "shield",
"twoHanded" : false,
"itemTags" : ["shield"],
"inventoryIcon" : "images/largemetal/1.png:nearidle",
"animation" : "shield.animation",
"animationParts" : {
"shield" : "images/largemetal/1.png"
},
"animationCustom" : {
"sounds" : {
"raiseShield" : [ "/sfx/melee/swing_dagger.ogg" ],
"perfectBlock" : [ "/sfx/melee/shield_block_wood_perfect.ogg" ],
"block" : [ "/sfx/melee/shield_block_wood.ogg" ],
"break" : [ "/sfx/melee/shield_break_wood.ogg" ]
}
},
"scripts" : ["/items/active/shields/shield.lua"],
"minActiveTime" : 0.2,
"forceWalk" : true,
"baseShieldHealth" : 100,
"cooldownTime" : 0.5,
"perfectBlockDirectives" : "?border=2;AACCFFFF;00000000",
"perfectBlockTime" : 0.2,
"knockback" : 10,
"stances" : {
"idle" : {
"armRotation" : -90,
"shieldRotation" : 0,
"allowRotate" : false,
"allowFlip" : true
},
"raised" : {
"armRotation" : 0,
"shieldRotation" : 0,
"allowRotate" : false,
"allowFlip" : true
}
},
"builder" : "/items/buildscripts/buildunrandshield.lua"
}

View file

@ -0,0 +1,17 @@
{
"itemName" : "unrealair",
"level" : 1,
"maxStack" : 1,
"rarity" : "legendary",
"description" : "Made from a skateboard and a Hella Jeff drawing.",
"shortdescription" : "Unreal Air",
"tooltipKind" : "base",
"twoHanded" : false,
"inventoryIcon" : "unrealairicon.png",
"animation" : "unrealair.animation",
"scripts" : ["unrealair.lua"],
"floatSpeed" : 8,
"floatForce" : 70
}

View file

@ -0,0 +1,18 @@
{
"animatedParts" : {
"parts" : {
"board" : {
"properties" : {
"centered" : true,
"image" : "unrealair.png",
"offset" : [-2.0, -0.125],
"rotationGroup" : "board"
}
}
}
},
"rotationGroups" : {
"board" : {}
}
}

View file

@ -0,0 +1,14 @@
function init()
animator.rotateGroup("board", 0.6, true)
end
function uninit()
end
function update(dt, fireMode, shiftHeld)
self.aimAndDir = table.pack(activeItem.aimAngleAndDirection(-1, activeItem.ownerAimPosition()))
activeItem.setFacingDirection(self.aimAndDir[2])
mcontroller.controlApproachYVelocity(config.getParameter("floatSpeed"), config.getParameter("floatForce"))
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

@ -0,0 +1,31 @@
{
"itemName" : "submarinecontrolleryellow",
"level" : 1,
"price" : 25000,
"rarity" : "rare",
"description" : "Create a yellow submarine from stored nanites.",
"shortdescription" : "Yellow Submarine Controller",
"twoHanded" : true,
"maxStack" : 1,
"itemTags" : ["vehiclecontroller"],
"animation" : "vehiclecontroller.animation",
"scripts" : ["vehiclecontroller.lua"],
"animationScripts" : ["vehiclecursor.lua"],
"filled" : true,
"respawnTime" : 1.0,
//=============Item specifc bits.
"vehicleType" : "submarineyellow",
"vehicleBoundingBox" : [-8, -5, 8, 5],
"vehicleImage" : "/vehicles/submarine/submarinewarp.png:warp.4",
"animationParts" : {
"casing" : "submarinecontrolleryellow.png"
},
"inventoryIcon" : "submarinecontrolleryellow.png:full",
"emptyInventoryIcon" : "/items/active/vehiclecontroller/submarinecontrolleryellow.png:empty",
"filledInventoryIcon" : "/items/active/vehiclecontroller/submarinecontrolleryellow.png:full"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

View file

@ -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
}
}
}

View file

@ -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" : [ ]
}
}

View file

@ -0,0 +1,9 @@
{
"frameGrid" : {
"size" : [19, 19],
"dimensions" : [2, 1],
"names" : [
["full", "empty"]
]
}
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

View file

@ -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"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

View file

@ -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"]
}

View file

@ -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]]
}
}
}
}
}

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

View file

@ -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" : []
}
}

View file

@ -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

View file

@ -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
}
}

View file

@ -0,0 +1,10 @@
{
"frameGrid" : {
"size" : [96, 48],
"dimensions" : [3, 1],
"names" : [
[ "1", "2", "3" ]
]
}
}

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -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
}
}
}
}

View file

@ -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
}
}
}
}

View file

@ -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
}
}

View file

@ -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" : [ ]
}
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

View file

@ -0,0 +1,12 @@
{
"frameGrid" : {
"size" : [15, 15],
"dimensions" : [2, 3],
"names" : [
[ "1.1", "1.2" ],
[ "2.1", "2.2" ],
[ "3.1", "3.2" ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

View file

@ -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
}
}

View file

@ -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" ]
}
}

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

View file

@ -0,0 +1,14 @@
{
"frameGrid" : {
"size" : [10, 3],
"dimensions" : [1, 5],
"names" : [
[ "reload.1" ],
[ "reload.2" ],
[ "reload.3" ],
[ "reload.4" ],
[ "ready" ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

View file

@ -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" : {}
}

View file

@ -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" : ""
}
}
}
}
}
}
}
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,12 @@
{
"frameGrid" : {
"size" : [15, 15],
"dimensions" : [2, 3],
"names" : [
[ "1.1", "1.2" ],
[ "2.1", "2.2" ],
[ "3.1", "3.2" ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

View file

@ -0,0 +1,14 @@
{
"frameGrid" : {
"size" : [10, 3],
"dimensions" : [1, 5],
"names" : [
[ "reload.1" ],
[ "reload.2" ],
[ "reload.3" ],
[ "reload.4" ],
[ "ready" ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

View file

@ -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
}
}

View file

@ -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" ]
}
}

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

View 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

View 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"
}

View 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" ]
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B