dwIndex

Raycast Script

Nov 11th, 2021 (edited)
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.10 KB | None | 0 0
  1. local tfm = tfm
  2. local system = system
  3. local ui = ui
  4. local os = os
  5. local math = math
  6.  
  7. system.disableChatCommandDisplay(nil)
  8.  
  9. tfm.exec.disablePhysicalConsumables(true)
  10. tfm.exec.disableAfkDeath(true)
  11. tfm.exec.disableAutoNewGame(true)
  12. tfm.exec.disableAutoShaman(true)
  13. tfm.exec.disableAutoTimeLeft(true)
  14. tfm.exec.disableAutoScore(true)
  15. tfm.exec.disablePhysicalConsumables(true)
  16.  
  17. local started
  18. local driver = {}
  19.  
  20. local timer = 0
  21. local mult = 16
  22.  
  23. local modulo = {
  24.     creator = "Indexinel#5948",
  25.     name = "Matrix",
  26.     loading = nil
  27. }
  28.  
  29. --local cumulativeRuntime = 0
  30. --local runtimeCount = 0
  31.  
  32. local isTribe = (string.sub(tfm.get.room.name, 1, 2) == "*\003")
  33. local rTms
  34. if isTribe then rTms = 40 else rTms = 60 end
  35. local runtimeLimit = math.ceil(4000 / (rTms / 3.7)) -- is the average runtime in ms per each run; don't touch unless wrong | currently: 3.4 | no warnings: 3.7 | add +0.3 for margin
  36.  
  37. local theme = "earth"
  38.  
  39. local imgdespawn = {}
  40.  
  41. local map = {
  42.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  43.     1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,1,
  44.     1,0,0,2,1,3,0,0,0,0,0,0,0,0,0,1,
  45.     1,0,1,3,0,0,0,0,0,1,1,0,0,0,1,1,
  46.     1,0,0,2,0,0,1,0,0,0,2,3,2,0,0,1,
  47.     1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,1,
  48.     1,0,0,0,0,0,3,0,0,0,0,0,0,1,0,1,
  49.     1,0,1,0,0,2,1,0,3,0,1,3,0,1,0,1,
  50.     1,0,1,1,0,0,2,0,2,0,0,1,0,0,0,1,
  51.     1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
  52.     1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,
  53.     1,1,0,2,2,3,0,0,3,1,0,1,0,0,1,1,
  54.     1,0,0,0,3,0,0,0,2,0,0,2,3,0,0,1,
  55.     1,0,1,0,0,0,0,2,3,3,0,1,0,0,0,1,
  56.     1,0,0,0,3,0,0,0,0,0,0,0,0,0,0,1,
  57.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
  58. }
  59.  
  60. local mapSize = 16
  61. local lcxdis = ((mapSize/2) + 1) * mult
  62. local lcmax = lcxdis * 2.25
  63. local lcydis = lcmax / 2
  64.  
  65. local keys = {
  66. 0, -- LEFT
  67. 1, -- UP
  68. 2, -- RIGHT
  69. 3, -- DOWN
  70. 27, -- ESC
  71. 67, -- C
  72. 72, -- H
  73. 81, -- Q
  74. 86, -- V
  75. 88, -- X
  76. 90 -- Z
  77. }
  78.  
  79. local pi360deg = math.pi * 2
  80. local pi270deg = math.pi * 1.5
  81. local pi90deg = math.pi / 2
  82.  
  83. local res = {}
  84.  
  85. res["def"] = {
  86.     light = "17cdc043c6b.png",
  87.     dark = "17cdc046b4e.png",
  88. }
  89.  
  90. res["snow"] = {
  91.     light = "17ce70c5762.png",
  92.     dark = "17ce70c6ed5.png",
  93.     background = {
  94.         url = "17ce7140914.png", -- Not working, must duplicate
  95.         x = 1895,
  96.         y = 500,
  97.         id = nil,
  98.     }
  99. }
  100.  
  101. res["earth"] = {
  102.     light = "17ce70c8648.png",
  103.     dark = "17ce70c9dbc.png",
  104.     background = {
  105.         url = "17d0c30945c.png",
  106.         x = 3204,
  107.         y = 400,
  108.         id = nil
  109.     }
  110. }
  111.  
  112. function renderRay(id, ray)
  113.     local xpos = (id*10) - 5
  114.     local rs = res[theme]
  115.  
  116.     local scaleY = 26/ray.distance -- >> = bigger
  117.     local ypos = math.floor(200 - (200 * scaleY) / 2) + 5
  118.    
  119.     if theme == "def" then scaleX = 0.625 else scaleX = 1.0 end
  120.    
  121.     if ray.side_hit then
  122.         imgId = rs.dark
  123.     else
  124.         imgId = rs.light
  125.     end
  126.  
  127.     return tfm.exec.addImage(imgId, "!1", xpos, ypos, nil, scaleX, scaleY, 0, 1.0, 0.5, 0)
  128. end
  129.  
  130. function renderBackground()
  131.     local bg = res[theme].background
  132.     local pl = driver
  133.    
  134.     local cos = math.cos
  135.     local sin = math.sin
  136.     local floor = math.floor
  137.    
  138.     if bg ~= nil then
  139.         local lx = lcxdis + (cos(pl.angle) * lcydis) -- 144 = 9.0; 160 = 10.0
  140.         local ly = lcxdis + (sin(pl.angle) * lcydis)
  141.         local dis = lcmax - distance(pl.x, pl.y, lx, ly)
  142.         local scaleY = 1.0 + (dis/lcmax)
  143.        
  144.         local yPos = floor(205 - ((bg.y * scaleY) / 2)) -- 400 - bg.y
  145.         local xPos = floor(((bg.x/4) * cos(pl.angle/2)) + 0.5)
  146.         if xPos < -(bg.x/2) then
  147.             xPos = xPos + bg.x
  148.         end
  149.        
  150.         if driver.start then tfm.exec.removeImage(bg.id) end
  151.         res[theme].background.id = tfm.exec.addImage(bg.url, "_1", xPos, yPos, nil, 1.0, scaleY, 0, 1.0, 0.5, 0)
  152.     end
  153. end
  154.  
  155. function raycast(rayAngle)
  156.     local pl = driver
  157.     local lmap = map
  158.    
  159.     local pi = math.pi
  160.     local mul = mult
  161.    
  162.     local lshift = bit32.lshift
  163.     local tan = math.tan
  164.    
  165.     local hx = pl.x
  166.     local hy = pl.y
  167.     local ry, rx, yo, xo, mx, my, mp, dist
  168.    
  169.     if rayAngle < 0 then
  170.         rayAngle = rayAngle + pi360deg
  171.     elseif rayAngle > pi360deg then
  172.         rayAngle = rayAngle - pi360deg
  173.     end
  174.    
  175.     local at = -1/tan(rayAngle)
  176.    
  177.     local rcl = 0
  178.     local disH = 400
  179.     if rayAngle > pi then
  180.         ry = lshift(lshift(driver.y, -4), 4) - 0.0001
  181.         rx = ((pl.y - ry)*at) + pl.x
  182.         yo = -mul
  183.         xo = -yo*at
  184.     end
  185.     if rayAngle < pi then
  186.         ry = lshift(lshift(driver.y, -4), 4) + mul
  187.         rx = ((pl.y - ry)*at) + pl.x
  188.         yo = mul
  189.         xo = -yo*at
  190.     end
  191.     if rayAngle == 0 or rayAngle == pi then
  192.         rx = pl.x
  193.         ry = pl.y
  194.         rcl = 8
  195.     end
  196.     while rcl < 8 do
  197.         mx = lshift(rx, -4)
  198.         my = lshift(ry, -4)
  199.         mp = (my*16) + mx
  200.         if  mp > 1 and mp <= 256 and lmap[mp] >= 1 then
  201.             hx = rx
  202.             hy = ry
  203.             disH = distance(pl.x, pl.y, hx, hy)
  204.             rcl = 8
  205.             ltype = lmap[mp]
  206.         else
  207.             rx = rx + xo
  208.             ry = ry + yo
  209.             rcl = rcl + 1
  210.         end
  211.     end
  212.  
  213.     local disV = 400
  214.     local vx = pl.x
  215.     local vy = pl.y
  216.     local nt = -tan(rayAngle)
  217.     rcl = 0
  218.  
  219.     if rayAngle > pi90deg and rayAngle < pi270deg then
  220.         rx = lshift(lshift(driver.x, -4), 4) - 0.0001
  221.         ry = ((pl.x - rx)*nt) + pl.y
  222.         xo = -mul
  223.         yo = -xo*nt
  224.     end
  225.     if rayAngle < pi90deg or rayAngle > pi270deg then
  226.         rx = lshift(lshift(driver.x, -4), 4) + mul
  227.         ry = ((pl.x - rx)*nt) + pl.y
  228.         xo = mul
  229.         yo = -xo*nt
  230.     end
  231.     if rayAngle == 0 or rayAngle == pi then
  232.         rx = pl.x
  233.         ry = pl.y
  234.         rcl = 8
  235.     end
  236.    
  237.     while rcl < 8 do
  238.         mx = lshift(rx, -4)
  239.         my = lshift(ry, -4)
  240.         mp = (my*16) + mx
  241.         if mp > 1 and mp <= 256 and lmap[mp] >= 1 then
  242.             vx = rx
  243.             vy = ry
  244.             disV = distance(pl.x, pl.y, vx, vy)
  245.             rcl = 8
  246.             ltype = lmap[mp]
  247.         else
  248.             rx = rx + xo
  249.             ry = ry + yo
  250.             rcl = rcl + 1
  251.         end
  252.     end
  253.    
  254.     if disV < disH then
  255.         rx = vx
  256.         ry = vy
  257.         dist = disV
  258.         lHit = true
  259.     elseif disH < disV then
  260.         rx = hx
  261.         ry = hy
  262.         dist = disH
  263.         lHit = false
  264.     else
  265.         dist = disV
  266.         lHit = true
  267.     end
  268.  
  269.     fa = pl.angle - rayAngle
  270.     if fa < 0 then
  271.         fa = fa + pi360deg
  272.     elseif fa > pi360deg then
  273.         fa = fa - pi360deg
  274.     end
  275.  
  276.     dist = dist * math.cos(fa)
  277.    
  278.     local ray = {
  279.         angle = rayAngle,
  280.         distance = dist,
  281.         side_hit = lHit,
  282.         block_type = ltype
  283.     }
  284.    
  285.     return ray
  286. end
  287.  
  288. function display()
  289.     local pl = driver
  290.     renderBackground()
  291.  
  292.     local rad = math.rad
  293.     local ra = pl.angle - rad(pl.fov / 2)
  294.     local fov = pl.fov --+ 1
  295.    
  296.     if ra < 0 then
  297.         ra = ra + pi360deg
  298.     elseif ra > pi360deg then
  299.         ra = ra - pi360deg
  300.     end
  301.    
  302.     local ray = {}
  303.     local raycastr = raycast
  304.     for r=1, fov do
  305.         ray = raycastr(ra)
  306.        
  307.         ra = ra + rad(1)
  308.         if ra < 0 then
  309.             ra = ra + pi360deg
  310.         elseif ra > pi360deg then
  311.             ra = ra - pi360deg
  312.         end
  313.        
  314.         if imgdespawn[r] then tfm.exec.removeImage(imgdespawn[r]) end
  315.         imgdespawn[r] = renderRay(r, ray)
  316.     end
  317.    
  318.     if driver.id then tfm.exec.removeImage(driver.id) end
  319.     driver.id = tfm.exec.addImage("17ce70cb52e.png", "&2", 725 + (pl.x - mult)/4, 25 + pl.y/4, nil, 1.0, 1.0, pl.angle+rad(90), 1.0, 0.5, 0.5)
  320.    
  321.     textUpdate(driver.name)
  322. end
  323.  
  324. function distance(ax, ay, bx, by)
  325.     return math.sqrt((bx-ax)^2 + (by-ay)^2)
  326. end
  327.  
  328. function eventKeyboard(playerName, key, down, x, y)
  329.     -- local timecheck = os.time()
  330.     local mul = mult
  331.     if playerName == driver.name then
  332.         if driver.timestamp < os.time() - runtimeLimit then
  333.             local po = {
  334.                 x = driver.x,
  335.                 y = driver.y,
  336.                 angle = driver.angle
  337.             }
  338.             local coords
  339.            
  340.             local ceil = math.ceil
  341.             local floor = math.floor
  342.  
  343.             if key >= 0 and key <= 3 then
  344.                 if key == 3 then -- BACK/DOWN [3]
  345.                     driver.x = driver.x - driver.dx
  346.                     driver.y = driver.y - driver.dy
  347.                 elseif key == 0 then -- LEFT [0]
  348.                     driver.x = driver.x + driver.dy
  349.                     driver.y = driver.y - driver.dx
  350.                 elseif key == 1 then -- FRONT/UP [1]
  351.                     driver.x = driver.x + driver.dx
  352.                     driver.y = driver.y + driver.dy
  353.                 elseif key == 2 then -- RIGHT [2]
  354.                     driver.x = driver.x - driver.dy
  355.                     driver.y = driver.y + driver.dx
  356.                 end
  357.  
  358.                 if map[ceil((floor(po.y/mult) * mul) + floor(driver.x/mul))] >= 1 then
  359.                     driver.x = po.x
  360.                 end
  361.                 if map[ceil((floor(driver.y/mul) * mul) + floor(po.x/mul))] >= 1 then
  362.                     driver.y = po.y
  363.                 end
  364.                
  365.             elseif key == 27 or key == 81 then -- ESC / Q
  366.                 startNewGame() --system.exit()
  367.             elseif key == 67 or key == 86 or key == 88 or key == 90 then
  368.                 if key == 90 then -- Z (-angle1)
  369.                     driver.angle = driver.angle - 0.15
  370.                 elseif key == 88 then -- X (+angle1)
  371.                     driver.angle = driver.angle + 0.15
  372.                 elseif key == 67 then -- C (-angle3)
  373.                     driver.angle = driver.angle - 0.45
  374.                 elseif key == 86 then -- V (+angle3)
  375.                     driver.angle = driver.angle + 0.45
  376.                 end
  377.  
  378.                 if driver.angle < 0 then
  379.                     driver.angle = driver.angle + pi360deg
  380.                 elseif driver.angle > pi360deg then
  381.                     driver.angle = driver.angle - pi360deg
  382.                 end
  383.  
  384.                 driver.dx = math.cos(driver.angle) * driver.speed
  385.                 driver.dy = math.sin(driver.angle) * driver.speed
  386.                
  387.             end
  388.            
  389.             driver.x = fRound(driver.x, 1)
  390.             driver.y = fRound(driver.y, 1)
  391.        
  392.        
  393.         if po.x ~= driver.x or po.y ~= driver.y or driver.angle ~= po.angle then
  394.             display()
  395.             driver.timestamp = os.time()
  396.         end
  397.         --[[cumulativeRuntime = cumulativeRuntime + (os.time() - timecheck)
  398.         runtimeCount = runtimeCount + 1
  399.         print(string.format("%f ms", fRound(cumulativeRuntime / runtimeCount, 3) ) )]]
  400.         end
  401.     end
  402.     if key == 72 then -- h
  403.         eventTextAreaCallback(100, playerName, "help")
  404.     end
  405. end
  406.  
  407. function eventMouse(playerName, x, y)
  408.     if playerName == driver.name then
  409.         if driver.timestamp < os.time() - runtimeLimit then
  410.             driver.angle = driver.angle - fRound(math.rad( (400 - x) / (800/driver.fov) ), 2)
  411.            
  412.             if driver.angle < 0 then
  413.                 driver.angle = driver.angle + pi360deg
  414.             elseif driver.angle > pi360deg then
  415.                 driver.angle = driver.angle - pi360deg
  416.             end
  417.            
  418.             driver.dx = math.cos(driver.angle) * driver.speed
  419.             driver.dy = math.sin(driver.angle) * driver.speed
  420.  
  421.             if x ~= 400 then
  422.                 display()
  423.                 driver.timestamp = os.time()
  424.             end
  425.         end
  426.     end
  427. end
  428.  
  429. function fRound(value, pres)
  430.     local mul = 10^pres
  431.     return math.floor((value * mul)) / mul
  432. end
  433.  
  434. function textUpdate(playerName)
  435.     local text = string.format(
  436.             "<VI><font size='18'>World</font>\n<font size='14'>Coordinates: <R>%0.2f</R>, <R>%0.2f</R>\nAngle: <R>%0.2f°</R></font></VI>",
  437.             driver.x,
  438.             driver.y,
  439.             fRound(math.deg(driver.angle), 2)
  440.         )
  441.     if not driver.start then
  442.         ui.addTextArea(0, text, nil, 0, 25, 0, 0, 0x010101, 0x010101, 0, true)
  443.     else
  444.         ui.updateTextArea(0, text, nil)
  445.     end
  446. end
  447.  
  448. function eventTextAreaCallback(id, playerName, event)
  449.     if event == "clear" then
  450.         ui.removeTextArea(id, playerName)
  451.     elseif event == "help" then
  452.         ui.addTextArea(20, "<font size='24'><T>Help</T></font>\n\nThis script uses the technique of raycasting to transform a 2D map into a 3D scene.\n\nThe controls for the character are:\nWASD / arrows :  Move the character.\nZ/C : Rotate character to left.\nX/V : Rotate characters to right.\nMouse : Rotates to the point you click.\nESC / Q : Removes you the driver role and starts a new round.\nH : Opens this tab.\n\nKeys relate to the character can only be used by the driver.\n\n\n<a href='event:clear'><R>Close</R></a>", playerName, 200, 50, 400, 300, 0x010101, 0x010101, 0.5, true)
  453.     end
  454. end
  455.  
  456. function eventChatCommand(playerName, command)
  457.     local arguments = {}
  458.     for arg in command:gmatch("[^%s]+") do
  459.         table.insert(arguments, arg)
  460.     end
  461.     if command == "help" then
  462.         eventTextAreaCallback(100, playerName, "help")
  463.     end
  464. end
  465.  
  466. function eventLoop(time, remaining)
  467.     timer = timer + 500
  468.     ui.updateTextArea(1, string.format("<p align='center'><font size='14'><ROSE>%0.2f</ROSE><J>s</J></font></p>", (timer / 1000)), nil)
  469.  
  470.     if timer > 3000 then
  471.         if started then
  472.             if driver.timestamp < os.time() - 120000 then -- 2 min
  473.                 startNewGame()
  474.             end
  475.         else
  476.             ui.removeTextArea(169)
  477.             tfm.exec.removeImage(modulo.loading)
  478.             startNewGame()
  479.             started = true
  480.         end
  481.     elseif timer == 500 and not started then
  482.         modulo.loading = tfm.exec.addImage("15150c10e92.png", "_1", 0, 0, nil, 1.0, 1.0, 0, 1.0, 0, 0)
  483.         ui.addTextArea(169 , "<font size='96'><p align='center'>Loading...</p></font>", nil, 100, 150, 600, 200, 0x000000, 0x000000, 1.0, true)
  484.     end
  485. end
  486.  
  487. function eventNewPlayer(playerName)
  488.     ui.addTextArea(100, "<ROSE><font size='16'><p align='right'><a href='event:help'>Help</a></p></font></ROSE>", playerName, 600, 375, 200, 0, 0x000000, 0x000000, 1.0, true)
  489.     for _, k in ipairs(keys) do
  490.         system.bindKeyboard(playerName, k, false)
  491.     end
  492.     system.bindMouse(playerName)
  493. end
  494.  
  495. function eventPlayerLeft(playerName)
  496.     if driver.name == playerName then
  497.         startNewGame()
  498.     end
  499. end
  500.  
  501. function eventNewGame()
  502.     timer = 0
  503.     display()
  504.    
  505.     ui.addTextArea(1, string.format("<p align='center'><font size='14'><ROSE>%0.2f</ROSE><J>s</J></font></p>", (timer / 1000)), nil, 375, 25, 0, 0, 0x000000, 0x000000, 0, true)
  506.     ui.addTextArea(10, string.format("<font size='14'><VI>Driver: <ROSE>%s</ROSE></VI></font>", driver.name), nil, 0, 380, 0, 0, 0x000000, 0x000000, 1.0, true)
  507.  
  508.     driver.minimap = tfm.exec.addImage("17ce70c3ff1.png", "&1", 725, 25, nil, 1.0, 1.0, 0, 0.75, 0, 0) -- minimap
  509.     --driver.id = tfm.exec.addImage("17ce70cb52e.png", "&2", 725 + driver.x/4, 25 + driver.y/4, nil, 1.0, 1.0, 0, 0.67, 0, 0) -- driver
  510.  
  511.     driver.start = true
  512. end
  513.  
  514. function startNewGame()
  515.     if started then
  516.         ui.removeTextArea(10)
  517.         tfm.exec.removeImage(driver.minimap)
  518.         tfm.exec.removeImage(driver.id)
  519.         tfm.exec.removeImage(res[theme].background.id)
  520.        
  521.         local playersList = {}
  522.         local i = 1
  523.         for playerName in next, tfm.get.room.playerList do
  524.             playersList[i] = playerName
  525.             i = i + 1
  526.         end
  527.         startPlayer(playersList[math.random(1, #playersList)]) --
  528.     else
  529.         for n in next, tfm.get.room.playerList do
  530.             startPlayer(n)
  531.         end
  532.     end
  533.    
  534.     tfm.exec.newGame(7883099)
  535. end
  536.  
  537. function startPlayer(playerName)
  538.     driver = {
  539.         name = playerName,
  540.         x = 11.5 * mult,
  541.         y = 10.0 * mult,
  542.         dx = 0,
  543.         dy = 0,
  544.         angle = 0.0,
  545.         fov = 80,
  546.         speed = mult / 3.5,
  547.         start = false,
  548.         timestamp = os.time(),
  549.         id = 0,
  550.         minimap = 0
  551.     }
  552.    
  553.     driver.dx = math.cos(driver.angle) * driver.speed
  554.     driver.dy = math.sin(driver.angle) * driver.speed
  555. end
  556.  
  557. function main()
  558.     for name, driver in pairs(tfm.get.room.playerList) do
  559.         eventNewPlayer(name)
  560.     end
  561.    
  562.     started = false
  563.  
  564.     --tfm.exec.addPhysicObject(0, 400, -600, {type=0, width=10, height=10, foreground=false, friction=0.3, restitution=0, dynamic=false, miceCollision=false, groundCollision=false})
  565. end
  566.  
  567. main()
Add Comment
Please, Sign In to add comment