Advertisement
Kijan

FW Canon

May 21st, 2020
1,253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.98 KB | None | 0 0
  1. fx = {Fire = 0, Idle = 0, Move = 1}
  2.  
  3. settings = {
  4.     barrelOffset  = {x=    0, y= 1.15, z= -1.8},
  5.     muzzleOffset  = {x= -0.2, y= 5.2 , z=  0.8},
  6.     muzzleOffset2 = {x=  0.2, y= 5.6 , z=  2.1},
  7.     minSpin   = 60,
  8.     maxSpin   = 120,
  9.     errorColor = {1, 0.4, 0.4},
  10.     infoColor = {0.8, 0.8, 1},
  11.     useRecoil = false,
  12. }
  13.  
  14. help = {
  15.     lowPower        = "Power is too low. Check object description",
  16.     nothingSelected = "You don't have anything selected",
  17.     objtoolarge     = "%s is too large to be auto-loaded",
  18.     unreadablePower = "Couldn't read Power from description. Example: [00CED1]Power: 25-32[ffffff]",
  19.     buttonFireLabel = "Fire!",
  20.     buttonLoadLabel = "Load",
  21.     buttonFire      = "Fire!",
  22.     buttonLoad      = "Load selected objects into the cannon.\nIf nothing is selected, repeat the previous payload.",
  23. }
  24.  
  25. --Runtime
  26. rotationAtLaunch     = {}
  27. posAtLaunch          = {}
  28. memorizedObjects     = {}
  29. nrOfMemorizedObjects = {}
  30. isFiring = false
  31.  
  32. function onload()
  33.     CreateButtons()
  34.     self.tooltip = false
  35. end
  36.  
  37. function FireCannon(obj, color)
  38.  
  39.     if isFiring then return end
  40.  
  41.     local power, launchVelocity = CalcPowerAndLaunchVelocity(color)
  42.  
  43.     if power > 0 then
  44.         isFiring = true
  45.         self.AssetBundle.playTriggerEffect(fx.Fire)
  46.         LaunchBarrelContents(launchVelocity, color)
  47.         AfterFire()
  48.     end
  49.  
  50. end
  51.  
  52. function AddObjects(obj,color)
  53.  
  54.     local barrelContents = GetBarrelContents()
  55.     local selectedObjects = Player[color].getSelectedObjects()
  56.     local firableObjects, nrOfFirable = GetFirableObjects(selectedObjects)
  57.  
  58.     if nrOfFirable > 0 then
  59.         memorizedObjects[color] = firableObjects
  60.         nrOfMemorizedObjects[color] = nrOfFirable
  61.     else
  62.         firableObjects = memorizedObjects[color] or {}
  63.         nrOfFirable = nrOfMemorizedObjects[color] or 0
  64.     end
  65.  
  66.     if nrOfFirable == 0 then
  67.         firableObjects = memorizedObjects["no color"] or {}
  68.         nrOfFirable = nrOfMemorizedObjects["no color"] or 0
  69.     end
  70.  
  71.     if nrOfFirable == 0 then broadcastToColor(help.nothingSelected, color, settings.infoColor) return end
  72.  
  73.     local objectsToMove = {}
  74.     for thisObjGUID,_ in pairs(firableObjects) do
  75.         local thisObj = getObjectFromGUID(thisObjGUID)
  76.         if thisObj and (not barrelContents[thisObjGUID]) then
  77.             table.insert(objectsToMove, thisObj)
  78.         end
  79.     end
  80.  
  81.     if #objectsToMove > 0 then
  82.         self.setLock(true)
  83.         Shuffle(objectsToMove)
  84.         MoveTableToBarrel({objs = objectsToMove})
  85.     end
  86. end
  87.  
  88. function LaunchBarrelContents(launchVelocity, color)
  89.     local barrelContents, nrOfBarrelContents = GetBarrelContents()
  90.     for thisObjGUID,_ in pairs(barrelContents) do
  91.         local launchSpin = settings.minSpin + math.random() * (settings.maxSpin - settings.minSpin)
  92.         getObjectFromGUID(thisObjGUID).setVar("firedByDiceRoller", color)
  93.         LaunchObject(getObjectFromGUID(thisObjGUID), launchVelocity, launchSpin)
  94.     end
  95. end
  96.  
  97. function AfterFire()
  98.     if settings.useRecoil then
  99.         rotationAtLaunch = self.getRotation()
  100.         posAtLaunch = self.getPosition()
  101.         CreateTimer(self.GetGUID() .. "Unlock", "Unlock", 0.2)
  102.         CreateTimer(self.GetGUID() .. "Recoil", "Recoil", 0.23, {power = power})
  103.         CreateTimer(self.GetGUID() .. "Reset" , "Reset" , 2.8)
  104.         CreateTimer(self.GetGUID() .. "Lock"  , "Lock"  , 3.5)
  105.     else
  106.         CreateTimer(self.GetGUID() .. "Reset" , "Reset" , 2.5)
  107.     end
  108. end
  109.  
  110. function CalcPowerAndLaunchVelocity(color)
  111.  
  112.     -- Help avoid end of barrel by raising the angle slightly
  113.     local launchDirection = rotateVec3(self.getTransformForward(), self.getTransformRight(), 45)
  114.     local desc = self.getDescription()
  115.     local powerMin, powerMax = desc:match("Power:%s*([%d%.]+)%s*-?%s*([%d%.]*)")
  116.     powerMin = tonumber(powerMin)  powerMax = tonumber(powerMax) or powerMin
  117.  
  118.     if (not powerMin) or (not powerMax) then
  119.         broadcastToColor(help.unreadablePower, color, settings.errorColor)
  120.         print(string.format("[ff6666]%s", help.unreadablePower) )
  121.         return 0
  122.     end
  123.  
  124.     local power = powerMin + math.random() * (powerMax - powerMin)
  125.     if power <= 0 then broadcastToColor(help.lowPower, color, settings.errorColor) return 0 end
  126.  
  127.     local launchVelocity = {launchDirection.x * power, launchDirection.y * power, launchDirection.z * power}
  128.  
  129.     return power, launchVelocity
  130.  
  131. end
  132.  
  133. function CreateTimer(timerName, funcName, delay, params)
  134.  
  135.     local parameters = {}
  136.     parameters.identifier     = timerName
  137.     parameters.function_name  = funcName
  138.     parameters.delay          = delay
  139.  
  140.     if params and type(params) == 'table' then
  141.         parameters.parameters = params
  142.     end
  143.  
  144.     Timer.create(parameters)
  145.  
  146. end
  147.  
  148. function Reset()
  149.     if settings.useRecoil then
  150.         self.setPositionSmooth(posAtLaunch, false, true)
  151.         self.setRotationSmooth(rotationAtLaunch, false, true)
  152.     end
  153.     isFiring = false
  154. end
  155.  
  156. function Lock()
  157.     self.setLock(true)
  158.     self.interactable = true
  159. end
  160.  
  161. function Unlock()
  162.     self.interactable = false -- prevent outlines during firing
  163.     self.setLock(false)
  164. end
  165.  
  166. function Recoil(args)
  167.     local fwdDirection = rotateVec3(self.getTransformForward(), self.getTransformRight(), -11)
  168.     local power = args.power/2 + 3
  169.     if power > 0 then
  170.         local pushVelocity = {
  171.             fwdDirection.x * power * -1,
  172.             fwdDirection.y * power * -1,
  173.             fwdDirection.z * power * -1
  174.             }
  175.         self.setVelocity(pushVelocity)
  176.     end
  177. end
  178.  
  179. function LaunchObject(thisObj, launchVelocity, launchSpin)
  180.     if thisObj ~= self then
  181.  
  182.         local spin = {}
  183.         spin.x = math.random() * launchSpin
  184.         spin.y = math.random() * (launchSpin - spin.x)
  185.         spin.z = (launchSpin - spin.x - spin.y)
  186.  
  187.         --randomly invert some of the axes
  188.         spin.x = spin.x * (math.random(0,1)*2-1)
  189.         spin.y = spin.y * (math.random(0,1)*2-1)
  190.         spin.z = spin.z * (math.random(0,1)*2-1)
  191.  
  192.         --Use setVelocity so that mass can be ignored
  193.         thisObj.setVelocity(launchVelocity)
  194.         thisObj.setAngularVelocity(spin)
  195.  
  196.     end
  197. end
  198.  
  199. function GetBarrelContents()
  200.  
  201.     local castSize    = 2 * self.getScale().x
  202.     local hitResults = Physics.cast(
  203.         {
  204.         origin       = self:positionToWorld( settings.barrelOffset ),
  205.         direction    = rotateVec3( self.getTransformForward(), self.getTransformRight(), 45 ),
  206.         type         = 2, -- sphere
  207.         size         = {castSize,castSize,castSize},
  208.         max_distance = 7.3 * self.getScale().x,
  209.         debug        = false
  210.         }
  211.     )
  212.  
  213.     local barrelContents = {}
  214.     local nrOfObjects = 0
  215.     for _,hit in ipairs(hitResults) do
  216.         if hit.hit_object ~= self then
  217.             nrOfObjects = nrOfObjects + 1
  218.             barrelContents[hit.hit_object.getGUID()] = true
  219.         end
  220.     end
  221.  
  222.     return barrelContents, nrOfObjects
  223.  
  224. end
  225.  
  226. function GetFirableObjects(t)
  227.     local validObjects = {}
  228.     local nrOfFirable = 0
  229.  
  230.     for _,o in ipairs(t) do
  231.         if (o.GetLock() == false) and IsSmallEnough(o) then
  232.             validObjects[o.getGUID()] = true
  233.             nrOfFirable = nrOfFirable + 1
  234.         end
  235.     end
  236.  
  237.     return validObjects, nrOfFirable
  238. end
  239.  
  240. function IsSmallEnough(obj)
  241.     local size = obj.getBoundsNormalized().size
  242.     local barrelSize = self.getScale().x * 1.8
  243.  
  244.     local result = size.x < barrelSize and size.y < barrelSize and size.z < barrelSize
  245.     if result == false then
  246.         local n = obj.getName() if n == "" then n = obj.name end
  247.         print(string.format(help.objtoolarge, n ))
  248.     end
  249.  
  250.     return result
  251. end
  252.  
  253. function MoveTableToBarrel(params)
  254.     local objs = params.objs
  255.     if objs and #objs > 0 then
  256.         local thisObj = table.remove(objs, 1)
  257.         if thisObj.GetLock() == false then
  258.             local o1 = settings.muzzleOffset
  259.             local o2 = settings.muzzleOffset2
  260.             local rndPoint = math.random()
  261.             local thisPosition = {
  262.                 o1.x + math.random()*(o2.x-o1.x),
  263.                 o1.y + rndPoint*(o2.y-o1.y),
  264.                 o1.z + rndPoint*(o2.z-o1.z)
  265.                 }
  266.             thisObj.setPositionSmooth(self:positionToWorld( thisPosition ), false, true)
  267.         end
  268.         if #objs > 0 then
  269.             CreateTimer(objs[1].GetGUID() .. "MoveTableToBarrel", "MoveTableToBarrel", 0.2, {objs = objs})
  270.         end
  271.     end
  272. end
  273.  
  274. function CreateButtons()
  275.  
  276.     local b = {}
  277.     b.function_owner = self
  278.     b.color          = {0.05, 0.05, 0.05, 0}
  279.     -- b.color          = {0.05, 0.05, 0.05, 0.9}
  280.     --b.color          = {0.75, 0.75, 0.75, 0.9}
  281.     b.font_color     = {0.7, 0.7, 0.7, 0}
  282.  
  283.     b.label          = help.buttonFireLabel
  284.     b.click_function = 'FireCannon'
  285.     b.tooltip        = help.buttonFire
  286.     b.width          = 280
  287.     b.height         = 360
  288.     b.position       = {0, 3.32, -2.55}
  289.     b.rotation       = {25, 180, 0}
  290.     self.createButton(b)
  291.  
  292.     b.width          = 500
  293.     b.height         = 400
  294.     b.position       = {1.26, 2.8, -1.8}
  295.     b.rotation       = {13, -65, 55}
  296.     self.createButton(b)
  297.  
  298.     b.width          = 500
  299.     b.height         = 400
  300.     b.position       = {-1.26, 2.8, -1.8}
  301.     b.rotation       = {13, 65, -55}
  302.     self.createButton(b)
  303.  
  304.  
  305.     b.label          = help.buttonLoadLabel
  306.     b.click_function = 'AddObjects'
  307.     b.tooltip        = help.buttonLoad
  308.     b.width          = 300
  309.     b.height         = 350
  310.     b.position       = {0, 4.68, 0.19}
  311.     b.rotation       = {28, 180, 0}
  312.     self.createButton(b)
  313.  
  314.     b.width          = 480
  315.     b.height         = 400
  316.     b.position       = {1.08, 4.2, 0.6}
  317.     b.rotation       = {14, -61, 55}
  318.     self.createButton(b)
  319.  
  320.     b.width          = 480
  321.     b.height         = 400
  322.     b.position       = {-1.08, 4.2, 0.6}
  323.     b.rotation       = {14, 61, -55}
  324.     self.createButton(b)
  325.  
  326. end
  327.  
  328. function onPickedUp(player_color)
  329.     self.AssetBundle.playLoopingEffect(fx.Move)
  330. end
  331.  
  332. function onDropped(player_color)
  333.     self.AssetBundle.playLoopingEffect(fx.Idle)
  334. end
  335.  
  336. function onCollisionEnter(hit)
  337.     if not isFiring then
  338.         local p = self.positionToLocal(hit.contact_points[1])
  339.         local obj = hit.collision_object
  340.         local tag = obj.tag
  341.         -- local name = obj.getName() if name =='' then name = obj.name end
  342.         -- print(string.format("%s, %.2f %.2f %.2f", name, p[1], p[2], p[3]))
  343.  
  344.         --Approximate location of the red vent hole
  345.         if tag ~= 'Dice' and p[2] > 2.9 and p[3] < -1.7 then
  346.             FireCannon(nil, "no color")
  347.         end
  348.     end
  349. end
  350.  
  351. function Shuffle(t)
  352.     local length = #t
  353.     for i = length, 1, -1 do
  354.         local thisIndex = math.random(length)
  355.         t[i], t[thisIndex] = t[thisIndex], t[i]
  356.     end
  357.     return t
  358. end
  359.  
  360. --  Functions to let us rotate a vector around an axis. -------------------
  361. --  This lets us point the cannon shot
  362.  
  363. function dotProduct(a, b)
  364.     return a[1]*b[1] + a[2]*b[2] + (a[3] or 0)*(b[3] or 0)
  365. end
  366.  
  367. -- multiply vector v by matrix with rows r1, r2 and r3
  368. function applyMatrixRowsToVec3(v, r1, r2, r3)
  369.     return {dotProduct(v, r1), dotProduct(v, r2), dotProduct(v, r3)}
  370. end
  371.  
  372. -- Create rotation vectors for angle (radians) about unit vector u
  373. function rotationVectors(u, angle)
  374.     local c = math.cos(angle)
  375.     local s = math.sin(angle)
  376.     local d = 1-c
  377.     local su = {s*u[1], s*u[2], s*u[3]}
  378.     local du = {d*u[1], d*u[2], d*u[3]}
  379.     local r1 = {du[1]*u[1] + c, du[1]*u[2] + su[3], du[1]*u[3] - su[2]}
  380.     local r2 = {du[2]*u[1] - su[3], du[2]*u[2] + c, du[2]*u[3] + su[1]}
  381.     local r3 = {du[3]*u[1] + su[2], du[2]*u[2] - su[1], du[3]*u[3] + c}
  382.     return r1, r2, r3
  383. end
  384.  
  385. --  Return vector v rotated angle degrees around vector u.
  386. function rotateVec3(v, u, angle)
  387.     local rads = angle * math.pi / 180
  388.     local v2 = applyMatrixRowsToVec3(v, rotationVectors(u, rads))
  389.     v2.x = v2[1]
  390.     v2.y = v2[2]
  391.     v2.z = v2[3]
  392.     return v2
  393. end
  394.  
  395. -- END Math functions ----------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement