Advertisement
Maticzpl

Untitled

Feb 5th, 2022
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.53 KB | None | 0 0
  1. --Made By Maticzpl
  2.  
  3. --is it CGI?
  4.  
  5. --"Yeah idk it just reverses stacks
  6. -- I think it's fine" - LBPhacker
  7.  
  8. --KEYS:
  9. -- CTRL + T  Create a new animation / Finish animating
  10. -- CTRL + ENTER Edit existing animation
  11. -- , (comma) Add new empty frame
  12. -- . (dot)   Duplicate current frame
  13. -- Left / Right Arrow - Navigate frames
  14. -- Backspace - Delete current frame
  15.  
  16. if GooAnim then return end
  17.  
  18. GooAnim = {
  19.     started = false,
  20.     frameCount = 0,
  21.     currentFrame = 0,
  22.     frameInterval = 5,
  23.     usedType = 0,
  24.     safeLimit = 0,
  25.     loadingMode = false,
  26.     partsPrev = 999999,
  27.     partsNow = 999999,
  28.     animSize = {x = 0,y = 0},
  29.     offset = {x = 10,y = 10},
  30.     frameData = {},
  31.     version = 2
  32. }
  33.  
  34. local g = GooAnim
  35.  
  36. function GooAnim.createAnimation(sizex,sizey)
  37.     if g.started then
  38.         local res = tpt.confirm("Start new animation?", "Do you want to abandon the current animation and start a new one?","Yes")
  39.         if not res then return end
  40.     end
  41.  
  42.     tpt.set_pause(1)
  43.     tpt.decorations_enable(1)
  44.  
  45.     g.frameCount = 1
  46.     g.frameData = {}
  47.     g.animSize.x = sizex
  48.     g.animSize.y = sizey  
  49.     g.started = true
  50.    
  51.     sim.createBox(  g.offset.x,
  52.                     g.offset.y,
  53.                     g.offset.x + g.animSize.x,
  54.                     g.offset.y + g.animSize.y,
  55.                     g.usedType
  56.                 )
  57. end
  58.  
  59. -- function GooAnim.showFrameCounter()      
  60. --     print("Frame: "..g.currentFrame.. " / "..(g.frameCount - 1).." (max "..(g.safeLimit - 1)..")")      
  61. -- end
  62.  
  63. function GooAnim.saveFrame(remove)
  64.     local frame = {}
  65.     for     x = g.offset.x, g.animSize.x + g.offset.x, 1 do
  66.         for y = g.offset.y, g.animSize.y + g.offset.y, 1 do    
  67.             local rx = x - g.offset.x
  68.             local ry = y - g.offset.y
  69.             local part = sim.partID(x,y)
  70.  
  71.             if part == nil then
  72.                 print(x,y)
  73.             end
  74.  
  75.             local deco = sim.partProperty(part,'dcolour')
  76.             if frame[ry] == nil then
  77.                 frame[ry] = {}                
  78.             end
  79.             frame[ry][rx] = deco
  80.  
  81.             if remove then
  82.                 sim.partKill(part)                
  83.             end
  84.         end            
  85.     end
  86.     g.frameData[g.currentFrame] = frame  
  87. end
  88.  
  89. function GooAnim.loadFrame(frameIndex)
  90.     for     x = g.offset.x, g.animSize.x + g.offset.x, 1 do
  91.         for y = g.offset.y, g.animSize.y + g.offset.y, 1 do  
  92.             local rx, ry = x - g.offset.x , y - g.offset.y
  93.  
  94.             local frame = g.frameData[frameIndex]
  95.            
  96.             if frame[ry] == nil or frame[ry][rx] == nil then
  97.                 local part = sim.partCreate(-3,x,y,elem.DEFAULT_PT_BRCK)                
  98.             else
  99.                 local deco = frame[ry][rx]
  100.                 local part = sim.partCreate(-3,x,y,g.usedType)
  101.                 sim.partProperty(part,'dcolour',deco)
  102.             end
  103.         end            
  104.     end
  105. end
  106.  
  107. -- Thanks to mad-cow for this function!
  108. local function GetAllPartsInRegion(x1, y1, x2, y2)
  109.     -- builts a map of particles in a region.
  110.     -- WARN: Misbehaves if partile order hasn't been reloaded since it relies on sim.parts()
  111.     -- Save the returned value and provide it to .GetAllPartsInPos(x,y,region) to reduce computational complexity
  112.     -- or you can just index the returned value youself, idc
  113.     local result = {}
  114.     local width = sim.XRES
  115.     if x2 < x1 then
  116.         x1,x2 = x2,x1
  117.     end
  118.     if y2 < y1 then
  119.         y1,y2 = y2,y1
  120.     end
  121.     for part in sim.parts() do
  122.         local px, py = sim.partPosition(part)
  123.        
  124.         px = math.floor(px+0.5) -- Round pos
  125.         py = math.floor(py+0.5)
  126.         local idx = math.floor(px + (py * width))
  127.        
  128.         if px >= x1 and px <= x2 and py >= y1 and py <= y2 then
  129.             if not result[idx] then
  130.                 result[idx] = {}
  131.             end
  132.             table.insert(result[idx], part)
  133.         end
  134.     end
  135.     return result
  136. end
  137. -- Yes, i did just copy those from my subframe chipmaker script
  138. local function ReorderParticles()    
  139.     local particles = {}
  140.     local width = sim.XRES
  141.     for part in sim.parts() do
  142.         local x = math.floor(sim.partProperty(part,'x') + 0.5);
  143.         local y = math.floor(sim.partProperty(part,'y') + 0.5);
  144.  
  145.         local particleData = {}
  146.         particleData.type =     sim.partProperty(part,'type');
  147.         particleData.temp =     sim.partProperty(part,'temp');
  148.         particleData.ctype =    sim.partProperty(part,'ctype');
  149.         particleData.tmp =      sim.partProperty(part,'tmp');
  150.         particleData.tmp2 =     sim.partProperty(part,'tmp2');
  151.         particleData.tmp3 =     sim.partProperty(part,'pavg0');
  152.         particleData.tmp4 =     sim.partProperty(part,'pavg1');
  153.         particleData.life =     sim.partProperty(part,'life');
  154.         particleData.vx =       sim.partProperty(part,'vx');
  155.         particleData.vy =       sim.partProperty(part,'vy');
  156.         particleData.dcolour =  sim.partProperty(part,'dcolour');
  157.         particleData.flags =    sim.partProperty(part,'flags');
  158.  
  159.         local index = math.floor(x + (y * width))
  160.         if particles[index] == nil then
  161.             particles[index] = {}            
  162.         end
  163.         table.insert(particles[index],particleData)
  164.         --particles[index][#particles[index]] = particleData  
  165.         sim.partKill(part)    
  166.     end
  167.  
  168.     for i = sim.XRES * sim.YRES, 0, -1 do
  169.         local stack = particles[i]
  170.         if stack ~= nil then
  171.             for j = #stack, 1, -1 do
  172.                 local part = stack[j]
  173.                 local x = math.floor(i % sim.XRES)
  174.                 local y = math.floor((i - x) / sim.XRES)
  175.  
  176.                 local id = sim.partCreate(-3,x,y,28)
  177.  
  178.                 sim.partProperty(id,'type',part.type);
  179.                 sim.partProperty(id,'temp',part.temp);
  180.                 sim.partProperty(id,'ctype',part.ctype);
  181.                 sim.partProperty(id,'tmp',part.tmp);
  182.                 sim.partProperty(id,'tmp2',part.tmp2);
  183.                 sim.partProperty(id,'pavg0',part.tmp3);
  184.                 sim.partProperty(id,'pavg1',part.tmp4);
  185.                 sim.partProperty(id,'life',part.life);
  186.                 sim.partProperty(id,'vx',part.vx);
  187.                 sim.partProperty(id,'vy',part.vy);
  188.                 sim.partProperty(id,'dcolour',part.dcolour)
  189.                 sim.partProperty(id,'flags',part.flags);
  190.             end            
  191.         end
  192.     end
  193.  
  194. end
  195.  
  196. local function ArrayGCD(arr)
  197.     local function gcd(a, b)        
  198.         if (a == 0) then
  199.             return b;
  200.         end
  201.         return gcd(b % a, a);
  202.     end
  203.          
  204.     local result = arr[1];
  205.     for i = 2, #arr, 1 do
  206.         result = gcd(arr[i], result);
  207.    
  208.         if(result == 1) then        
  209.             return 1;
  210.         end
  211.     end
  212.     return result;        
  213. end
  214.  
  215. function GooAnim.toFrame(frameIndex)    
  216.     if frameIndex < 0 or frameIndex >= GooAnim.frameCount  then
  217.         return
  218.     end
  219.  
  220.     GooAnim.saveFrame(true)
  221.     g.currentFrame = frameIndex
  222.     GooAnim.loadFrame(frameIndex)
  223. end
  224.  
  225. function GooAnim.nextFrame(clone,placeAfterCurrent)
  226.     GooAnim.saveFrame(not clone)
  227.     if placeAfterCurrent then
  228.         g.currentFrame = g.currentFrame + 1
  229.  
  230.         for i = g.frameCount - 1, g.currentFrame, -1 do
  231.             g.frameData[i+1] = g.frameData[i]
  232.         end      
  233.  
  234.     else
  235.         g.currentFrame = g.frameCount
  236.     end
  237.  
  238.     if not clone then
  239.         sim.createBox(  g.offset.x,
  240.                         g.offset.y,
  241.                         g.offset.x + g.animSize.x,
  242.                         g.offset.y + g.animSize.y,
  243.                         g.usedType
  244.                     )
  245.     end
  246.  
  247.     g.frameCount = g.frameCount + 1
  248. end
  249.  
  250. function GooAnim.deleteFrame(frameIndex)
  251.     if g.frameCount < 2 then
  252.         print("Can't delete this frames")
  253.         return
  254.     end
  255.  
  256.     if g.currentFrame >= g.frameCount - 1 then
  257.         g.currentFrame = g.currentFrame - 1
  258.     end
  259.  
  260.     g.frameCount = g.frameCount - 1
  261.  
  262.     if frameIndex == 0 then
  263.         for i = 0, g.frameCount - 1, 1 do
  264.             g.frameData[i] = g.frameData[i+1]
  265.         end      
  266.         g.frameData[g.frameCount] = nil
  267.     else
  268.         table.remove(g.frameData,frameIndex)
  269.     end
  270.  
  271.     sim.clearRect(g.offset.x,g.offset.y,g.animSize.x+1,g.animSize.y+1)
  272.     g.loadFrame(g.currentFrame)
  273. end
  274.  
  275. function GooAnim.finishAnimation()
  276.     local confirm = tpt.confirm("Finish animation?", "Do you want to finish the animation?","Yes")
  277.     if not confirm then
  278.         return
  279.     end
  280.  
  281.     GooAnim.saveFrame()
  282.     sim.clearSim()
  283.  
  284.     sim.createWallBox(g.offset.x, g.offset.y, g.animSize.x + g.offset.x, g.animSize.y + g.offset.y, 12)  
  285.  
  286.  
  287.     for     y = g.offset.y, g.animSize.y + g.offset.y, 1 do  
  288.         for x = g.offset.x, g.animSize.x + g.offset.x, 1 do
  289.             for i = g.frameCount - 1, 0 , -1 do
  290.                 local frame = g.frameData[i]
  291.                 if frame ~= nil then
  292.                     local rx = x - g.offset.x
  293.                     local ry = y - g.offset.y
  294.                     local deco = frame[ry][rx]
  295.  
  296.                     local part = nil
  297.  
  298.                     local prev = 1
  299.                     if i-prev >= 0 then                    
  300.                         while true do
  301.                             while i-prev >= 0 and g.frameData[i-prev] == nil do
  302.                                 prev = prev + 1
  303.                             end
  304.  
  305.                             if i-prev < 0 then                    
  306.                                 part = sim.partCreate(-3,x,y,g.usedType)
  307.                                 sim.partProperty(part,'dcolour',deco)
  308.                                 break                            
  309.                             end
  310.                            
  311.                             if g.frameData[i-prev][ry][rx] == deco then
  312.                                 break
  313.                             else                            
  314.                                 part = sim.partCreate(-3,x,y,g.usedType)
  315.                                 sim.partProperty(part,'dcolour',deco)
  316.                                 break
  317.                             end
  318.                         end          
  319.                     else
  320.                         part = sim.partCreate(-3,x,y,g.usedType)
  321.                         sim.partProperty(part,'dcolour',deco)
  322.                     end
  323.  
  324.                     if part ~= nil then    
  325.                         local lasting = 1
  326.                         if g.frameData[i+lasting] ~= nil then                    
  327.                             while g.frameData[i+lasting][ry][rx] == deco do
  328.                                 lasting = lasting + 1
  329.                                 if g.frameData[i+lasting] == nil then        
  330.                                     break
  331.                                 end
  332.                             end
  333.                         end
  334.  
  335.                         sim.partProperty(part,'life',(i + lasting) * g.frameInterval);
  336.                     end
  337.                 end
  338.             end
  339.         end        
  340.     end
  341.  
  342.     GooAnim.started = false    
  343.     sim.takeSnapshot()
  344.     sim.saveStamp(g.offset.x,g.offset.y,g.animSize.x,g.animSize.y)
  345.     print("Animation saved in stamps")
  346. end
  347.  
  348. function GooAnim.loadAnimation()
  349.     print("Loading animation")
  350.    
  351.     g.offset = nil
  352.     local furthestX = 0
  353.     local furthestY = 0
  354.     local maxLife = 0
  355.     local allLifeValues = {}
  356.     for part in sim.parts() do  
  357.         local x,y = sim.partPosition(part)
  358.         x = math.floor(x)
  359.         y = math.floor(y)
  360.  
  361.         if sim.partProperty(part,'life') > maxLife then
  362.             maxLife = sim.partProperty(part,'life')
  363.         end
  364.         table.insert(allLifeValues,sim.partProperty(part,'life'))
  365.        
  366.         if x > furthestX then
  367.             furthestX = x                    
  368.         end
  369.         if y > furthestY then
  370.             furthestY = y              
  371.         end
  372.  
  373.         if g.offset == nil then
  374.             g.offset = {x=x,y=y}
  375.         end
  376.     end
  377.  
  378.     g.frameCount = 0
  379.     g.animSize.x = furthestX - g.offset.x
  380.     g.animSize.y = furthestY - g.offset.y
  381.     g.started = true
  382.     g.frameData = {}
  383.     g.safeLimit = math.floor(235008 / (tonumber(g.animSize.x) * tonumber(g.animSize.y)))
  384.  
  385.     ReorderParticles()
  386.  
  387.     local stacks = GetAllPartsInRegion(g.offset.x,g.offset.y,furthestX,furthestY)
  388.  
  389.     g.frameInterval = ArrayGCD(allLifeValues)
  390.  
  391.     g.frameCount = maxLife / g.frameInterval
  392.  
  393.     for k, stack in pairs(stacks) do
  394.         local rx, ry = sim.partPosition(stack[0] or stack[1])
  395.         rx = math.floor(rx + 0.5) - g.offset.x
  396.         ry = math.floor(ry + 0.5) - g.offset.y
  397.  
  398.         local frames = 0
  399.         local offset = 0
  400.         for j, part in pairs(stack) do  
  401.             offset = offset - 1
  402.  
  403.             local part = stack[#stack - j + 1]  
  404.             g.usedType = sim.partProperty(part,'type')              
  405.          
  406.             local life = sim.partProperty(part,'life')    
  407.  
  408.             local toSkip = math.floor(life / g.frameInterval) - j - (offset + 1)
  409.  
  410.             for s = 0, toSkip, 1 do
  411.                 offset = offset + 1
  412.                 if g.frameData[j-1+offset] == nil then                
  413.                     g.frameData[j-1+offset] = {}
  414.                 end
  415.                 if g.frameData[j-1+offset][ry] == nil then                
  416.                     g.frameData[j-1+offset][ry] = {}
  417.                 end
  418.                 if g.frameData[j-1+offset][ry][rx] == nil then
  419.                     g.frameData[j-1+offset][ry][rx] = sim.partProperty(part,'dcolour')      
  420.                 end
  421.             end          
  422.         end
  423.  
  424.         if frames > g.frameCount then
  425.             g.frameCount = frames
  426.         end
  427.     end
  428.  
  429.     sim.clearSim()
  430.  
  431.     local prevInterval = g.frameInterval
  432.     g.frameInterval = tonumber(tpt.input("Enter New Frame Interval","Do you want to change the frame interval?",g.frameInterval))
  433.     if g.frameInterval == nil then
  434.         g.frameInterval = prevInterval
  435.     end
  436.  
  437.     g.currentFrame = 0
  438.     GooAnim.loadFrame(0)
  439. end
  440.  
  441. local function bindKeys()
  442.     event.register(event.keypress, function(key,scan,rpt,shift,ctrl,alt)
  443.         if shift or alt then return end
  444.        
  445.         if GooAnim.started and not ctrl then            
  446.             if key == 44 and not rpt then -- < to next frame
  447.                 local afterCurrent = false
  448.                 if g.currentFrame ~= g.frameCount - 1 then
  449.                     afterCurrent = tpt.confirm("Where to put the frame?","Click 'Cancel' to put the frame as a new frame at the end. Click 'Ok' to insert a new frame after this one.","Ok")
  450.                 end
  451.  
  452.                 GooAnim.nextFrame(false,afterCurrent)
  453.                 return false
  454.             end
  455.  
  456.             if key == 46 and not rpt then -- > to clone frame
  457.                 local afterCurrent = false
  458.                 if g.currentFrame ~= g.frameCount - 1 then
  459.                     afterCurrent = tpt.confirm("Where to put the frame?","Click 'Cancel' to put the frame as a new frame at the end. Click 'Ok' to insert a new frame after this one.","Ok")
  460.                 end
  461.  
  462.                 GooAnim.nextFrame(true,afterCurrent)
  463.                 return false
  464.             end
  465.  
  466.             if key == 1073741903 then -- right arrow
  467.                 GooAnim.toFrame(GooAnim.currentFrame + 1 )
  468.             end
  469.             if key == 1073741904 then -- left arrow
  470.                 GooAnim.toFrame(GooAnim.currentFrame - 1 )                
  471.             end
  472.  
  473.             if key == 8 and not rpt then --Backspace
  474.                 GooAnim.deleteFrame(g.currentFrame)
  475.             end
  476.         end
  477.  
  478.         if key == 13 and ctrl and not GooAnim.started then -- CTRL + ENTER
  479.             if tpt.confirm("Is the simulation clear?","Make sure the simulation is clear of everything except the animation you want to edit.","Yes") then
  480.                 GooAnim.loadAnimation()
  481.             end
  482.         end
  483.  
  484.         if key == 116 and ctrl then --CTRL + T to Start / Stop animation
  485.             if GooAnim.started then
  486.                 GooAnim.finishAnimation()
  487.             else
  488.                 if not tpt.confirm("New animation", "The whole simulation will be cleared, proceed?","Yes") then
  489.                     return
  490.                 end
  491.                 sim.clearSim()
  492.                 local x = tpt.input("Enter Width","Enter the target resolution for your animation",25)
  493.                 if x == "" then
  494.                     return
  495.                 end
  496.                 local y = tpt.input("Enter Height","Enter the target resolution for your animation",math.floor((x / 16) * 9))
  497.                 if y == "" then
  498.                     return
  499.                 end
  500.                 GooAnim.frameInterval = tpt.input("Enter Frame Interval","Enter the delay (in game frames) between an animation frame changes",5)
  501.                 local type = tpt.input("Enter Type","What particle type to use (other types than GOO can break the script)","GOO")
  502.                
  503.                 type = string.upper(type)
  504.  
  505.                 if elem["DEFAULT_PT_"..type] ~= nil then
  506.                     GooAnim.usedType = elem["DEFAULT_PT_"..type]
  507.                 else
  508.                     tpt.message_box("Wrong Type","The type '"..type.."' is not found")
  509.                     return
  510.                 end
  511.                
  512.                 -- part limit around 235008
  513.                 GooAnim.safeLimit = math.floor(235008 / (tonumber(x) * tonumber(y)))
  514.  
  515.                 if tonumber(x) * tonumber(y) >= 40000 then
  516.                     tpt.message_box("Warning","Big resolution animations may exceed the particle limit")
  517.                 end
  518.                 GooAnim.createAnimation(x,y)
  519.             end
  520.             return false
  521.         end        
  522.        
  523.     end)  
  524.  
  525.     event.register(event.tick, function ()
  526.         if g.started then
  527.             local text = "Frame: "..g.currentFrame.. " / "..(g.frameCount - 1).." (max "..(g.safeLimit - 1).." worst case scenario)"
  528.             local w,h = gfx.textSize(text)
  529.  
  530.             gfx.drawText(sim.XRES / 2 - (w / 2),sim.YRES - 50,text,255,255,255,255)
  531.  
  532.             local text = "[,] - New Empty Frame [.] - Clone Frame [CTRL + T] - Finish Animating"
  533.             local w,h = gfx.textSize(text)
  534.             gfx.drawText(sim.XRES / 2 - (w / 2),sim.YRES - 35,text,255,255,255,255)
  535.  
  536.             local text = "[<- / ->] - Change current frame [Backspace] - Delete current frame"
  537.             local w,h = gfx.textSize(text)
  538.             gfx.drawText(sim.XRES / 2 - (w / 2),sim.YRES - 20,text,255,255,255,255)
  539.         end
  540.     end)
  541.  
  542. end
  543.  
  544. bindKeys()
  545.  
  546. -- TODO:
  547. -- Accurate max frame limit
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement