Modding Help How to make a grapple gun that overlays your hand

Discussion in 'Starbound Modding' started by ShirtyScarab554, Jun 22, 2017.

  1. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    What exactly should I do, apparently the "handGrip" : "wrap", code doesn't work on grapple guns.

    Pictures below vvv
     

    Attached Files:

  2. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    fyi the "what i want" picture is a gun, not a grapple.
     
  3. projectmayhem

    projectmayhem Spaceman Spiff

    Use "handGrip" : "outside" in your activeitem file
     
  4. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    didn't work
     
  5. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    Here is the code.

    Code:
     "scripts" : ["/items/active/grapplinghooks/grapplebeam.lua"],
      "animationScripts" : ["/items/active/effects/renderrope.lua"],
    
      "animation" : "dreadGB.animation",
    
      "fireOffset" : [0, 0.3],
      "ropeOffset" : [-1.75, 0.1],
      "ropeVisualOffset" : [0.75, 0.1],
      "handGrip" : "outside",
     
      "consumeOnUse" : false,
    
      "projectileType" : "grapplebeam",
      "projectileParameters" : {
        "speed" : 150,
        "timeToLive" : 0.35
      },
    
      "ropeWidth" : 1.0,
      "ropeColor" : [4, 255, 246, 80],
    
      "reelInDistance" : 5.5,
      "reelOutLength" : 50,
      "breakLength" : 60,
    
      "minSwingDistance" : 2.0,
    
      "reelSpeed" : 25,
      "controlForce" : 10000,
    
      "groundLagTime" : 0.2
    }
    
     
  6. IHart

    IHart Scruffy Nerf-Herder

    those are a part of weapon.lua. you can copy the parts from there to a lua hook. I'm pretty sure there is no other way.
     
  7. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    I tried that and it didn't seem to work, then again my LUA knowledge is VERY limited, so I probably messed up big time.


    here is what I did.
    Code:
    require "/scripts/util.lua"
    require "/scripts/vec2.lua"
    require "/scripts/rope.lua"
    
    function init()
      self.fireOffset = config.getParameter("fireOffset")
      self.ropeOffset = config.getParameter("ropeOffset")
      self.ropeVisualOffset = config.getParameter("ropeVisualOffset")
      self.consumeOnUse = config.getParameter("consumeOnUse")
      self.projectileType = config.getParameter("projectileType")
      self.projectileParameters = config.getParameter("projectileParameters")
      self.reelInDistance = config.getParameter("reelInDistance")
      self.reelOutLength = config.getParameter("reelOutLength")
      self.breakLength = config.getParameter("breakLength")
      self.minSwingDistance = config.getParameter("minSwingDistance")
      self.reelSpeed = config.getParameter("reelSpeed")
      self.controlForce = config.getParameter("controlForce")
      self.groundLagTime = config.getParameter("groundLagTime")
    
      self.rope = {}
      self.ropeLength = 0
      self.aimAngle = 0
      self.onGround = false
      self.onGroundTimer = 0
      self.facingDirection = 0
      self.projectileId = nil
      self.projectilePosition = nil
      self.anchored = false
      self.previousMoves = {}
      self.previousFireMode = nil
    end
    
    function uninit()
      cancel()
    end
    
    function update(dt, fireMode, shiftHeld, moves)
      if fireMode == "primary" and self.previousFireMode ~= "primary" then
        if self.projectileId then
          cancel()
        elseif status.stat("activeMovementAbilities") < 1 then
          fire()
        end
      end
      self.previousFireMode = fireMode
    
      self.aimAngle, self.facingDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
      activeItem.setFacingDirection(self.facingDirection)
    
      trackGround(dt)
      trackProjectile()
    
      if self.projectileId then
        if world.entityExists(self.projectileId) then
          local position = mcontroller.position()
          local handPosition = vec2.add(position, activeItem.handPosition(self.ropeOffset))
    
          local newRope
          if #self.rope == 0 then
            newRope = {handPosition, self.projectilePosition}
          else
            newRope = copy(self.rope)
            table.insert(newRope, 1, world.nearestTo(newRope[1], handPosition))
            table.insert(newRope, world.nearestTo(newRope[#newRope], self.projectilePosition))
          end
    
          windRope(newRope)
          updateRope(newRope)
    
          if not self.anchored and self.ropeLength > self.reelOutLength then
            cancel()
          end
        else
          cancel()
        end
      end
    
      if self.ropeLength > self.breakLength then
        cancel()
      end
    
      if self.anchored then
        swing(moves)
      else
        activeItem.setArmAngle(self.aimAngle)
      end
    end
    
    function trackProjectile()
      if self.projectileId then
        if world.entityExists(self.projectileId) then
          local position = mcontroller.position()
          self.projectilePosition = vec2.add(world.distance(world.entityPosition(self.projectileId), position), position)
          if not self.anchored then
            self.anchored = world.callScriptedEntity(self.projectileId, "anchored")
          end
        else
          cancel()
        end
      end
    end
    
    function trackGround(dt)
      if mcontroller.onGround() then
        self.onGround = true
        self.onGroundTimer = self.groundLagTime
      else
        self.onGroundTimer = self.onGroundTimer - dt
        if self.onGroundTimer < 0 then
          self.onGround = false
        end
      end
    end
    
    function fire()
      cancel()
    
      local aimVector = vec2.rotate({1, 0}, self.aimAngle)
      aimVector[1] = aimVector[1] * self.facingDirection
    
      self.projectileId = world.spawnProjectile(
          self.projectileType,
          firePosition(),
          activeItem.ownerEntityId(),
          aimVector,
          false,
          self.projectileParameters
        )
    
      if self.projectileId then
        animator.playSound("fire")
        status.setPersistentEffects("grapplingHook"..activeItem.hand(), {{stat = "activeMovementAbilities", amount = 0.5}})
      end
    end
    
    function cancel()
      if self.projectileId and world.entityExists(self.projectileId) then
        world.callScriptedEntity(self.projectileId, "kill")
      end
      if self.projectileId and self.anchored and self.consumeOnUse then
        item.consume(1)
      end
      self.projectileId = nil
      self.projectilePosition = nil
      self.anchored = false
      updateRope({})
      status.clearPersistentEffects("grapplingHook"..activeItem.hand())
    end
    
    function swing(moves)
      local canReel = self.ropeLength > self.reelInDistance or world.magnitude(self.rope[2], mcontroller.position()) > self.reelInDistance
    
      local armAngle = activeItem.aimAngle(self.fireOffset[2], self.rope[2])
      local pullDirection = vec2.withAngle(armAngle)
      activeItem.setArmAngle(self.facingDirection == 1 and armAngle or math.pi - armAngle)
    
      if world.magnitude(self.projectilePosition, mcontroller.position()) < self.minSwingDistance then
        --do nothing
      elseif self.onGround then
        if (moves.up and canReel) or self.ropeLength > self.reelOutLength then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), self.reelSpeed, self.controlForce, true)
        end
      else
        if moves.down and self.ropeLength < self.reelOutLength then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), -self.reelSpeed, self.controlForce, true)
        elseif moves.up and canReel then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), self.reelSpeed, self.controlForce, true)
        elseif pullDirection[2] > 0 or self.ropeLength > self.reelOutLength then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), 0, self.controlForce, true)
        end
    
        if moves.jump and not self.previousMoves.jump then
          if not mcontroller.canJump() then
            mcontroller.controlJump(true)
          end
          cancel()
        end
      end
    
      self.previousMoves = moves
    end
    
    function firePosition()
      local entityPos = mcontroller.position()
      local barrelOffset = activeItem.handPosition(self.fireOffset)
      local barrelPosition = vec2.add(entityPos, barrelOffset)
      local collidePoint = world.lineCollision(entityPos, barrelPosition)
      if collidePoint then
        return vec2.add(entityPos, vec2.mul(barrelOffset, vec2.mag(barrelOffset) - 0.5))
      else
        return barrelPosition
      end
    end
    
    function updateRope(newRope)
      local position = mcontroller.position()
      local previousRopeCount = #self.rope
      self.rope = newRope
      self.ropeLength = 0
    
      activeItem.setScriptedAnimationParameter("ropeOffset", self.ropeVisualOffset)
      for i = 2, #self.rope do
        self.ropeLength = self.ropeLength + world.magnitude(self.rope[i], self.rope[i - 1])
        activeItem.setScriptedAnimationParameter("p" .. i, self.rope[i])
      end
      for i = #self.rope + 1, previousRopeCount do
        activeItem.setScriptedAnimationParameter("p" .. i, nil)
      end
    end
    
    if self.handGrip == "wrap" then
        activeItem.setOutsideOfHand(self:isFrontHand())
      elseif self.handGrip == "embed" then
        activeItem.setOutsideOfHand(not self:isFrontHand())
      elseif self.handGrip == "outside" then
        activeItem.setOutsideOfHand(true)
      elseif self.handGrip == "inside" then
        activeItem.setOutsideOfHand(false)
      end
     
  8. IHart

    IHart Scruffy Nerf-Herder

    oh. is this your grapplebeam.lua?
     
  9. IHart

    IHart Scruffy Nerf-Herder

    This should be within the update function. Right now it's in no function at all. I'm surprised calling the script isnt breaking the game.
     
  10. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    It just causes me to hold the grappel forward and not rotate it.

    I'll try your idea and move it to the update function.
     
  11. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    Well..... it didn't make it overlap my arm
    but the good news is the gun functioned normally.


    here is the new code.
    Code:
    require "/scripts/util.lua"
    require "/scripts/vec2.lua"
    require "/scripts/rope.lua"
    
    function init()
      self.fireOffset = config.getParameter("fireOffset")
      self.ropeOffset = config.getParameter("ropeOffset")
      self.ropeVisualOffset = config.getParameter("ropeVisualOffset")
      self.consumeOnUse = config.getParameter("consumeOnUse")
      self.projectileType = config.getParameter("projectileType")
      self.projectileParameters = config.getParameter("projectileParameters")
      self.reelInDistance = config.getParameter("reelInDistance")
      self.reelOutLength = config.getParameter("reelOutLength")
      self.breakLength = config.getParameter("breakLength")
      self.minSwingDistance = config.getParameter("minSwingDistance")
      self.reelSpeed = config.getParameter("reelSpeed")
      self.controlForce = config.getParameter("controlForce")
      self.groundLagTime = config.getParameter("groundLagTime")
    
      self.rope = {}
      self.ropeLength = 0
      self.aimAngle = 0
      self.onGround = false
      self.onGroundTimer = 0
      self.facingDirection = 0
      self.projectileId = nil
      self.projectilePosition = nil
      self.anchored = false
      self.previousMoves = {}
      self.previousFireMode = nil
    end
    
    function uninit()
      cancel()
    end
    
    function update(dt, fireMode, shiftHeld, moves)
      if fireMode == "primary" and self.previousFireMode ~= "primary" then
        if self.projectileId then
          cancel()
        elseif status.stat("activeMovementAbilities") < 1 then
          fire()
        end
      end
      self.previousFireMode = fireMode
    
      self.aimAngle, self.facingDirection = activeItem.aimAngleAndDirection(self.fireOffset[2], activeItem.ownerAimPosition())
      activeItem.setFacingDirection(self.facingDirection)
    
      trackGround(dt)
      trackProjectile()
    
      if self.projectileId then
        if world.entityExists(self.projectileId) then
          local position = mcontroller.position()
          local handPosition = vec2.add(position, activeItem.handPosition(self.ropeOffset))
    
          local newRope
          if #self.rope == 0 then
            newRope = {handPosition, self.projectilePosition}
          else
            newRope = copy(self.rope)
            table.insert(newRope, 1, world.nearestTo(newRope[1], handPosition))
            table.insert(newRope, world.nearestTo(newRope[#newRope], self.projectilePosition))
          end
    
          windRope(newRope)
          updateRope(newRope)
    
          if not self.anchored and self.ropeLength > self.reelOutLength then
            cancel()
          end
        else
          cancel()
        end
      end
     
       if self.handGrip == "wrap" then
        activeItem.setOutsideOfHand(self:isFrontHand())
      elseif self.handGrip == "embed" then
        activeItem.setOutsideOfHand(not self:isFrontHand())
      elseif self.handGrip == "outside" then
        activeItem.setOutsideOfHand(true)
      elseif self.handGrip == "inside" then
        activeItem.setOutsideOfHand(false)
      end
    
      if self.ropeLength > self.breakLength then
        cancel()
      end
    
      if self.anchored then
        swing(moves)
      else
        activeItem.setArmAngle(self.aimAngle)
      end
    end
    
    function trackProjectile()
      if self.projectileId then
        if world.entityExists(self.projectileId) then
          local position = mcontroller.position()
          self.projectilePosition = vec2.add(world.distance(world.entityPosition(self.projectileId), position), position)
          if not self.anchored then
            self.anchored = world.callScriptedEntity(self.projectileId, "anchored")
          end
        else
          cancel()
        end
      end
    end
    
    function trackGround(dt)
      if mcontroller.onGround() then
        self.onGround = true
        self.onGroundTimer = self.groundLagTime
      else
        self.onGroundTimer = self.onGroundTimer - dt
        if self.onGroundTimer < 0 then
          self.onGround = false
        end
      end
    end
    
    function fire()
      cancel()
    
      local aimVector = vec2.rotate({1, 0}, self.aimAngle)
      aimVector[1] = aimVector[1] * self.facingDirection
    
      self.projectileId = world.spawnProjectile(
          self.projectileType,
          firePosition(),
          activeItem.ownerEntityId(),
          aimVector,
          false,
          self.projectileParameters
        )
    
      if self.projectileId then
        animator.playSound("fire")
        status.setPersistentEffects("grapplingHook"..activeItem.hand(), {{stat = "activeMovementAbilities", amount = 0.5}})
      end
    end
    
    function cancel()
      if self.projectileId and world.entityExists(self.projectileId) then
        world.callScriptedEntity(self.projectileId, "kill")
      end
      if self.projectileId and self.anchored and self.consumeOnUse then
        item.consume(1)
      end
      self.projectileId = nil
      self.projectilePosition = nil
      self.anchored = false
      updateRope({})
      status.clearPersistentEffects("grapplingHook"..activeItem.hand())
    end
    
    function swing(moves)
      local canReel = self.ropeLength > self.reelInDistance or world.magnitude(self.rope[2], mcontroller.position()) > self.reelInDistance
    
      local armAngle = activeItem.aimAngle(self.fireOffset[2], self.rope[2])
      local pullDirection = vec2.withAngle(armAngle)
      activeItem.setArmAngle(self.facingDirection == 1 and armAngle or math.pi - armAngle)
    
      if world.magnitude(self.projectilePosition, mcontroller.position()) < self.minSwingDistance then
        --do nothing
      elseif self.onGround then
        if (moves.up and canReel) or self.ropeLength > self.reelOutLength then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), self.reelSpeed, self.controlForce, true)
        end
      else
        if moves.down and self.ropeLength < self.reelOutLength then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), -self.reelSpeed, self.controlForce, true)
        elseif moves.up and canReel then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), self.reelSpeed, self.controlForce, true)
        elseif pullDirection[2] > 0 or self.ropeLength > self.reelOutLength then
          mcontroller.controlApproachVelocityAlongAngle(vec2.angle(pullDirection), 0, self.controlForce, true)
        end
    
        if moves.jump and not self.previousMoves.jump then
          if not mcontroller.canJump() then
            mcontroller.controlJump(true)
          end
          cancel()
        end
      end
    
      self.previousMoves = moves
    end
    
    function firePosition()
      local entityPos = mcontroller.position()
      local barrelOffset = activeItem.handPosition(self.fireOffset)
      local barrelPosition = vec2.add(entityPos, barrelOffset)
      local collidePoint = world.lineCollision(entityPos, barrelPosition)
      if collidePoint then
        return vec2.add(entityPos, vec2.mul(barrelOffset, vec2.mag(barrelOffset) - 0.5))
      else
        return barrelPosition
      end
    end
    
    function updateRope(newRope)
      local position = mcontroller.position()
      local previousRopeCount = #self.rope
      self.rope = newRope
      self.ropeLength = 0
    
      activeItem.setScriptedAnimationParameter("ropeOffset", self.ropeVisualOffset)
      for i = 2, #self.rope do
        self.ropeLength = self.ropeLength + world.magnitude(self.rope[i], self.rope[i - 1])
        activeItem.setScriptedAnimationParameter("p" .. i, self.rope[i])
      end
      for i = #self.rope + 1, previousRopeCount do
        activeItem.setScriptedAnimationParameter("p" .. i, nil)
      end
    end
     
  12. Nemasys

    Nemasys Cosmic Narwhal

    Wish I had seen this earlier. I've dabbled with this exact thing and iirc all it needs is to add the folowing line of code to the activeitem file:
    Code:
    "handGrip" : "wrap",
    projectmayhem had the right idea, just the wrong value.
     
  13. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    Already tried it, didn't work.
     
  14. Nemasys

    Nemasys Cosmic Narwhal

    Well, if I exercised some reading comprehension, I would have seen that in you OP. Sorry, 'bout that.

    Strange that it's not working for a grappling gun... That's all I had to add for a pistol. I guess there's something to that lua suggestion after all. Unfortunately I only know little about lua. Sorry :(
     
    Last edited: Jun 23, 2017
  15. ShirtyScarab554

    ShirtyScarab554 Subatomic Cosmonaut

    Apparently the Grapple gun uses it's own Lua script, (as seen above) unfortunately I don't know how to take the weapon.lua coding that allows for texture placement and insert it to the grapple.lua.
     

Share This Page