Advertisement
Guest User

NPC Mech support

a guest
Jun 23rd, 2019
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.99 KB | None | 0 0
  1. -- vanilla SB modularmech.lua update() with NPC Mechs support by LoPhatKao
  2. -- changes begin on line 124 of this document
  3.  
  4. function update(dt)
  5.   -- despawn if owner has left the world
  6.   if not self.ownerEntityId or world.entityType(self.ownerEntityId) ~= "player" then
  7.     despawn()
  8.   end
  9.  
  10.   if self.explodeTimer then
  11.     self.explodeTimer = math.max(0, self.explodeTimer - dt)
  12.     if self.explodeTimer == 0 then
  13.       local params = {
  14.         referenceVelocity = mcontroller.velocity(),
  15.         damageTeam = {
  16.           type = "enemy",
  17.           team = 9001
  18.         }
  19.       }
  20.       world.spawnProjectile(self.explodeProjectile, mcontroller.position(), nil, nil, false, params)
  21.       animator.playSound("explode")
  22.       vehicle.destroy()
  23.     else
  24.       local fade = 1 - (self.explodeTimer / self.explodeTime)
  25.       animator.setGlobalTag("directives", string.format("?fade=FCC93C;%.1f", fade))
  26.     end
  27.     return
  28.   elseif self.despawnTimer then
  29.     self.despawnTimer = math.max(0, self.despawnTimer - dt)
  30.     if self.despawnTimer == 0 then
  31.       vehicle.destroy()
  32.     else
  33.       local multiply, fade, light
  34.       if self.despawnTimer > 0.5 * self.despawnTime then
  35.         fade = 1.0 - (self.despawnTimer - 0.5 * self.despawnTime) / (0.5 * self.despawnTime)
  36.         light = fade
  37.         multiply = 255
  38.       else
  39.         fade = 1.0
  40.         light = self.despawnTimer / (0.5 * self.despawnTime)
  41.         multiply = math.floor(255 * light)
  42.       end
  43.       animator.setGlobalTag("directives", string.format("?multiply=ffffff%02x?fade=ffffff;%.1f", multiply, fade))
  44.       animator.setLightActive("deployLight", true)
  45.       animator.setLightColor("deployLight", {light, light, light})
  46.     end
  47.     return
  48.   end
  49.  
  50.   setFlightMode(world.gravity(mcontroller.position()) == 0)
  51.  
  52.   -- update positions and movement
  53.  
  54.   self.boostDirection = {0, 0}
  55.  
  56.   local newPosition = mcontroller.position()
  57.   local newVelocity = mcontroller.velocity()
  58.  
  59.   -- decrement timers
  60.  
  61.   self.stepSoundLimitTimer = math.max(0, self.stepSoundLimitTimer - dt)
  62.   self.landingBobTimer = math.max(0, self.landingBobTimer - dt)
  63.   self.jumpBoostTimer = math.max(0, self.jumpBoostTimer - dt)
  64.   self.fallThroughTimer = math.max(0, self.fallThroughTimer - dt)
  65.   self.onGroundTimer = math.max(0, self.onGroundTimer - dt)
  66.  
  67.   -- track onGround status
  68.   if mcontroller.onGround() then
  69.     self.onGroundTimer = self.onGroundTime
  70.   end
  71.   local onGround = self.onGroundTimer > 0
  72.  
  73.   -- hit ground
  74.  
  75.   if onGround and not self.lastOnGround and newVelocity[2] - self.lastVelocity[2] > self.landingBobThreshold then
  76.     self.landingBobTimer = self.landingBobTime
  77.     triggerStepSound()
  78.   end
  79.  
  80.   -- update driver
  81.  
  82.   local driverId = vehicle.entityLoungingIn("seat")
  83.   if driverId and not self.driverId then
  84.     animator.setAnimationState("power", "activate")
  85.   elseif self.driverId and not driverId then
  86.     animator.setAnimationState("power", "deactivate")
  87.   end
  88.   self.driverId = driverId
  89.  
  90.   -- read controls or do deployment
  91.  
  92.   local newControls = {}
  93.   local oldControls = self.lastControls
  94.  
  95.   if self.deploy then
  96.     self.deploy.fadeTimer = math.max(0.0, self.deploy.fadeTimer - dt)
  97.     self.deploy.deployTimer = math.max(0.0, self.deploy.deployTimer - dt)
  98.  
  99.     -- visual fade in
  100.     local multiply = math.floor(math.min(1.0, (self.deploy.fadeTime - self.deploy.fadeTimer) / self.deploy.fadeInTime) * 255)
  101.     local fade = math.min(1.0, self.deploy.fadeTimer / self.deploy.fadeOutTime)
  102.     animator.setGlobalTag("directives", string.format("?multiply=ffffff%02x?fade=ffffff;%.1f", multiply, fade))
  103.     animator.setLightActive("deployLight", true)
  104.     animator.setLightColor("deployLight", {fade, fade, fade})
  105.  
  106.     -- boost to a stop
  107.     if self.deploy.deployTimer < self.deploy.boostTime then
  108.       mcontroller.approachYVelocity(0, math.abs(self.deploy.initialVelocity) / self.deploy.boostTime * mcontroller.parameters().mass)
  109.       boost({0, util.toDirection(-self.deploy.initialVelocity)})
  110.     end
  111.  
  112.     if self.deploy.deployTimer == 0.0 then
  113.       self.deploy = nil
  114.       animator.setLightActive("deployLight", false)
  115.     end
  116.   else
  117.     self.damageFlashTimer = math.max(0, self.damageFlashTimer - dt)
  118.     if self.damageFlashTimer == 0 then
  119.       animator.setGlobalTag("directives", "")
  120.     end
  121.  
  122.     local walking = false
  123.     if self.driverId then
  124.       -- for k, _ in pairs(self.lastControls) do
  125.         -- newControls[k] = vehicle.controlHeld("seat", k)
  126.       -- end
  127.  
  128.       -- self.aimPosition = vehicle.aimPosition("seat")
  129.             self.aimPosition,newControls = readMechControls(newControls)
  130.  --- NPC Mechs - read controls from external function - allows override for faked input
  131.  
  132.       if newControls.Special1 and not self.lastControls.Special1 then
  133.         animator.playSound("horn")
  134.       end
  135.  
  136.       if self.flightMode then
  137.         if newControls.jump then
  138.           local vel = mcontroller.velocity()
  139.           if vel[1] ~= 0 or vel[2] ~= 0 then
  140.             mcontroller.approachVelocity({0, 0}, self.flightControlForce)
  141.             boost(vec2.mul(vel, -1))
  142.           end
  143.         else
  144.           if newControls.right then
  145.             mcontroller.approachXVelocity(self.flightControlSpeed, self.flightControlForce)
  146.             boost({1, 0})
  147.           end
  148.  
  149.           if newControls.left then
  150.             mcontroller.approachXVelocity(-self.flightControlSpeed, self.flightControlForce)
  151.             boost({-1, 0})
  152.           end
  153.  
  154.           if newControls.up then
  155.             mcontroller.approachYVelocity(self.flightControlSpeed, self.flightControlForce)
  156.             boost({0, 1})
  157.           end
  158.  
  159.           if newControls.down then
  160.             mcontroller.approachYVelocity(-self.flightControlSpeed, self.flightControlForce)
  161.             boost({0, -1})
  162.           end
  163.         end
  164.       else
  165.         if not newControls.jump then
  166.           self.fallThroughSustain = false
  167.         end
  168.  
  169.         if onGround then
  170.           if newControls.right and not newControls.left then
  171.             mcontroller.approachXVelocity(self.groundSpeed, self.groundControlForce)
  172.             walking = true
  173.           end
  174.  
  175.           if newControls.left and not newControls.right then
  176.             mcontroller.approachXVelocity(-self.groundSpeed, self.groundControlForce)
  177.             walking = true
  178.           end
  179.  
  180.           if newControls.jump and self.jumpBoostTimer > 0 then
  181.             mcontroller.setYVelocity(self.jumpVelocity)
  182.           elseif newControls.jump and not self.lastControls.jump then
  183.             if newControls.down then
  184.               self.fallThroughTimer = self.fallThroughTime
  185.               self.fallThroughSustain = true
  186.             else
  187.               jump()
  188.             end
  189.           else
  190.             self.jumpBoostTimer = 0
  191.           end
  192.         else
  193.           local controlSpeed = self.jumpBoostTimer > 0 and self.jumpAirControlSpeed or self.airControlSpeed
  194.           local controlForce = self.jumpBoostTimer > 0 and self.jumpAirControlForce or self.airControlForce
  195.  
  196.           if newControls.right then
  197.             mcontroller.approachXVelocity(controlSpeed, controlForce)
  198.             boost({1, 0})
  199.           end
  200.  
  201.           if newControls.left then
  202.             mcontroller.approachXVelocity(-controlSpeed, controlForce)
  203.             boost({-1, 0})
  204.           end
  205.  
  206.           if newControls.jump then
  207.             if self.jumpBoostTimer > 0 then
  208.               mcontroller.setYVelocity(self.jumpVelocity)
  209.             end
  210.           else
  211.             self.jumpBoostTimer = 0
  212.           end
  213.         end
  214.       end
  215.  
  216.       self.facingDirection = world.distance(self.aimPosition, mcontroller.position())[1] > 0 and 1 or -1
  217.  
  218.       self.lastControls = newControls
  219.     else
  220.       for k, _ in pairs(self.lastControls) do
  221.         self.lastControls[k] = false
  222.       end
  223.  
  224.       newControls = self.lastControls
  225.       oldControls = self.lastControls
  226.  
  227.       self.aimPosition = nil
  228.     end
  229.   end
  230.  
  231.   -- update damage team (don't take damage without a driver)
  232.   -- also anything else that depends on a driver's presence
  233.  
  234.   if self.driverId then
  235.     vehicle.setDamageTeam(world.entityDamageTeam(self.driverId))
  236.     vehicle.setInteractive(false)
  237.     vehicle.setForceRegionEnabled("itemMagnet", true)
  238.     vehicle.setDamageSourceEnabled("bumperGround", not self.flightMode)
  239.     animator.setLightActive("activeLight", true)
  240.   else
  241.     vehicle.setDamageTeam({type = "ghostly"})
  242.     vehicle.setInteractive(true)
  243.     vehicle.setForceRegionEnabled("itemMagnet", false)
  244.     vehicle.setDamageSourceEnabled("bumperGround", false)
  245.     animator.setLightActive("activeLight", false)
  246.     animator.setLightActive("boostLight", false)
  247.   end
  248.  
  249.   -- decay and check energy
  250.  
  251.   if self.driverId then
  252.     storage.energy = math.max(0, storage.energy - self.energyDrain * dt)
  253.   end
  254.  
  255.   local inLiquid = world.liquidAt(mcontroller.position())
  256.   if inLiquid then
  257.     local liquidName = root.liquidName(inLiquid[1])
  258.     if self.liquidVulnerabilities[liquidName] then
  259.       storage.energy = math.max(0, storage.energy - self.liquidVulnerabilities[liquidName].energyDrain * dt)
  260.       if storage.energy == 0 then
  261.         explode()
  262.         return
  263.       end
  264.  
  265.       if not self.liquidVulnerabilities[liquidName].warned then
  266.         world.sendEntityMessage(self.ownerEntityId, "queueRadioMessage", self.liquidVulnerabilities[liquidName].message)
  267.         self.liquidVulnerabilities[liquidName].warned = true
  268.       end
  269.     end
  270.   end
  271.  
  272.   if storage.energy == 0 then
  273.     despawn()
  274.     return
  275.   end
  276.  
  277.   -- set appropriate movement parameters for walking/falling conditions
  278.  
  279.   if not self.flightMode then
  280.     if walking ~= self.lastWalking then
  281.       self.lastWalking = walking
  282.       if self.lastWalking then
  283.         mcontroller.applyParameters(self.walkingMovementSettings)
  284.       else
  285.         mcontroller.resetParameters(self.movementSettings)
  286.       end
  287.     end
  288.  
  289.     if self.fallThroughTimer > 0 or self.fallThroughSustain then
  290.       mcontroller.applyParameters({ignorePlatformCollision = true})
  291.     else
  292.       mcontroller.applyParameters({ignorePlatformCollision = false})
  293.     end
  294.   end
  295.  
  296.   -- flip to match facing direction
  297.  
  298.   animator.setFlipped(self.facingDirection < 0)
  299.  
  300.   -- compute leg cycle
  301.  
  302.   if onGround then
  303.     local newLegCycle = self.legCycle
  304.     newLegCycle = self.legCycle + ((newPosition[1] - self.lastPosition[1]) * self.facingDirection) / (4 * self.legRadius)
  305.  
  306.     if math.floor(self.legCycle * 2) ~= math.floor(newLegCycle * 2) then
  307.       triggerStepSound()
  308.     end
  309.  
  310.     self.legCycle = newLegCycle
  311.   end
  312.  
  313.   -- animate legs, leg joints, and hips
  314.  
  315.   if self.flightMode then
  316.     -- legs stay locked in place for flight
  317.   else
  318.     local legs = {
  319.       front = {},
  320.       back = {}
  321.     }
  322.     local legCycleOffset = 0
  323.  
  324.     for _, legSide in pairs({"front", "back"}) do
  325.       local leg = legs[legSide]
  326.  
  327.       leg.offset = legOffset(self.legCycle + legCycleOffset)
  328.       legCycleOffset = legCycleOffset + 0.5
  329.  
  330.       leg.onGround = leg.offset[2] <= 0
  331.  
  332.       -- put foot down when stopped
  333.       if not walking and math.abs(newVelocity[1]) < 0.5 then
  334.         leg.offset[2] = 0
  335.         leg.onGround = true
  336.       end
  337.  
  338.       local footGroundOffset = findFootGroundOffset(leg.offset, self[legSide .. "Foot"])
  339.       if footGroundOffset then
  340.         leg.offset[2] = leg.offset[2] + footGroundOffset
  341.       else
  342.         leg.offset[2] = self.reachGroundDistance[2]
  343.         leg.onGround = false
  344.       end
  345.  
  346.       animator.setAnimationState(legSide .. "Foot", leg.onGround and "flat" or "tilt")
  347.       animator.resetTransformationGroup(legSide .. "Leg")
  348.       animator.translateTransformationGroup(legSide .. "Leg", leg.offset)
  349.       animator.resetTransformationGroup(legSide .. "LegJoint")
  350.       animator.translateTransformationGroup(legSide .. "LegJoint", {0.6 * leg.offset[1], 0.7 * leg.offset[2]})
  351.     end
  352.  
  353.     if math.abs(newVelocity[1]) < 0.5 and math.abs(self.lastVelocity[1]) >= 0.5 then
  354.       triggerStepSound()
  355.     end
  356.  
  357.     animator.resetTransformationGroup("hips")
  358.     local hipsOffset = math.max(-0.625, math.min(0, math.min(legs.front.offset[2] + 0.75, legs.back.offset[2] + 0.75)))
  359.     animator.translateTransformationGroup("hips", {0, hipsOffset})
  360.   end
  361.  
  362.   -- update and animate arms
  363.  
  364.   local chains = {}
  365.   for _, arm in pairs({"left", "right"}) do
  366.     local fireControl = (arm == "left") and "PrimaryFire" or "AltFire"
  367.  
  368.     animator.resetTransformationGroup(arm .. "Arm")
  369.     animator.resetTransformationGroup(arm .. "ArmFlipper")
  370.  
  371.     self[arm .. "Arm"]:updateBase(dt, self.driverId, newControls[fireControl], oldControls[fireControl], self.aimPosition, self.facingDirection)
  372.     self[arm .. "Arm"]:update(dt)
  373.  
  374.     if self[arm.."Arm"].renderChain then
  375.       table.insert(chains, self[arm.."Arm"].chain)
  376.     end
  377.  
  378.     if self.facingDirection < 0 then
  379.       animator.translateTransformationGroup(arm .. "ArmFlipper", {(arm == "right") and self.armFlipOffset or -self.armFlipOffset, 0})
  380.     end
  381.   end
  382.   vehicle.setAnimationParameter("chains", chains)
  383.  
  384.   -- animate boosters and boost flames
  385.  
  386.   animator.resetTransformationGroup("boosters")
  387.  
  388.   if self.jumpBoostTimer > 0 then
  389.     boost({0, 1})
  390.   end
  391.  
  392.   if self.boostDirection[1] == 0 and self.boostDirection[2] == 0 then
  393.     animator.setAnimationState("boost", "idle")
  394.     animator.setLightActive("boostLight", false)
  395.   else
  396.     local stateTag = "boost"
  397.     if self.boostDirection[2] > 0 then
  398.       stateTag = stateTag .. "N"
  399.     elseif self.boostDirection[2] < 0 then
  400.       stateTag = stateTag .. "S"
  401.     end
  402.     if self.boostDirection[1] * self.facingDirection > 0 then
  403.       stateTag = stateTag .. "E"
  404.     elseif self.boostDirection[1] * self.facingDirection < 0 then
  405.       stateTag = stateTag .. "W"
  406.     end
  407.     animator.setAnimationState("boost", stateTag)
  408.     animator.setLightActive("boostLight", true)
  409.   end
  410.  
  411.   -- animate bobbing and landing
  412.  
  413.   animator.resetTransformationGroup("body")
  414.   if self.flightMode then
  415.     local newFlightOffset = {
  416.         math.max(-self.flightOffsetClamp, math.min(self.boostDirection[1] * self.facingDirection * self.flightOffsetFactor, self.flightOffsetClamp)),
  417.         math.max(-self.flightOffsetClamp, math.min(self.boostDirection[2] * self.flightOffsetFactor, self.flightOffsetClamp))
  418.       }
  419.  
  420.     self.currentFlightOffset = vec2.div(vec2.add(newFlightOffset, vec2.mul(self.currentFlightOffset, 4)), 5)
  421.  
  422.     animator.translateTransformationGroup("boosters", self.currentFlightOffset)
  423.     animator.translateTransformationGroup("rightArm", self.currentFlightOffset)
  424.     animator.translateTransformationGroup("leftArm", self.currentFlightOffset)
  425.   elseif not onGround or self.jumpBoostTimer > 0 then
  426.     -- TODO: bob while jumping?
  427.   elseif self.landingBobTimer == 0 then
  428.     local bodyCycle = (self.legCycle * 2) % 1
  429.     local bodyOffset = {0, self.walkBobMagnitude * math.sin(math.pi * bodyCycle)}
  430.     animator.translateTransformationGroup("body", bodyOffset)
  431.  
  432.     local boosterCycle = ((self.legCycle * 2) - self.boosterBobDelay) % 1
  433.     local boosterOffset = {0, self.walkBobMagnitude * math.sin(math.pi * boosterCycle)}
  434.     animator.translateTransformationGroup("boosters", boosterOffset)
  435.  
  436.     local armCycle = ((self.legCycle * 2) - self.armBobDelay) % 1
  437.     local armOffset = {0, self.walkBobMagnitude * math.sin(math.pi * armCycle)}
  438.     animator.translateTransformationGroup("rightArm", self.rightArm.bobLocked and boosterOffset or armOffset)
  439.     animator.translateTransformationGroup("leftArm", self.leftArm.bobLocked and boosterOffset or armOffset)
  440.   else
  441.     -- TODO: make this less complicated
  442.     local landingCycleTotal = 1.0 + math.max(self.boosterBobDelay, self.armBobDelay)
  443.     local landingCycle = landingCycleTotal * (1 - (self.landingBobTimer / self.landingBobTime))
  444.  
  445.     local bodyCycle = math.max(0, math.min(1.0, landingCycle))
  446.     local bodyOffset = {0, -self.landingBobMagnitude * math.sin(math.pi * bodyCycle)}
  447.     animator.translateTransformationGroup("body", bodyOffset)
  448.  
  449.     local legJointOffset = {0, 0.5 * bodyOffset[2]}
  450.     animator.translateTransformationGroup("frontLegJoint", legJointOffset)
  451.     animator.translateTransformationGroup("backLegJoint", legJointOffset)
  452.  
  453.     local boosterCycle = math.max(0, math.min(1.0, landingCycle + self.boosterBobDelay))
  454.     local boosterOffset = {0, -self.landingBobMagnitude * 0.5 * math.sin(math.pi * boosterCycle)}
  455.     animator.translateTransformationGroup("boosters", boosterOffset)
  456.  
  457.     local armCycle = math.max(0, math.min(1.0, landingCycle + self.armBobDelay))
  458.     local armOffset = {0, -self.landingBobMagnitude * 0.25 * math.sin(math.pi * armCycle)}
  459.     animator.translateTransformationGroup("rightArm", self.rightArm.bobLocked and boosterOffset or armOffset)
  460.     animator.translateTransformationGroup("leftArm", self.leftArm.bobLocked and boosterOffset or armOffset)
  461.   end
  462.  
  463.   self.lastPosition = newPosition
  464.   self.lastVelocity = newVelocity
  465.   self.lastOnGround = onGround
  466. end
  467.  
  468.  
  469. function readMechControls(newControls)
  470.       for k, _ in pairs(self.lastControls) do
  471.         newControls[k] = vehicle.controlHeld("seat", k)
  472.       end
  473.  
  474.       return vehicle.aimPosition("seat"),newControls
  475. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement