function checkCollision(position)
  local collisionBounds = tech.collisionBounds()
  collisionBounds[1] = collisionBounds[1] - mcontroller.position()[1] + position[1]
  collisionBounds[2] = collisionBounds[2] - mcontroller.position()[2] + position[2]
  collisionBounds[3] = collisionBounds[3] - mcontroller.position()[1] + position[1]
  collisionBounds[4] = collisionBounds[4] - mcontroller.position()[2] + position[2]

  return not world.rectCollision(collisionBounds)
end

function math.distance(coordA, coordB)
  return math.abs(math.sqrt((coordA[1]-coordB[1])^2 + (coordA[2]-coordB[2])^2))
end

function math.midPoint(coordA, coordB)
  local u = { 0.5 * (coordB[1] + coordA[1]), 0.5 * (coordB[2] + coordA[2]) }
  return u
end

function math.getDir(coordA, coordB)
  local dist = math.distance(coordA, coordB)
  local u = {(coordB[1] - coordA[1])/dist,(coordB[2] - coordA[2])/dist}
  return u
end

function randomProjectileLine(startPoint, endPoint, stepSize, projectile, chanceToSpawn)
  local dist = math.distance(startPoint, endPoint)
  local steps = math.floor(dist / stepSize)
  local normX = (endPoint[1] - startPoint[1]) / dist
  local normY = (endPoint[2] - startPoint[2]) / dist
  for i = 0, steps do
    local p1 = { normX * i * stepSize + startPoint[1], normY * i * stepSize + startPoint[2]}
	local p2 = { normX * (i + 1) * stepSize + startPoint[1] + math.random(-1, 1), normY * (i + 1) * stepSize + startPoint[2] + math.random(-1, 1)} 
	if math.random() <= chanceToSpawn then
	  world.spawnProjectile(projectile, math.midPoint(p1, p2), entity.id(), {normX, normY}, false)
	end
  end
  return endPoint
end

function progressiveLineCollision(startPoint, endPoint, stepSize, projectile)
  local dist = math.distance(startPoint, endPoint)
  local steps = math.floor(dist / stepSize)
  local normX = (endPoint[1] - startPoint[1]) / dist
  local normY = (endPoint[2] - startPoint[2]) / dist
  for i = 0, steps do
    local p1 = { normX * i * stepSize + startPoint[1], normY * i * stepSize + startPoint[2]}
	local p2 = { normX * (i + 1) * stepSize + startPoint[1], normY * (i + 1) * stepSize + startPoint[2]}
	if projectile ~= nil then            
	  world.spawnProjectile(projectile, math.midPoint(p1, p2), entity.id(), {normX, normY}, false)
	end
	if world.lineCollision(p1, p2) then
	  return math.midPoint(p1, p2)
	end
  end
  return endPoint
end

function blinkAdjust(position, doPathCheck, doCollisionCheck, doLiquidCheck, doStandCheck)
  local blinkCollisionCheckDiameter = tech.parameter("blinkCollisionCheckDiameter")
  local blinkVerticalGroundCheck = tech.parameter("blinkVerticalGroundCheck")
  local blinkFootOffset = tech.parameter("blinkFootOffset")

  if doPathCheck then
    local collisionBlocks = world.collisionBlocksAlongLine(mcontroller.position(), position, true, 1)
    if #collisionBlocks ~= 0 then
      local diff = world.distance(position, mcontroller.position())
      diff[1] = diff[1] / math.abs(diff[1])
      diff[2] = diff[2] / math.abs(diff[2])

      position = {collisionBlocks[1][1] - diff[1], collisionBlocks[1][2] - diff[2]}
    end
  end

  if doCollisionCheck and not checkCollision(position) then
    local spaceFound = false
    for i = 1, blinkCollisionCheckDiameter * 2 do
      if checkCollision({position[1] + i / 2, position[2] + i / 2}) then
        position = {position[1] + i / 2, position[2] + i / 2}
        spaceFound = true
        break
      end

      if checkCollision({position[1] - i / 2, position[2] + i / 2}) then
        position = {position[1] - i / 2, position[2] + i / 2}
        spaceFound = true
        break
      end

      if checkCollision({position[1] + i / 2, position[2] - i / 2}) then
        position = {position[1] + i / 2, position[2] - i / 2}
        spaceFound = true
        break
      end

      if checkCollision({position[1] - i / 2, position[2] - i / 2}) then
        position = {position[1] - i / 2, position[2] - i / 2}
        spaceFound = true
        break
      end
    end

    if not spaceFound then
      return nil
    end
  end

  if doStandCheck then
    local groundFound = false 
    for i = 1, blinkVerticalGroundCheck * 2 do
      local checkPosition = {position[1], position[2] - i / 2}

      if world.pointCollision(checkPosition, false) then
        groundFound = true
        position = {checkPosition[1], checkPosition[2] + 0.5 - blinkFootOffset}
        break
      end
    end

    if not groundFound then
      return nil
    end
  end

  if doLiquidCheck and (world.liquidAt(position) or world.liquidAt({position[1], position[2] + blinkFootOffset})) then
    return nil
  end

  if doCollisionCheck and not checkCollision(position) then
    return nil
  end

  return position
end

function findRandomBlinkLocation(doCollisionCheck, doLiquidCheck, doStandCheck)
  local randomBlinkTries = tech.parameter("randomBlinkTries")
  local randomBlinkDiameter = tech.parameter("randomBlinkDiameter")

  for i=1,randomBlinkTries do
    local position = mcontroller.position()
    position[1] = position[1] + (math.random() * 2 - 1) * randomBlinkDiameter
    position[2] = position[2] + (math.random() * 2 - 1) * randomBlinkDiameter

    local position = blinkAdjust(position, false, doCollisionCheck, doLiquidCheck, doStandCheck)
    if position then
      return position
    end
  end

  return nil
end

function init()
  data.active = false
  data.fireTimer = 0
  data.fireSecTimer = 0
  tech.setVisible(false)
  tech.rotateGroup("guns", 0, true)
  data.multiJumps = 0
  data.lastJump = false
  data.mode = "none"
  data.timer = 0
  data.targetPosition = nil
  data.grabbed = false
  data.holdingJump = false
  data.ranOut = false
  data.airDashing = false
  data.dashTimer = 0
  data.dashDirection = 0
  data.dashLastInput = 0
  data.dashTapLast = 0
  data.dashTapTimer = 0
  data.aoeLastInput = 0
  data.aoeTapLast = 0
  data.aoeTapTimer = 0
  data.dashAttackfireTimer = 0
  data.dashAttackTimer = 0
  data.dashAttackDirection = 0
  data.dashAttackLastInput = 0
  data.dashAttackTapLast = 0
  data.dashAttackTapTimer = 0
  data.holdingUp = false
  data.holdingDown = false
  data.holdingLeft = false
  data.holdingRight = false
  data.speedMultiplier = 1.1
  data.levitateActivated = false
  data.mechTimer = 0
  data.chargePower = 0
  data.chargeTimer = 0
  data.chargeFireTimer = 0
  data.chargeCharging = false
  data.chargeFiring = false
  data.chargeRecharging = false
  data.projectilesFired = 0
end

function uninit()
  if data.active then
    local mechTransformPositionChange = tech.parameter("mechTransformPositionChange")
    mcontroller.translate({-mechTransformPositionChange[1], -mechTransformPositionChange[2]})
    tech.setParentOffset({0, 0})
    data.active = false
    tech.setVisible(false)
    tech.setParentState("normal")
    tech.setToolUsageSuppressed(false)
    mcontroller.controlFace(nil)
  end
end

function input(args)

  if data.dashTimer > 0 then
    return nil
  end

  local maximumDoubleTapTime = tech.parameter("maximumDoubleTapTime")

  if data.dashTapTimer > 0 then
    data.dashTapTimer = data.dashTapTimer - args.dt
  end
  
    if args.moves["right"] and data.active then
    if data.dashLastInput ~= 1 then
      if data.dashTapLast == 1 and data.dashTapTimer > 0 then
        data.dashTapLast = 0
        data.dashTapTimer = 0
        return "dashRight"
      else
        data.dashTapLast = 1
        data.dashTapTimer = maximumDoubleTapTime
      end
    end
    data.dashLastInput = 1
	
  elseif args.moves["left"] and data.active then
    if data.dashLastInput ~= -1 then
      if data.dashTapLast == -1 and data.dashTapTimer > 0 then
        data.dashTapLast = 0
        data.dashTapTimer = 0
        return "dashLeft"
      else
        data.dashTapLast = -1
        data.dashTapTimer = maximumDoubleTapTime
      end
    end
    data.dashLastInput = -1
  else
    data.dashLastInput = 0
  end
  
  ------------------------
  
  local maximumDoubleTapTime2 = tech.parameter("maximumDoubleTapTime2")
  
  if data.aoeTapTimer > 0 then
    data.aoeTapTimer = data.aoeTapTimer - args.dt
  end
  
    if args.moves["down"] and data.active then
    if data.aoeLastInput ~= 1 then
      if data.aoeTapLast == 1 and data.aoeTapTimer > 0 then
        data.aoeTapLast = 0
        data.aoeTapTimer = 0
        return "mechSecFire"
      else
        data.aoeTapLast = 1
        data.aoeTapTimer = maximumDoubleTapTime2
      end
    end
    data.aoeLastInput = 1
  else
    data.aoeLastInput = 0
  end
  
  if args.moves["jump"] and tech.jumping() then
    data.holdingJump = true
  elseif not args.moves["jump"] then
    data.holdingJump = false
  end
	
  if args.moves["special"] == 1 then
    if data.active then
      return "mechDeactivate"
    else
      return "mechActivate"
    end
	
  elseif args.moves["special"] == 2 and data.active then
    return "blink"
  elseif args.moves[""] and args.moves[""] and args.moves[""] and not data.levitateActivated and data.active then
    return "grab"
  elseif args.moves["down"] and args.moves["right"] and not data.levitateActivated and data.active then
    return "dashAttackRight"
  elseif args.moves["down"] and args.moves["left"] and not data.levitateActivated and data.active then
    return "dashAttackLeft"
  -- elseif args.moves["primaryFire"] and args.moves["altFire"] and data.active then
    -- return "mechMineFire"
  elseif args.moves["primaryFire"] and data.active then
    return "mechFire"
  elseif args.moves["altFire"] and data.active then
    return "mechAltFire"
  elseif args.moves[""] and args.moves[""] and data.active then
    return "mechSecFire"
  elseif args.moves[""] and not tech.canJump() and not data.holdingJump and data.active then
    return "jetpack"
  elseif args.moves["jump"] and not tech.jumping() and not tech.canJump() and not data.lastJump and data.active then
    data.lastJump = true
    return "multiJump"
  else
    data.lastJump = args.moves["jump"]
  end
  
  -- RedOrb
   if args.moves["left"] then
     data.holdingLeft = true
   elseif not args.moves["left"] then
     data.holdingLeft = false
   end

   if args.moves["right"] then
     data.holdingRight = true
   elseif not args.moves["right"] then
     data.holdingRight = false
   end

   if args.moves["up"] then
     data.holdingUp = true
   elseif not args.moves["up"] then
     data.holdingUp = false
   end

   if args.moves["down"] then
     data.holdingDown = true
   elseif not args.moves["down"] then
     data.holdingDown = false
   end
  
   if not args.moves["jump"] and not args.moves["left"]and not args.moves["right"]and not args.moves["up"]and not args.moves["down"] and not tech.canJump() and not data.holdingJump and data.levitateActivated then
     return "levitatehover"
   elseif args.moves["jump"] and args.moves["up"] then
     return "levitate"
   elseif args.moves["left"] and args.moves["right"] and not tech.canJump() and data.levitateActivated then
     return "levitatehover"
   elseif args.moves["up"] and args.moves["down"] and not tech.canJump() and data.levitateActivated then
     return "levitatehover"
   elseif (args.moves["jump"] or args.moves["up"]) and args.moves["left"] and not tech.canJump() and not data.holdingRight and data.levitateActivated then
     return "levitateleftup"
   elseif (args.moves["jump"] or args.moves["up"]) and args.moves["right"] and not tech.canJump() and not data.holdingLeft and data.levitateActivated then
     return "levitaterightup"
   elseif args.moves["down"] and args.moves["left"] and not tech.canJump() and not data.holdingRight and data.levitateActivated then
     return "levitateleftdown"
   elseif args.moves["down"] and args.moves["right"] and not tech.canJump() and not data.holdingLeft and data.levitateActivated then
     return "levitaterightdown"
   elseif args.moves["left"] and not tech.canJump() and not data.holdingRight and data.levitateActivated then
     return "levitateleft"
   elseif args.moves["right"] and not tech.canJump() and not data.holdingLeft and data.levitateActivated then
     return "levitateright"
   elseif args.moves["up"] and not tech.canJump() and not data.holdingDown and data.levitateActivated then
     return "levitateup"
   elseif args.moves["down"] and not tech.canJump() and not data.holdingUp and data.levitateActivated then
     return "levitatedown"
    else
     return nil
   end
  -- RedOrb End

  end




function update(args)
	
  tech.burstParticleEmitter("glowParticles")

  if data.mechTimer > 0 then
	data.mechTimer = data.mechTimer - args.dt
  end

  local dashControlForce = tech.parameter("dashControlForce")
  local dashSpeed = tech.parameter("dashSpeed")
  local dashDuration = tech.parameter("dashDuration")
  local energyUsageDash = tech.parameter("energyUsageDash")

  local usedEnergy = 0
  if args.actions["dashRight"] and data.dashTimer <= 0 and args.availableEnergy > energyUsageDash then
    data.dashTimer = dashDuration
    data.dashDirection = 1
    usedEnergy = energyUsageDash
    data.airDashing = not mcontroller.onGround()
	return energyUsageDash
  elseif args.actions["dashLeft"] and data.dashTimer <= 0 and args.availableEnergy > energyUsageDash then
    data.dashTimer = dashDuration
    data.dashDirection = -1
    usedEnergy = energyUsageDash
    data.airDashing = not mcontroller.onGround()
	return energyUsageDash
  end

  if data.dashTimer > 0 then
    mcontroller.controlApproachXVelocity(dashSpeed * data.dashDirection, dashControlForce, true)

    if data.airDashing then
      mcontroller.controlParameters({gravityEnabled = false})
      mcontroller.controlApproachYVelocity(0, dashControlForce, true)
    end

    if data.dashDirection == -1 then
      tech.moveLeft()
      tech.setFlipped(true)
    else
      tech.moveRight()
      tech.setFlipped(false)
    end
    tech.setAnimationState("dashing", "on")
    tech.setParticleEmitterActive("dashParticles", true)
    data.dashTimer = data.dashTimer - args.dt
  else
    tech.setAnimationState("dashing", "off")
    tech.setParticleEmitterActive("dashParticles", false)
  end
  
  local dashAttackControlForce = tech.parameter("dashAttackControlForce")
  local dashAttackSpeed = tech.parameter("dashAttackSpeed")
  local dashAttackDuration = tech.parameter("dashAttackDuration")
  local energyUsageDashAttack = tech.parameter("energyUsageDashAttack")
  local diffDash = world.distance(tech.aimPosition(), mcontroller.position())
  local aimAngleDash = math.atan2(diffDash[2], diffDash[1])
  local mechDashFireCycle = tech.parameter("mechDashFireCycle")
  local mechDashProjectile = tech.parameter("mechDashProjectile")
  local mechDashProjectileConfig = tech.parameter("mechDashProjectileConfig")
  local flipDash = aimAngleDash > math.pi / 2 or aimAngleDash < -math.pi / 2

  	if flipDash then
      tech.setFlipped(false)
      mcontroller.controlFace(-1)
	  data.dashAttackDirection = -1
    else
      tech.setFlipped(true)
      mcontroller.controlFace(1)
	  data.dashAttackDirection = 1
    end
  
if args.availableEnergy > energyUsageDashAttack and args.actions["dashAttackLeft"] or args.actions["dashAttackRight"] then
    if data.dashAttackTimer <= 0 then
        world.spawnProjectile(mechDashProjectile, tech.anchorPoint("frontDashGunFirePoint"), entity.id(), {math.cos(0), math.sin(0)}, false, mechDashProjectileConfig)
        data.dashAttackTimer = data.dashAttackTimer + mechDashFireCycle
	else
        data.dashAttackTimer = data.dashAttackTimer - args.dt
	end
    
    mcontroller.controlApproachXVelocity(dashAttackSpeed * data.dashAttackDirection, dashAttackControlForce, true)
    tech.setAnimationState("dashingAttack", "on")
    tech.setParticleEmitterActive("dashAttackParticles", true)
  else
    tech.setAnimationState("dashingAttack", "off")
    tech.setParticleEmitterActive("dashAttackParticles", false)
  end

  local energyUsageBlink = tech.parameter("energyUsageBlink")
  local blinkMode = tech.parameter("blinkMode")
  local blinkOutTime = tech.parameter("blinkOutTime")
  local blinkInTime = tech.parameter("blinkInTime")

  if args.actions["blink"] and data.mode == "none" and args.availableEnergy > energyUsageBlink then
    local blinkPosition = nil
    if blinkMode == "random" then
      local randomBlinkAvoidCollision = tech.parameter("randomBlinkAvoidCollision")
      local randomBlinkAvoidMidair = tech.parameter("randomBlinkAvoidMidair")
      local randomBlinkAvoidLiquid = tech.parameter("randomBlinkAvoidLiquid")

      blinkPosition =
        findRandomBlinkLocation(randomBlinkAvoidCollision, randomBlinkAvoidMidair, randomBlinkAvoidLiquid) or
        findRandomBlinkLocation(randomBlinkAvoidCollision, randomBlinkAvoidMidair, false) or
        findRandomBlinkLocation(randomBlinkAvoidCollision, false, false)
    elseif blinkMode == "cursor" then
      blinkPosition = blinkAdjust(tech.aimPosition(), true, true, false, false)
    elseif blinkMode == "cursorPenetrate" then
      blinkPosition = blinkAdjust(tech.aimPosition(), false, true, false, false)
    end

    if blinkPosition then
      data.targetPosition = blinkPosition
      data.mode = "start"
    else
      -- Make some kind of error noise
    end
  end

  if data.mode == "start" then
    tech.setVelocity({0, 0})
    data.mode = "out"
    data.timer = 0

    return energyUsageBlink
  elseif data.mode == "out" then
    tech.setParentState("hidden")
    tech.setVisible(false)
    tech.setAnimationState("blinking", "out")
    tech.setVelocity({0, 0})
    data.timer = data.timer + args.dt

    if data.timer > blinkOutTime then
      tech.setPosition(data.targetPosition)
      data.mode = "in"
      data.timer = 0
    end

    return 0
  elseif data.mode == "in" then
    tech.setParentState("sit")
    tech.setVisible(true)
    tech.setAnimationState("blinking", "in")
    tech.setVelocity({0, 0})
    data.timer = data.timer + args.dt

    if data.timer > blinkInTime then
      data.mode = "none"
    end

    return 0
  end

  local energyUsageJump = tech.parameter("energyUsageJump")
  local multiJumpCount = tech.parameter("multiJumpCount")

  if args.actions["multiJump"] and data.multiJumps < multiJumpCount and args.availableEnergy > energyUsageJump then
    tech.jump(true)
    data.multiJumps = data.multiJumps + 1
    tech.burstParticleEmitter("multiJumpParticles")
    tech.playSound(tech.parameter("sound"))
    return energyUsageJump
  else
    if mcontroller.onGround() or mcontroller.liquidMovement() then
      data.multiJumps = 0
    end
  end

  local energyCostPerSecond = tech.parameter("energyCostPerSecond")
  local energyCostPerSecondPrim = tech.parameter("energyCostPerSecondPrim")
  local energyCostPerSecondSec = tech.parameter("energyCostPerSecondSec")
  local energyCostPerSecondAlt = tech.parameter("energyCostPerSecondAlt")
  local mechCustomMovementParameters = tech.parameter("mechCustomMovementParameters")
  local mechTransformPositionChange = tech.parameter("mechTransformPositionChange")
  local parentOffset = tech.parameter("parentOffset")
  local mechCollisionTest = tech.parameter("mechCollisionTest")
  local mechAimLimit = tech.parameter("mechAimLimit") * math.pi / 180
  local mechFrontRotationPoint = tech.parameter("mechFrontRotationPoint")
  local mechFrontFirePosition = tech.parameter("mechFrontFirePosition")
  local mechBackRotationPoint = tech.parameter("mechBackRotationPoint")
  local mechBackFirePosition = tech.parameter("mechBackFirePosition")
  local mechFireCycle = tech.parameter("mechFireCycle")
  local mechProjectile = tech.parameter("mechProjectile")
  local mechProjectileConfig = tech.parameter("mechProjectileConfig")
  local mechAltFireCycle = tech.parameter("mechAltFireCycle")
  local mechAltProjectile = tech.parameter("mechAltProjectile")
  local mechAltProjectile2 = tech.parameter("mechAltProjectile2")
  local mechAltProjectile3 = tech.parameter("mechAltProjectile3")
  local mechAltProjectile4 = tech.parameter("mechAltProjectile4")
  local mechAltProjectileConfig = tech.parameter("mechAltProjectileConfig")
  local mechSecFireCycle = tech.parameter("mechSecFireCycle")
  local mechSecProjectile = tech.parameter("mechSecProjectile")
  local mechSecProjectileConfig = tech.parameter("mechSecProjectileConfig")
  local mechGunBeamMaxRange = tech.parameter("mechGunBeamMaxRange")
  local mechGunBeamStep = tech.parameter("mechGunBeamStep")
  local mechGunBeamSmokeProkectile = tech.parameter("mechGunBeamSmokeProkectile")
  local mechGunBeamEndProjectile = tech.parameter("mechGunBeamEndProjectile")
  local mechGunBeamUpdateTime = tech.parameter("mechGunBeamUpdateTime")
  local mechTransform = tech.parameter("mechTransform")
  local mechMineFireCycle = tech.parameter("mechMineFireCycle")
  local mechMineDistance = tech.parameter("mechMineDistance")
  local mechMineEnergy = tech.parameter("mechMineEnergy")
  local chargingSound = tech.parameter("chargingSound")
  local chargeFireSound = tech.parameter("chargeFireSound")
  local primaryFireSound = tech.parameter("primaryFireSound")
  local aoeFireSound = tech.parameter("aoeFireSound")
  
  local mechActiveSide = nil
	  if tech.setFlipped(true) then
	    mechActiveSide = "left"
	  elseif tech.setFlipped(false) then
	    mechActiveSide = "right"
	  end  
  
  if data.active and (args.actions["mechDeactivate"] or energyCostPerSecond * args.dt > args.availableEnergy) then
    data.mechTimer = mechTransform
	tech.setAnimationState("transform", "out")
  end

  if not data.active and args.actions["mechActivate"] then
    mechCollisionTest[1] = mechCollisionTest[1] + mcontroller.position()[1]
    mechCollisionTest[2] = mechCollisionTest[2] + mcontroller.position()[2]
    mechCollisionTest[3] = mechCollisionTest[3] + mcontroller.position()[1]
    mechCollisionTest[4] = mechCollisionTest[4] + mcontroller.position()[2]
	
    if not world.rectCollision(mechCollisionTest) then
      tech.burstParticleEmitter("mechActivateParticles")
      mcontroller.translate(mechTransformPositionChange)
      tech.setVisible(true)
      tech.setParentState("sit")
	  tech.setAnimationState("transform", "in")
      tech.setToolUsageSuppressed(true)
      data.active = true
    else
      -- Make some kind of error noise
    end
  elseif data.active and data.mechTimer < 0 then
    data.mechTimer = 0
    tech.burstParticleEmitter("mechDeactivateParticles")
    mcontroller.translate({-mechTransformPositionChange[1], -mechTransformPositionChange[2]})
    tech.setVisible(false)
    tech.setParentState("normal")
    tech.setToolUsageSuppressed(false)
    tech.setParentOffset({0, 0})
    data.active = false
  end

  mcontroller.controlFace(nil)
  if data.active then
    local diff = world.distance(tech.aimPosition(), mcontroller.position())
    local aimAngle = math.atan2(diff[2], diff[1])
    local flip = aimAngle > math.pi / 2 or aimAngle < -math.pi / 2

    mcontroller.controlParameters(mechCustomMovementParameters)
    if flip then
      tech.setFlipped(false)
      local nudge = tech.appliedOffset()
      tech.setParentOffset({-parentOffset[1] - nudge[1] - 1.0, parentOffset[2] + nudge[2] + 3.0})
      mcontroller.controlFace(-1)

      if aimAngle > 0 then
        aimAngle = math.max(aimAngle, math.pi - mechAimLimit)
      else
        aimAngle = math.min(aimAngle, -math.pi + mechAimLimit)
      end

      tech.rotateGroup("guns", math.pi + aimAngle)
    else
      tech.setFlipped(true)
      local nudge = tech.appliedOffset()
      tech.setParentOffset({parentOffset[1] + nudge[1] + 1.0, parentOffset[2] + nudge[2] + 3.0})
      mcontroller.controlFace(1)

      if aimAngle > 0 then
        aimAngle = math.min(aimAngle, mechAimLimit)
      else
        aimAngle = math.max(aimAngle, -mechAimLimit)
      end

      tech.rotateGroup("guns", -aimAngle)
    end

 if not mcontroller.onGround() then
      if mcontroller.velocity()[2] > 0 then
	  	if args.actions["mechFire"] then
		tech.setAnimationState("movement", "jumpAttack")
		elseif args.actions["mechAltFire"] then
      	tech.setAnimationState("movement", "jumpAttack")
		elseif args.actions["mechSecFire"] then
      	tech.setAnimationState("movement", "jumpAttack")
		elseif args.actions["mechMineFire"] then
      	tech.setAnimationState("movement", "mine")
		else
		tech.setAnimationState("movement", "jump")
		end  
      else
	  if args.actions["mechFire"] then
        tech.setAnimationState("movement", "fallAttack")
        elseif args.actions["mechAltFire"] then
      	tech.setAnimationState("movement", "fallAttack")
		elseif args.actions["mechSecFire"] then
      	tech.setAnimationState("movement", "fallAttack")
		elseif args.actions["mechMineFire"] then
      	tech.setAnimationState("movement", "mine")
		else
		tech.setAnimationState("movement", "fall")
		end
      end
    elseif mcontroller.walking() or mcontroller.running() then
      if flip and mcontroller.movingDirection() == 1 or not flip and mcontroller.movingDirection() == -1 then
	  if args.actions["mechFire"] then
        tech.setAnimationState("movement", "backWalkAttack")
        elseif args.actions["mechAltFire"] then
      	tech.setAnimationState("movement", "backWalkAttack")
		elseif args.actions["mechSecFire"] then
      	tech.setAnimationState("movement", "backWalkAttack")
		elseif args.actions["mechMineFire"] then
      	tech.setAnimationState("movement", "mine")
		elseif args.actions["dashAttackRight"] then
      	tech.setAnimationState("movement", "backWalkDash")
		elseif args.actions["dashAttackLeft"] then
      	tech.setAnimationState("movement", "backWalkDash")
		else
		tech.setAnimationState("movement", "backWalk")
		end
      else
	  	if args.actions["mechFire"] then
        tech.setAnimationState("movement", "walkAttack")
		elseif args.actions["mechAltFire"] then
      	tech.setAnimationState("movement", "walkAttack")
		elseif args.actions["mechSecFire"] then
      	tech.setAnimationState("movement", "walkAttack")
		elseif args.actions["mechMineFire"] then
      	tech.setAnimationState("movement", "mine")
		elseif args.actions["dashAttackRight"] then
      	tech.setAnimationState("movement", "walkDash")
		elseif args.actions["dashAttackLeft"] then
      	tech.setAnimationState("movement", "walkDash")
		else
		tech.setAnimationState("movement", "walk")
		end
      end
    else
	if args.actions["mechFire"] then
      tech.setAnimationState("movement", "idleAttack")
	  elseif args.actions["mechAltFire"] then
      tech.setAnimationState("movement", "idleAttack")
	  elseif args.actions["mechSecFire"] then
      tech.setAnimationState("movement", "idleAttack")
	  elseif args.actions["mechMineFire"] then
      tech.setAnimationState("movement", "mine")
	  else
	  tech.setAnimationState("movement", "idle")
	  end
    end

    if args.actions["mechFire"] and args.availableEnergy > energyCostPerSecondPrim then
      if data.fireTimer <= 0 then
        world.spawnProjectile(mechProjectile, tech.anchorPoint("frontGunFirePoint"), entity.id(), {math.cos(aimAngle), math.sin(aimAngle)}, false, mechProjectileConfig)
		tech.playSound( primaryFireSound )
        data.fireTimer = data.fireTimer + mechFireCycle
        tech.setAnimationState("frontFiring", "fire")
	  else
        local oldFireTimer = data.fireTimer
        data.fireTimer = data.fireTimer - args.dt
        if oldFireTimer > mechFireCycle / 2 and data.fireTimer <= mechFireCycle / 2 then
        end
      end
	  return energyCostPerSecondPrim
    end
	
	if not args.actions["mechFire"] then
	
	end
	
--Charged Fire

	local mechChargeIncrement = tech.parameter("mechChargeIncrement")
	local energyCostPerCharge = tech.parameter("energyCostPerCharge")
	local mechChargeTime = tech.parameter("mechChargeTime")
	local mechChargeRatio = tech.parameter("mechChargeRatio")

	if args.actions["mechAltFire"] and not data.chargeFiring and not data.chargeRecharging then
	  if not data.chargeCharging then
		if args.availableEnergy > energyCostPerCharge then
		  data.chargeCharging = true
		  data.chargePower = 1
		  tech.playSound( chargingSound )
		  data.chargeTimer = mechChargeIncrement
		end
      elseif data.chargeTimer > 0 then
	    data.chargeTimer = data.chargeTimer - args.dt
	  elseif data.chargeTimer <= 0 and data.chargePower < 4 and args.availableEnergy > energyCostPerCharge then
	    data.chargePower = data.chargePower + 1
		tech.playSound( chargingSound )
		data.chargeTimer = mechChargeIncrement
      end

	  if data.chargePower == 1 then
		tech.setAnimationState("frontAltFiring", "fireAlt")
	  elseif data.chargePower == 2 then
		tech.setAnimationState("frontAltFiring", "fireAlt2")
	  elseif data.chargePower == 3 then
		tech.setAnimationState("frontAltFiring", "fireAlt3")
	  elseif data.chargePower == 4 then
		tech.setAnimationState("frontAltFiring", "fireAlt4")
	  end	  
	  
	elseif data.chargeCharging and not args.actions["mechAltFire"] and not data.chargeRecharging then
	  data.chargeFireTimer = mechChargeTime * ( 1 + data.chargePower * mechChargeRatio )
	  data.chargeCharging = false
	  data.chargeFiring = true
	  
	elseif data.chargeFiring and data.chargeFireTimer > 0 and not data.chargeRecharging then
	  data.chargeFireTimer = data.chargeFireTimer - args.dt
	  
	  if data.chargePower == 1 and args.availableEnergy > energyCostPerCharge * 1 then
	    ----------------------------------------------
		data.projectilesFired = 1
		world.spawnProjectile(mechAltProjectile, tech.anchorPoint("frontAltGunFirePoint"), entity.id(), {math.cos(aimAngle), math.sin(aimAngle)}, false, mechAltProjectileConfig)
		tech.playSound( chargeFireSound )
		data.chargeRecharging = true
		----------------------------------------------
	  elseif data.chargePower == 2 and  args.availableEnergy > energyCostPerCharge * 2 then
	    ----------------------------------------------
		data.projectilesFired = 2
		world.spawnProjectile(mechAltProjectile2, tech.anchorPoint("frontAltGunFirePoint"), entity.id(), {math.cos(aimAngle), math.sin(aimAngle)}, false, mechAltProjectileConfig)
		tech.playSound( chargeFireSound )
		data.chargeRecharging = true
		----------------------------------------------
	  elseif data.chargePower == 3 and  args.availableEnergy > energyCostPerCharge * 3 then
	    ----------------------------------------------
		data.projectilesFired = 3
		world.spawnProjectile(mechAltProjectile3, tech.anchorPoint("frontAltGunFirePoint"), entity.id(), {math.cos(aimAngle), math.sin(aimAngle)}, false, mechAltProjectileConfig)
		tech.playSound( chargeFireSound )
		data.chargeRecharging = true
		----------------------------------------------
	  elseif data.chargePower == 4 and  args.availableEnergy > energyCostPerCharge * 4 then
	    ----------------------------------------------
		data.projectilesFired = 4
		world.spawnProjectile(mechAltProjectile4, tech.anchorPoint("frontAltGunFirePoint"), entity.id(), {math.cos(aimAngle), math.sin(aimAngle)}, false, mechAltProjectileConfig)
		tech.playSound( chargeFireSound )
		data.chargeRecharging = true
		----------------------------------------------
	  end	  
	  
	elseif data.chargeFiring and data.chargeFireTimer <= 0 and not data.chargeRecharging then
	  data.chargeFiring = false
	  data.chargeRecharging = true
	  
	elseif data.chargeRecharging and data.chargeFireTimer > 0 then
	  data.chargeFireTimer = data.chargeFireTimer - args.dt
	  
	elseif data.chargeRecharging and data.chargeFireTimer <= 0 then
	  
	  data.chargePower = 0
	  data.chargeFireTimer = 0
	  data.chargeCharging = false
	  data.chargeTimer = 0
	  data.chargeFiring = false
	  data.chargeRecharging = false

	  return energyCostPerCharge * data.projectilesFired
	end
	
--Charged Fire End
	
	-- if args.actions["mechAltFire"] and args.availableEnergy > energyCostPerSecondAlt then
      -- if data.fireTimer <= 0 then
        -- world.spawnProjectile(mechAltProjectile, tech.anchorPoint("frontAltGunFirePoint"), entity.id(), {math.cos(aimAngle), math.sin(aimAngle)}, false, mechAltProjectileConfig)
        -- data.fireTimer = data.fireTimer + mechAltFireCycle
        -- tech.setAnimationState("frontAltFiring", "fireAlt")
      -- else
        -- local oldFireTimer = data.fireTimer
        -- data.fireTimer = data.fireTimer - args.dt
        -- if oldFireTimer > mechAltFireCycle / 2 and data.fireTimer <= mechAltFireCycle / 2 then
        -- end
      -- end
	  -- return energyCostPerSecondAlt
    -- end
	
	if args.actions["mechSecFire"] and args.availableEnergy > energyCostPerSecondSec then
	world.spawnProjectile(mechSecProjectile, tech.anchorPoint("frontSecGunFirePoint"), entity.id(), {math.cos(0), math.sin(0)}, false, mechAltProjectileConfig)
	tech.playSound( aoeFireSound )
    tech.setAnimationState("frontSecFiring", "fireSec")
	  return energyCostPerSecondSec
    end
	
	if args.actions["mechMineFire"] then
      if data.fireTimer <= 0 and mechMineEnergy <= args.availableEnergy then
        if math.abs(world.distance(tech.aimPosition(),mcontroller.position())[1]) <= mechMineDistance then
          local x,y = tech.aimPosition()[1],tech.aimPosition()[2]
          local tilelist = {{x-1,y+2},{x,y+2},{x+1,y+2},{x-1,y-2},{x,y-2},{x+1,y-2}}
          for i = 1,5 do 
            table.insert(tilelist,{x-3+i,y-1})
            table.insert(tilelist,{x-3+i,y})
            table.insert(tilelist,{x-3+i,y+1})
          end
          world.damageTiles(tilelist, "foreground", mcontroller.position(), "blockish", 5)
          data.fireTimer = data.fireTimer + mechMineFireCycle
        end
      else
        data.fireTimer = data.fireTimer - args.dt
      end
    end
  
   local levitateSpeed = tech.parameter("levitateSpeed")
   local levitateControlForce = tech.parameter("levitateControlForce")
   local energyUsagePerSecondLevitate = tech.parameter("energyUsagePerSecondLevitate")
   local energyUsagelevitate = energyUsagePerSecondLevitate * args.dt

   if args.availableEnergy < energyUsagelevitate then
     data.ranOut = true
   elseif mcontroller.onGround() or mcontroller.liquidMovement() then
     data.ranOut = false
   end

   if args.actions["levitate"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(levitateSpeed, levitateControlForce, true)
	 data.levitateActivated = true
     return energyUsagelevitate
   elseif args.actions["levitatehover"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(0, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(0, levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitateleft"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
		 mcontroller.controlApproachYVelocity(0, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(-(levitateSpeed*data.speedMultiplier), levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitateleftup"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(levitateSpeed, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(-(levitateSpeed*data.speedMultiplier), levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitateleftdown"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(-(levitateSpeed)*0.5, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(-(levitateSpeed*data.speedMultiplier), levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitateright"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
		 mcontroller.controlApproachYVelocity(0, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(levitateSpeed*data.speedMultiplier, levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitaterightup"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(levitateSpeed, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(levitateSpeed*data.speedMultiplier, levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitaterightdown"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(-(levitateSpeed)*0.5, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(levitateSpeed*data.speedMultiplier, levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitateup"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(levitateSpeed, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(0, levitateControlForce, true)
     return energyUsagelevitate
   elseif args.actions["levitatedown"] and not data.ranOut then
     tech.setAnimationState("levitate", "on")
     mcontroller.controlApproachYVelocity(-(levitateSpeed)*0.5, levitateControlForce, true)
		 mcontroller.controlApproachXVelocity(0, levitateControlForce, true)
     return energyUsagelevitate
   else
	 data.levitateActivated = false
     tech.setAnimationState("levitate", "off")
     return 0
   end

    --return energyCostPerSecond * args.dt
  end

  return 0
end
