Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local tfm = tfm
- local system = system
- local ui = ui
- local os = os
- local math = math
- system.disableChatCommandDisplay(nil)
- tfm.exec.disablePhysicalConsumables(true)
- tfm.exec.disableAfkDeath(true)
- tfm.exec.disableAutoNewGame(true)
- tfm.exec.disableAutoShaman(true)
- tfm.exec.disableAutoTimeLeft(true)
- tfm.exec.disableAutoScore(true)
- tfm.exec.disablePhysicalConsumables(true)
- local started
- local driver = {}
- local timer = 0
- local mult = 16
- local modulo = {
- creator = "Indexinel#5948",
- name = "Matrix",
- loading = nil
- }
- --local cumulativeRuntime = 0
- --local runtimeCount = 0
- local isTribe = (string.sub(tfm.get.room.name, 1, 2) == "*\003")
- local rTms
- if isTribe then rTms = 40 else rTms = 60 end
- 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
- local theme = "earth"
- local imgdespawn = {}
- local map = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,1,
- 1,0,0,2,1,3,0,0,0,0,0,0,0,0,0,1,
- 1,0,1,3,0,0,0,0,0,1,1,0,0,0,1,1,
- 1,0,0,2,0,0,1,0,0,0,2,3,2,0,0,1,
- 1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,1,
- 1,0,0,0,0,0,3,0,0,0,0,0,0,1,0,1,
- 1,0,1,0,0,2,1,0,3,0,1,3,0,1,0,1,
- 1,0,1,1,0,0,2,0,2,0,0,1,0,0,0,1,
- 1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
- 1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,
- 1,1,0,2,2,3,0,0,3,1,0,1,0,0,1,1,
- 1,0,0,0,3,0,0,0,2,0,0,2,3,0,0,1,
- 1,0,1,0,0,0,0,2,3,3,0,1,0,0,0,1,
- 1,0,0,0,3,0,0,0,0,0,0,0,0,0,0,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
- }
- local mapSize = 16
- local lcxdis = ((mapSize/2) + 1) * mult
- local lcmax = lcxdis * 2.25
- local lcydis = lcmax / 2
- local keys = {
- 0, -- LEFT
- 1, -- UP
- 2, -- RIGHT
- 3, -- DOWN
- 27, -- ESC
- 67, -- C
- 72, -- H
- 81, -- Q
- 86, -- V
- 88, -- X
- 90 -- Z
- }
- local pi360deg = math.pi * 2
- local pi270deg = math.pi * 1.5
- local pi90deg = math.pi / 2
- local res = {}
- res["def"] = {
- light = "17cdc043c6b.png",
- dark = "17cdc046b4e.png",
- }
- res["snow"] = {
- light = "17ce70c5762.png",
- dark = "17ce70c6ed5.png",
- background = {
- url = "17ce7140914.png", -- Not working, must duplicate
- x = 1895,
- y = 500,
- id = nil,
- }
- }
- res["earth"] = {
- light = "17ce70c8648.png",
- dark = "17ce70c9dbc.png",
- background = {
- url = "17d0c30945c.png",
- x = 3204,
- y = 400,
- id = nil
- }
- }
- function renderRay(id, ray)
- local xpos = (id*10) - 5
- local rs = res[theme]
- local scaleY = 26/ray.distance -- >> = bigger
- local ypos = math.floor(200 - (200 * scaleY) / 2) + 5
- if theme == "def" then scaleX = 0.625 else scaleX = 1.0 end
- if ray.side_hit then
- imgId = rs.dark
- else
- imgId = rs.light
- end
- return tfm.exec.addImage(imgId, "!1", xpos, ypos, nil, scaleX, scaleY, 0, 1.0, 0.5, 0)
- end
- function renderBackground()
- local bg = res[theme].background
- local pl = driver
- local cos = math.cos
- local sin = math.sin
- local floor = math.floor
- if bg ~= nil then
- local lx = lcxdis + (cos(pl.angle) * lcydis) -- 144 = 9.0; 160 = 10.0
- local ly = lcxdis + (sin(pl.angle) * lcydis)
- local dis = lcmax - distance(pl.x, pl.y, lx, ly)
- local scaleY = 1.0 + (dis/lcmax)
- local yPos = floor(205 - ((bg.y * scaleY) / 2)) -- 400 - bg.y
- local xPos = floor(((bg.x/4) * cos(pl.angle/2)) + 0.5)
- if xPos < -(bg.x/2) then
- xPos = xPos + bg.x
- end
- if driver.start then tfm.exec.removeImage(bg.id) end
- res[theme].background.id = tfm.exec.addImage(bg.url, "_1", xPos, yPos, nil, 1.0, scaleY, 0, 1.0, 0.5, 0)
- end
- end
- function raycast(rayAngle)
- local pl = driver
- local lmap = map
- local pi = math.pi
- local mul = mult
- local lshift = bit32.lshift
- local tan = math.tan
- local hx = pl.x
- local hy = pl.y
- local ry, rx, yo, xo, mx, my, mp, dist
- if rayAngle < 0 then
- rayAngle = rayAngle + pi360deg
- elseif rayAngle > pi360deg then
- rayAngle = rayAngle - pi360deg
- end
- local at = -1/tan(rayAngle)
- local rcl = 0
- local disH = 400
- if rayAngle > pi then
- ry = lshift(lshift(driver.y, -4), 4) - 0.0001
- rx = ((pl.y - ry)*at) + pl.x
- yo = -mul
- xo = -yo*at
- end
- if rayAngle < pi then
- ry = lshift(lshift(driver.y, -4), 4) + mul
- rx = ((pl.y - ry)*at) + pl.x
- yo = mul
- xo = -yo*at
- end
- if rayAngle == 0 or rayAngle == pi then
- rx = pl.x
- ry = pl.y
- rcl = 8
- end
- while rcl < 8 do
- mx = lshift(rx, -4)
- my = lshift(ry, -4)
- mp = (my*16) + mx
- if mp > 1 and mp <= 256 and lmap[mp] >= 1 then
- hx = rx
- hy = ry
- disH = distance(pl.x, pl.y, hx, hy)
- rcl = 8
- ltype = lmap[mp]
- else
- rx = rx + xo
- ry = ry + yo
- rcl = rcl + 1
- end
- end
- local disV = 400
- local vx = pl.x
- local vy = pl.y
- local nt = -tan(rayAngle)
- rcl = 0
- if rayAngle > pi90deg and rayAngle < pi270deg then
- rx = lshift(lshift(driver.x, -4), 4) - 0.0001
- ry = ((pl.x - rx)*nt) + pl.y
- xo = -mul
- yo = -xo*nt
- end
- if rayAngle < pi90deg or rayAngle > pi270deg then
- rx = lshift(lshift(driver.x, -4), 4) + mul
- ry = ((pl.x - rx)*nt) + pl.y
- xo = mul
- yo = -xo*nt
- end
- if rayAngle == 0 or rayAngle == pi then
- rx = pl.x
- ry = pl.y
- rcl = 8
- end
- while rcl < 8 do
- mx = lshift(rx, -4)
- my = lshift(ry, -4)
- mp = (my*16) + mx
- if mp > 1 and mp <= 256 and lmap[mp] >= 1 then
- vx = rx
- vy = ry
- disV = distance(pl.x, pl.y, vx, vy)
- rcl = 8
- ltype = lmap[mp]
- else
- rx = rx + xo
- ry = ry + yo
- rcl = rcl + 1
- end
- end
- if disV < disH then
- rx = vx
- ry = vy
- dist = disV
- lHit = true
- elseif disH < disV then
- rx = hx
- ry = hy
- dist = disH
- lHit = false
- else
- dist = disV
- lHit = true
- end
- fa = pl.angle - rayAngle
- if fa < 0 then
- fa = fa + pi360deg
- elseif fa > pi360deg then
- fa = fa - pi360deg
- end
- dist = dist * math.cos(fa)
- local ray = {
- angle = rayAngle,
- distance = dist,
- side_hit = lHit,
- block_type = ltype
- }
- return ray
- end
- function display()
- local pl = driver
- renderBackground()
- local rad = math.rad
- local ra = pl.angle - rad(pl.fov / 2)
- local fov = pl.fov --+ 1
- if ra < 0 then
- ra = ra + pi360deg
- elseif ra > pi360deg then
- ra = ra - pi360deg
- end
- local ray = {}
- local raycastr = raycast
- for r=1, fov do
- ray = raycastr(ra)
- ra = ra + rad(1)
- if ra < 0 then
- ra = ra + pi360deg
- elseif ra > pi360deg then
- ra = ra - pi360deg
- end
- if imgdespawn[r] then tfm.exec.removeImage(imgdespawn[r]) end
- imgdespawn[r] = renderRay(r, ray)
- end
- if driver.id then tfm.exec.removeImage(driver.id) end
- 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)
- textUpdate(driver.name)
- end
- function distance(ax, ay, bx, by)
- return math.sqrt((bx-ax)^2 + (by-ay)^2)
- end
- function eventKeyboard(playerName, key, down, x, y)
- -- local timecheck = os.time()
- local mul = mult
- if playerName == driver.name then
- if driver.timestamp < os.time() - runtimeLimit then
- local po = {
- x = driver.x,
- y = driver.y,
- angle = driver.angle
- }
- local coords
- local ceil = math.ceil
- local floor = math.floor
- if key >= 0 and key <= 3 then
- if key == 3 then -- BACK/DOWN [3]
- driver.x = driver.x - driver.dx
- driver.y = driver.y - driver.dy
- elseif key == 0 then -- LEFT [0]
- driver.x = driver.x + driver.dy
- driver.y = driver.y - driver.dx
- elseif key == 1 then -- FRONT/UP [1]
- driver.x = driver.x + driver.dx
- driver.y = driver.y + driver.dy
- elseif key == 2 then -- RIGHT [2]
- driver.x = driver.x - driver.dy
- driver.y = driver.y + driver.dx
- end
- if map[ceil((floor(po.y/mult) * mul) + floor(driver.x/mul))] >= 1 then
- driver.x = po.x
- end
- if map[ceil((floor(driver.y/mul) * mul) + floor(po.x/mul))] >= 1 then
- driver.y = po.y
- end
- elseif key == 27 or key == 81 then -- ESC / Q
- startNewGame() --system.exit()
- elseif key == 67 or key == 86 or key == 88 or key == 90 then
- if key == 90 then -- Z (-angle1)
- driver.angle = driver.angle - 0.15
- elseif key == 88 then -- X (+angle1)
- driver.angle = driver.angle + 0.15
- elseif key == 67 then -- C (-angle3)
- driver.angle = driver.angle - 0.45
- elseif key == 86 then -- V (+angle3)
- driver.angle = driver.angle + 0.45
- end
- if driver.angle < 0 then
- driver.angle = driver.angle + pi360deg
- elseif driver.angle > pi360deg then
- driver.angle = driver.angle - pi360deg
- end
- driver.dx = math.cos(driver.angle) * driver.speed
- driver.dy = math.sin(driver.angle) * driver.speed
- end
- driver.x = fRound(driver.x, 1)
- driver.y = fRound(driver.y, 1)
- if po.x ~= driver.x or po.y ~= driver.y or driver.angle ~= po.angle then
- display()
- driver.timestamp = os.time()
- end
- --[[cumulativeRuntime = cumulativeRuntime + (os.time() - timecheck)
- runtimeCount = runtimeCount + 1
- print(string.format("%f ms", fRound(cumulativeRuntime / runtimeCount, 3) ) )]]
- end
- end
- if key == 72 then -- h
- eventTextAreaCallback(100, playerName, "help")
- end
- end
- function eventMouse(playerName, x, y)
- if playerName == driver.name then
- if driver.timestamp < os.time() - runtimeLimit then
- driver.angle = driver.angle - fRound(math.rad( (400 - x) / (800/driver.fov) ), 2)
- if driver.angle < 0 then
- driver.angle = driver.angle + pi360deg
- elseif driver.angle > pi360deg then
- driver.angle = driver.angle - pi360deg
- end
- driver.dx = math.cos(driver.angle) * driver.speed
- driver.dy = math.sin(driver.angle) * driver.speed
- if x ~= 400 then
- display()
- driver.timestamp = os.time()
- end
- end
- end
- end
- function fRound(value, pres)
- local mul = 10^pres
- return math.floor((value * mul)) / mul
- end
- function textUpdate(playerName)
- local text = string.format(
- "<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>",
- driver.x,
- driver.y,
- fRound(math.deg(driver.angle), 2)
- )
- if not driver.start then
- ui.addTextArea(0, text, nil, 0, 25, 0, 0, 0x010101, 0x010101, 0, true)
- else
- ui.updateTextArea(0, text, nil)
- end
- end
- function eventTextAreaCallback(id, playerName, event)
- if event == "clear" then
- ui.removeTextArea(id, playerName)
- elseif event == "help" then
- 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)
- end
- end
- function eventChatCommand(playerName, command)
- local arguments = {}
- for arg in command:gmatch("[^%s]+") do
- table.insert(arguments, arg)
- end
- if command == "help" then
- eventTextAreaCallback(100, playerName, "help")
- end
- end
- function eventLoop(time, remaining)
- timer = timer + 500
- ui.updateTextArea(1, string.format("<p align='center'><font size='14'><ROSE>%0.2f</ROSE><J>s</J></font></p>", (timer / 1000)), nil)
- if timer > 3000 then
- if started then
- if driver.timestamp < os.time() - 120000 then -- 2 min
- startNewGame()
- end
- else
- ui.removeTextArea(169)
- tfm.exec.removeImage(modulo.loading)
- startNewGame()
- started = true
- end
- elseif timer == 500 and not started then
- modulo.loading = tfm.exec.addImage("15150c10e92.png", "_1", 0, 0, nil, 1.0, 1.0, 0, 1.0, 0, 0)
- ui.addTextArea(169 , "<font size='96'><p align='center'>Loading...</p></font>", nil, 100, 150, 600, 200, 0x000000, 0x000000, 1.0, true)
- end
- end
- function eventNewPlayer(playerName)
- 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)
- for _, k in ipairs(keys) do
- system.bindKeyboard(playerName, k, false)
- end
- system.bindMouse(playerName)
- end
- function eventPlayerLeft(playerName)
- if driver.name == playerName then
- startNewGame()
- end
- end
- function eventNewGame()
- timer = 0
- display()
- 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)
- 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)
- driver.minimap = tfm.exec.addImage("17ce70c3ff1.png", "&1", 725, 25, nil, 1.0, 1.0, 0, 0.75, 0, 0) -- minimap
- --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
- driver.start = true
- end
- function startNewGame()
- if started then
- ui.removeTextArea(10)
- tfm.exec.removeImage(driver.minimap)
- tfm.exec.removeImage(driver.id)
- tfm.exec.removeImage(res[theme].background.id)
- local playersList = {}
- local i = 1
- for playerName in next, tfm.get.room.playerList do
- playersList[i] = playerName
- i = i + 1
- end
- startPlayer(playersList[math.random(1, #playersList)]) --
- else
- for n in next, tfm.get.room.playerList do
- startPlayer(n)
- end
- end
- tfm.exec.newGame(7883099)
- end
- function startPlayer(playerName)
- driver = {
- name = playerName,
- x = 11.5 * mult,
- y = 10.0 * mult,
- dx = 0,
- dy = 0,
- angle = 0.0,
- fov = 80,
- speed = mult / 3.5,
- start = false,
- timestamp = os.time(),
- id = 0,
- minimap = 0
- }
- driver.dx = math.cos(driver.angle) * driver.speed
- driver.dy = math.sin(driver.angle) * driver.speed
- end
- function main()
- for name, driver in pairs(tfm.get.room.playerList) do
- eventNewPlayer(name)
- end
- started = false
- --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})
- end
- main()
Add Comment
Please, Sign In to add comment