jacob614

modified tpt multiplayer script

Oct 6th, 2012
312
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 52.67 KB | None | 0 0
  1. --Cracker64's Lua Multiplayer Script
  2. --Modified by jacob1
  3. --has half support for multiple people to connect to a tpt server
  4. --works perfectly with 2 people with the extra options
  5. --with more than 2, doesn't sync correctly for everyone
  6. --also don't press 'b' (not sure if I disabled that or not)
  7. --and you'll need to remove my debug stuff and set the IS_SERVER variable
  8. --my mod makes it work better with more options/better syncing
  9. --note: the code/syncing is really badly written
  10. --See forum post http://powdertoy.co.uk/Discussions/Thread/View.html?Thread=14352 for more info
  11. --Update to build 185 to have the mouse wheel change brush size!
  12.  
  13. --Version 1.1.0
  14.  
  15. --TODO's
  16. --sync entire screen with stamps, tpt.load/stave_stamp needs to be changed first
  17. --make WIND work? try to make FAN work
  18. --Add custom deco editor (already finished in favorites menu script)
  19. --CAPS_MODE, replace mode (for build 185+)
  20. --More work on multi-line chat
  21. --Line tool is still off slightly
  22. --Hacky method for PROP (read particle before it runs, check for a change after)
  23.  
  24. --These features are impossible (in v81), don't suggest them, even though they would be great
  25. --load a save/stamp simultaneously
  26. --gravity/wind modes
  27. --signs, STKM controls
  28. --AIR/VAC , WIND, PGRV/NGRV. no pressure,velocity,gravity get functions
  29. --Deco editor (script doesn't run there)
  30.  
  31. --run lua commands typed in the chat window
  32. --disable things that can't sync, re-enable with   TODO: way to re-enable, disable more
  33. --= key resets pressure & velocity/sparks
  34. --sync some simulation options
  35. --half allow multiple people to connect (probably won't finish, the code is really bad)
  36. --works better when using jacob1's mod
  37. --other stuff...
  38. --don't send empty lines in chat
  39. --multiple lines in chat, up to 5(needs more work, optimizations)  v1.1.0
  40. --floodfill delete while holding
  41. --ESC key leaves chatbox_focus
  42. --function to add data handlers so other scripts can add on functions
  43. --Hopefully fixed altgr key    v1.0.9
  44. --Interface flashes a bit after a disconnect --FIXED
  45. --some keys enter spaces in chat --FIXED
  46. --different language keyboard support --just Finnish right now, taking requests for others.
  47. --WL_STREAM draws a bit too much --FIXED
  48. --Drawing on CLNE and such sets ctype --Use a small brush 8 radius or smaller v1.0.8
  49. --Block a few elements/tools from sending and notify
  50. --Zoom window, yes, you can now use the zoom whenever and however you want, pixel art and electronics fans rejoice v1.0.7
  51. --Floodfill ONLY with erase tool  --v1.0.6
  52. --I broke right click, my bad --FIXED v1.0.5
  53. --HEAT/COOL are now perfect (but still laggy)
  54. --FULL BRUSH SUPPORT, triangle,square,circle,ovals.   mouse wheel changing(if using build 185 or higher) v1.0.4
  55. --version check (notify if other person is higher) v1.0.3
  56. --GoL elements besides first don't work and cause errors FIXED v1.0.2
  57. --cursor (flash?) in chat box that moves (delete key) DONE v1.0.1
  58. --connect command from chat window --DONE
  59. --need better chat entering, and general looks--DONE
  60. --chat box DONE
  61. --Walls --DONE
  62. --FIGH and LIGH should only spawn once per click -FIXED
  63. --Energy particles spawning too much --FIXED
  64.  
  65. loader,msg = package.loadlib("luasocket.dll","luaopen_socket_core") --this is the socket core dll, a few shortcut helper scripts are missing. If you want those get the full lua socket download
  66. if loader then loader() else socket=require("socket") end --try loading normal location for socket
  67.  
  68. local PORT = 3000 --Change 3000 to your desired port
  69. local IS_SERVER = true
  70.  
  71. players = {}
  72.  
  73. --if tpt.get_name() == "" then IS_SERVER = false function tpt.get_name() return "jacob2" end end
  74. function newplayer()
  75.     local otheruser = { otherversion = 0, lastpacket = os.clock(), lastpsent = 0, lastping = 0, pingtimer = 0, pingtext = "", timesincelast = os.clock(),
  76.                 sleft = 1, sright = 0, salt = 0, lastmx = 0, lastmy = 0, otheruser = "", otherbrx = 2, otherbry = 2, otherbrushmode = 0, sendbuffer = 0.0167, messagebuffer = "",
  77.                 otherfps = 60, otherdeco = 0xFFFFFFFF, serverclient = nil }
  78.     return otheruser
  79. end
  80. players[1] = newplayer()
  81. players[1].otheruser = tpt.get_name()
  82. local playernum = 1
  83.  
  84. local KEYBOARD = 1 --only change if you have issues. Only other option right now is 2(finnish).
  85. local tcp = nil
  86. local version = 110
  87. local tptversion = tpt.version.build
  88. local usenewbrush = tptversion>=185
  89. local client = nil
  90. local pingtext = ""
  91. local myleft = 1 local myright = 0 --local myalt=0
  92. local statustext = "Waiting...  or type '/c ip port' right in here! \\/"
  93. local infotext = ""
  94. local infoalpha = 0
  95. local mybrx = 2 local mybry = 2
  96. local mybrushmode = 0 --0 circle, 1 square, 2 tri
  97. local kmod = 0
  98. local startx = 0 local starty = 0
  99. local releasetype = 0
  100. local pausenextframe = false
  101. local datasent = 0
  102. local myfps = 60
  103. local fpstime = os.clock()
  104. local fpstimer = 0
  105. local fpscapped = false
  106. local init = true
  107. local selectingdeco = false
  108. local drawingdeco = false
  109.  
  110. local myplayernum = 1
  111. local numplayersconnected = 0
  112.  
  113. local chatbox_messages = {}
  114. local chatbox_newmessage = false
  115. local wheel = 0
  116.  
  117. local ZSIZE = 16
  118. local ZFACTOR = math.floor(256/ZSIZE)
  119. local zoom_en = 0
  120. local zoom_x = math.floor((612-ZSIZE)/2)
  121. local zoom_y = math.floor((384-ZSIZE)/2)
  122. local zoom_wx = 0
  123. local zoom_wy = 0
  124. local zoom_trig = 0
  125.  
  126. local GoLrule = {{0,0,0,0,0,0,0,0,0,2},{0,0,1,3,0,0,0,0,0,2},{0,0,1,3,0,0,2,0,0,2},{0,0,0,2,3,3,1,1,0,2},{0,1,1,2,0,1,2,0,0,2},{0,0,0,3,1,0,3,3,3,2},{0,1,0,3,0,3,0,2,1,2},{0,0,1,2,1,1,2,0,2,2},{0,0,1,3,0,2,0,2,1,2},{0,0,0,2,0,3,3,3,3,2},{0,0,0,3,3,0,0,0,0,2},{0,0,0,2,2,3,0,0,0,2},{0,0,1,3,0,1,3,3,3,2},{0,0,2,0,0,0,0,0,0,2},{0,1,1,3,1,1,0,0,0,2},{0,0,1,3,0,1,1,3,3,2},{0,0,1,1,3,3,2,2,2,2},{0,3,0,0,0,0,0,0,0,2},{0,3,0,3,0,3,0,3,0,2},{1,0,0,2,2,3,1,1,3,2},{0,0,0,3,1,1,0,2,1,4},{0,1,1,2,1,0,0,0,0,3},{0,0,2,1,1,1,1,2,2,6},{0,1,1,2,2,0,0,0,0,3},{0,0,2,0,2,0,3,0,0,3}}
  127. --get different lists for other language keyboards
  128. local keyboardshift = { {before=" qwertyuiopasdfghjklzxcvbnm1234567890-=.,/`|;'[]\\",after=" QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_+><?~\\:\"{}|",},{before=" qwertyuiopasdfghjklzxcvbnm1234567890+,.-'´¨<",after=" QWERTYUIOPASDFGHJKLZXCVBNM!\"#¤%&/()=?;:_*`^>",}  }
  129. local keyboardaltrg = { {nil},{before=" qwertyuiopasdfghjklzxcvbnm1234567890+,.-'¨<",after=" qwertyuiopasdfghjklzxcvbnm1@£$€6{[]}\\,.-'~|",},}
  130.  
  131. function shift(s)
  132.     if keyboardshift[KEYBOARD]~=nil then
  133.         return (s:gsub("(.)",function(c)return keyboardshift[KEYBOARD]["after"]:sub(keyboardshift[KEYBOARD]["before"]:find(c,1,true))end))
  134.     else return s end
  135. end
  136. function altgr(s)
  137.     if keyboardaltgr[KEYBOARD]~=nil then
  138.         return (s:gsub("(.)",function(c)return keyboardaltgr[KEYBOARD]["after"]:sub(keyboardaltgr[KEYBOARD]["before"]:find(c,1,true))end))
  139.     else return s end
  140. end
  141.  
  142. function onstartup()
  143.     tcp = socket.bind("*",PORT,0)
  144.     tcp:settimeout(0)
  145. end
  146. --some luasocket shortcuts
  147. function socket.bind(host, port, backlog)
  148.     local sock, err = socket.tcp()
  149.     if not sock then return nil, err end
  150.     sock:setoption("reuseaddr", true)
  151.     local res, err = sock:bind(host, port)
  152.     if not res then return nil, err end
  153.     res, err = sock:listen(backlog)
  154.     if not res then return nil, err end
  155.     return sock
  156. end
  157. function socket.connect(address, port, laddress, lport)
  158.     local sock, err = socket.tcp()
  159.     if not sock then return nil, err end
  160.     if laddress then
  161.         local res, err = sock:bind(laddress, lport, -1)
  162.         if not res then return nil, err end
  163.     end
  164.     local res, err = sock:connect(address, port)
  165.     if not res then return nil, err end
  166.     return sock
  167. end
  168.  
  169. function isserver()
  170.    return client == nil
  171. end
  172.  
  173. function step()
  174.     if init then init=false if IS_SERVER then onstartup() end end
  175.     local currenttime = os.clock()
  176.     tpt.drawtext(240,10,statustext,255,255,0)
  177.     tpt.drawtext(135,10,"Data sent: "..datasent)
  178.     --tpt.drawtext(100,100,otherdeco .. " " .. sleft .. " " .. sright)
  179.     --[/[
  180.     playernum = 1
  181.     while players[playernum] ~= nil do
  182.         tpt.drawtext(100,100+playernum*10,players[playernum].messagebuffer)
  183.         playernum = playernum + 1
  184.     end
  185.     playernum = 1
  186.     --]/]
  187.     tpt.drawtext(85,10,pingtext)
  188.     --tpt.drawtext(85,50,myleft)
  189.     if infoalpha > 0 then tpt.drawtext(240,20,infotext,255,255,255,infoalpha) infoalpha = infoalpha-5 end
  190.     if tpt.get_name() == "" then statustext = "You need to login first" return end
  191.     if pausenextframe then pausenextframe=false tpt.set_pause(1) end
  192.     --check for new connections
  193.     if IS_SERVER then
  194.         playernum = 2
  195.         while players[playernum] ~= nil and players[playernum].serverclient ~= nil do --find first open slot
  196.             playernum = playernum + 1
  197.         end
  198.         if players[playernum] == nil then
  199.             players[playernum] = newplayer(playernum)
  200.             if tcp == nil then
  201.                 tcp = socket.bind("*",PORT+playernum-2,0)
  202.                 tcp:settimeout(0)
  203.             end
  204.         end
  205.         if players[playernum].serverclient == nil then --allow players to join
  206.             players[playernum].serverclient, err = tcp:accept()
  207.             if players[playernum].serverclient~= nil then players[playernum].serverclient:settimeout(0)
  208.                 statustext = "Got a connection..."
  209.                 numplayersconnected = numplayersconnected + 1
  210.                 init_connection()
  211.                 send_playerlist()
  212.                 tcp:close()
  213.                 tcp = nil
  214.             end
  215.         end
  216.     end
  217.  
  218.     --check streams for data
  219.     if not IS_SERVER then
  220.         if client ~= nil then
  221.             playernum = 1
  222.             data, err = client:receive('*l')
  223.             if data~=nil then readdata(data) end
  224.         end
  225.     else
  226.         playernum = 2
  227.         while players[playernum] ~= nil do
  228.             if players[playernum].serverclient~=nil then
  229.                 data, err = players[playernum].serverclient:receive('*l')
  230.                 if data~=nil then
  231.                     readdata(data)
  232.                     --data = "p "..playernum.."|"..data
  233.                     local playernum_sendto = 2
  234.                     while players[playernum_sendto] ~= nil do
  235.                         if playernum ~= playernum_sendto and players[playernum_sendto].serverclient ~= nil then send(data,playernum_sendto) end
  236.                         playernum_sendto = playernum_sendto + 1
  237.                     end
  238.                 end
  239.             end
  240.             playernum = playernum + 1
  241.         end
  242.     end
  243.  
  244.     --timeout/ping
  245.     playernum = 1
  246.     while false and players[playernum] ~= nil do
  247.         if (players[playernum].serverclient~=nil or client~=nil) then
  248.             local timeout = currenttime-players[playernum].lastpacket
  249.             local pingtimeout = currenttime-players[playernum].lastping
  250.             if timeout>15 then
  251.                 if players[playernum].serverclient ~= nil then players[playernum].serverclient:close() players[playernum].serverclient=nil end
  252.                 if client ~= nil then client:close() client=nil end
  253.                 infotext = "Lost connection to " .. players[playernum].otheruser  infoalpha = 255
  254.                 players[playernum].otheruser = "" pingtext = ""
  255.                 numplayersconnected = numplayersconnected - 1
  256.             end
  257.             if pingtimeout>2 then
  258.                 players[playernum].lastping = currenttime
  259.                 send("ping", playernum)
  260.             end
  261.         end
  262.         playernum = playernum + 1
  263.     end
  264.     playernum = 1
  265.     --update brush selections
  266.     if drawingdeco and (myleft~=248 or myright~=249) then
  267.         myleft = 248
  268.         myright = 249
  269.         send("s 248 249")
  270.     elseif not drawingdeco and (myleft~=tpt.selectedl or myright~=tpt.selectedr) then
  271.         myleft = tpt.selectedl
  272.         myright = tpt.selectedr
  273.         send("s " .. myleft .. " " .. myright)
  274.         if myleft ~= 248 and myleft ~= 249 then drawingdeco = false end
  275.     end
  276.     --new brush size sync
  277.     if usenewbrush and (mybrx~=tpt.brushx or mybry~=tpt.brushy) then
  278.         mybrx = tpt.brushx
  279.         mybry = tpt.brushy
  280.         send("b " .. mybrx .. " " .. mybry)
  281.     end
  282.     --fps sync
  283.     if fpstimer>=60 then
  284.         fpstimer = 0
  285.         myfps = math.floor(60/(currenttime-fpstime))
  286.         fpstime = currenttime
  287.         send("fps " .. myfps)
  288.     end
  289.     fpstimer = fpstimer + 1
  290.     if players[1].otheruser~="" then tpt.drawtext(16,27,players[1].otheruser .. " FPS: " .. players[1].otherfps) end
  291.    
  292.     if selectingdeco then choosecolor() end
  293.     update_chatbox(textboxes[1])
  294.     local i = 1
  295.     while textboxes[i] ~= nil do
  296.         if not textboxes[i].hidden then
  297.             update_textbox(textboxes[i])
  298.         end
  299.         i = i + 1
  300.     end
  301.     if jacob1s_mod then update_options() end
  302.  
  303.     send("")--try sending buffer
  304. end
  305.  
  306. function update_options()
  307.     local ngrav = tpt.newtonian_gravity()
  308.     if ngrav ~= oldngrav then send("ngrav " .. ngrav) end
  309.     oldngrav = ngrav
  310.  
  311.     local aheat = tpt.ambient_heat()
  312.     if aheat ~= oldaheat then send("aheat ".. aheat) end
  313.     oldaheat = aheat
  314.  
  315.     local decoenable = tpt.decorations_enable()
  316.     if decoenable ~= olddecoenable then send("deco ".. decoenable) end
  317.     olddecoenable = decoenable
  318.  
  319.     local heatsim = tpt.heat()
  320.     if heatsim ~= oldheatsim then send("heat ".. heatsim) end
  321.     oldheatsim = heatsim
  322. end
  323.  
  324. local datahandlers = {
  325. b = function(words)
  326.     players[playernum].otherbrx=tonumber(words[2])
  327.     players[playernum].otherbry=tonumber(words[3])
  328.     if words[4]~=nil then players[playernum].otherbrushmode=tonumber(words[4]) end end,
  329. d = function(words) --draw left click
  330.     local n = tonumber(words[2])
  331.     x = n%1024
  332.     y = math.floor(n/1024)
  333.     if tonumber(words[3])~=nil then
  334.         drawstuff(x,y,players[playernum].otherbrx,players[playernum].otherbry,players[playernum].sleft,true,players[playernum].otherbrushmode)
  335.     else
  336.         create_line(players[playernum].lastmx,players[playernum].lastmy,x,y,players[playernum].otherbrx,players[playernum].otherbry,players[playernum].sleft,players[playernum].otherbrushmode)
  337.     end
  338.     players[playernum].lastmx = x
  339.     players[playernum].lastmy = y end,
  340. r = function(words)
  341.     local n = tonumber(words[2])
  342.     x = n%1024
  343.     y = math.floor(n/1024)
  344.     if tonumber(words[3])~=nil then
  345.         drawstuff(x,y,players[playernum].otherbrx,players[playernum].otherbry,players[playernum].sright,true,players[playernum].otherbrushmode)
  346.     else
  347.         create_line(players[playernum].lastmx,players[playernum].lastmy,x,y,players[playernum].otherbrx,players[playernum].otherbry,players[playernum].sright,players[playernum].otherbrushmode)
  348.     end
  349.     players[playernum].lastmx = x
  350.     players[playernum].lastmy = y end,
  351. l = function(words) --line left
  352.     create_line(tonumber(words[2]),tonumber(words[3]),tonumber(words[4]),tonumber(words[5]),players[playernum].otherbrx,players[playernum].otherbry,players[playernum].sleft,players[playernum].otherbrushmode) end,
  353. lr = function(words) --line right
  354.     create_line(tonumber(words[2]),tonumber(words[3]),tonumber(words[4]),tonumber(words[5]),players[playernum].otherbrx,players[playernum].otherbry,players[playernum].sright,players[playernum].otherbrushmode) end,
  355. bo = function(words) --box left
  356.     create_box(tonumber(words[2]),tonumber(words[3]),tonumber(words[4]),tonumber(words[5]),players[playernum].sleft) end,
  357. br = function(words) --box right
  358.     create_box(tonumber(words[2]),tonumber(words[3]),tonumber(words[4]),tonumber(words[5]),players[playernum].sright) end,
  359. s = function(words) --selected elements
  360.     players[playernum].sleft = tonumber(words[2])
  361.     players[playernum].sright = tonumber(words[3]) end,
  362. clear = function(words)
  363.     clearsim()
  364.     infotext = players[playernum].otheruser .. " cleared the screen"
  365.     infoalpha = 255 end,
  366. pause = function(words)
  367.     if words[2] ~= nil then
  368.         tpt.set_pause(tonumber(words[2]))
  369.     else
  370.         tpt.toggle_pause()
  371.     end
  372.     infotext = players[playernum].otheruser .. " toggled pause"
  373.     infoalpha = 255 end,
  374. n = function(words) --username
  375.     players[playernum].otheruser = words[2]
  376.     statustext = "Connected with " .. players[playernum].otheruser end,
  377. fps = function(words) --fps sync
  378.     players[playernum].otherfps = tonumber(words[2])
  379.     --if players[playernum].otherfps<myfps then fpscapped=true tpt.setfpscap(math.max(math.min(players[playernum].otherfps+1,60),3)) --fpscap sync fails epicly
  380.     --elseif fpscapped then if players[playernum].otherfps>=59 then fpscapped=false end tpt.setfpscap(math.max(math.min(players[playernum].otherfps+1,60),3)) end
  381.     players[playernum].sendbuffer = math.min(1/players[playernum].otherfps,0.1) end,
  382. f = function(words) --framestep, syncs pause as well
  383.     pausenextframe = true
  384.     tpt.set_pause(0) end,
  385. ch = function(words) --chat
  386.     table.insert(chatbox_messages, "o:".. command:sub(4))
  387.     if textboxes[1].hidden then chatbox_newmessage = true end end,
  388. cm = function(words) --chat
  389.     table.insert(chatbox_messages, "o:".. command:sub(4))
  390.     if textboxes[1].hidden then chatbox_newmessage = true end
  391.     runluacode(command:sub(4)) end,
  392. ping = function(words)
  393.     send("pong", playernum) end,
  394. pong = function(words)
  395.     pingtext = "Ping: " .. math.ceil((os.clock()-players[playernum].lastping)*1000) end,
  396. ver = function(words)
  397.     players[playernum].otherversion = tonumber(words[2])
  398.     if players[playernum].otherversion>version then statustext = players[playernum].otheruser.." has a newer version" end end,
  399. jver = function(words)
  400.     players[playernum].otherjversion = tonumber(words[2])
  401.     disabled = {[226]=true,[241]=true,[246]=true,[250]=true,[251]=true,[252]=true,[253]=true} end,
  402. ff = function(words)
  403.     x=tonumber(words[2]) y=tonumber(words[3]) c=tonumber(words[4])
  404.     floodparts(x,y,c,-1,-1) end,
  405. ngrav = function(words)
  406.     oldngrav = tonumber(words[2]) tpt.newtonian_gravity(oldngrav)
  407.     infotext = players[playernum].otheruser .. " toggled newtonian gravity"
  408.     infoalpha = 255 end,
  409. aheat = function(words)
  410.     oldaheat = tonumber(words[2]) tpt.ambient_heat(oldaheat)
  411.     infotext = players[playernum].otheruser .. " toggled ambient heat"
  412.     infoalpha = 255 end,
  413. deco = function(words)
  414.     olddecoenable = tonumber(words[2]) tpt.decorations_enable(olddecoenable)
  415.     infotext = players[playernum].otheruser .. " toggled decorations"
  416.     infoalpha = 255 end,
  417. heat = function(words)
  418.     oldheatsim = tonumber(words[2]) tpt.heat(oldheatsim)
  419.     infotext = players[playernum].otheruser .. " toggled heat simulation"
  420.     infoalpha = 255 end,
  421. resetp = function(words)
  422.     if jacob1s_mod then tpt.reset_pressure()
  423.     else tpt.set_pressure(0,0,152,95,0) end
  424.     tpt.reset_velocity()
  425.     infotext = players[playernum].otheruser .. " reset the pressure"
  426.     infoalpha = 255 end,
  427. resets = function(words)
  428.     tpt.reset_spark()
  429.     infotext = players[playernum].otheruser .. " reset sparks"
  430.     infoalpha = 255 end,
  431. cmode = function(words)
  432.     if jacob1s_mod then tpt.display_mode(words[2]) end end, -- still says not implimented in tpt, even though I put back set_cmode
  433. decocol = function(words)
  434.     players[playernum].otherdeco = words[2] end,
  435. p = function(words)
  436.     playernum = tonumber(words[2]) if players[playernum] == nil then players[playernum] = newplayer(playernum) end tpt.drawtext(200,200,words[2]) end,
  437. pnum = function(words)
  438.     myplayernum = tonumber(words[2])
  439.     if players[myplayernum] == nil then players[myplayernum] = newplayer() end
  440.     players[myplayernum].otheruser = tpt.get_name()
  441.     send("p "..myplayernum.."|n "..tpt.get_name().."|s "..myleft.." "..myright.."|b ".. mybrx.." "..mybry.." "..mybrushmode.."|ver "..version, 1)
  442.     end,
  443. }
  444. --function that you can call from other scripts to recieve new packets and run functions
  445. function newdatahandler(mess,func)
  446.     datahandlers[mess]=func
  447. end
  448. --newdatahandler("waffle",function(words) tpt.create(200,200,1) end)
  449.  
  450. function readdata(data)
  451.     lastsent = data
  452.     players[playernum].lastpacket = os.clock()
  453.     local i = string.find(data,"|")
  454.     --go through all commands from the line
  455.     infotext=lastsent  infoalpha=255
  456.     while data~=nil do
  457.         if i~=nil then
  458.            command = string.sub(data,1,i-1)
  459.            --cut the first command off
  460.            data = string.sub(data,i+1)
  461.            i = string.find(data,"|")
  462.         else command=data data=nil --no data left
  463.         end
  464.         local words = {}
  465.         for word in string.gmatch(command, "%w+") do table.insert(words,word) end
  466.         --switch table for reading data, yay!
  467.         if type(datahandlers[words[1]])=="function" then datahandlers[words[1]](words) end
  468.     end
  469. end
  470.  
  471. function split_message(mess)
  472.     local message=mess
  473.     local width=tpt.textwidth(message)
  474.     local lines = {}
  475.     local k=1
  476.     while width>152 do
  477.         local j=15
  478.         local nextwidth = tpt.textwidth(message:sub(1,j))
  479.         while nextwidth<=152 do
  480.             j=j+1
  481.             nextwidth = tpt.textwidth(message:sub(1,j))
  482.         end
  483.         j=j-1
  484.         lines[k]=message:sub(1,j)
  485.         message=message:sub(j+1)
  486.         width=tpt.textwidth(message)
  487.         k=k+1
  488.     end
  489.     lines[k]=message
  490.     return lines
  491. end
  492.  
  493. function connect(ip,port)
  494.     if tpt.get_name() == "" then tpt.log("You need to be logged in") return end
  495.     client, err = socket.connect(ip,port)
  496.     if client~= nil then
  497.         tpt.log("Connected")
  498.         client:setoption("keepalive",true)
  499.         client:settimeout(0)
  500.         --tcp:close()
  501.         --tcp = nil
  502.         init_connection()
  503.     else
  504.         tpt.log("Fail")
  505.     end
  506. end
  507.  
  508. function init_connection()
  509.    tpt.set_pause(1)
  510.    clearsim()
  511.    players[playernum].lastpacket=os.clock()
  512.    tpt.set_console(0)
  513.    tpt.newtonian_gravity(0) oldngrav = 0
  514.    tpt.ambient_heat(0) oldaheat = 0
  515.    tpt.decorations_enable(1) olddecoenable = 1
  516.    tpt.display_mode(3)
  517.    tpt.heat(1) oldheatsim = 1
  518.    tpt.setfpscap(60)
  519.    chatbox_messages = {}
  520.    --send("n "..tpt.get_name().."|s "..myleft.." "..myright.."|b ".. mybrx.." "..mybry.." "..mybrushmode.."|ver "..version, true)--send name
  521.    --if jacob1s_mod then send("jver " .. jacob1s_mod) end
  522.    disabled = { [226]=true,[236]=true,[239]=true,[241]=true,[243]=true,[244]=true,[246]=true,[250]=true,[251]=true,[252]=true,[253]=true}
  523. end
  524.  
  525. function send_playerlist()
  526.     send("pnum " ..playernum, playernum)
  527.     send("p 1|n "..tpt.get_name().."|s "..myleft.." "..myright.."|b ".. mybrx.." "..mybry.." "..mybrushmode.."|ver "..version, playernum)
  528.     local playernum_sendlist = 2
  529.     while players[playernum_sendlist] ~= nil and players[playernum_sendlist].otheruser ~= nil do
  530.         if playernum ~= playernum_sendlist then
  531.             send("p "..playernum_sendlist.."|n "..players[playernum_sendlist].otheruser.."|s "..players[playernum_sendlist].sleft.." "..players[playernum_sendlist].sright.."|b ".. players[playernum_sendlist].otherbrx.." "..players[playernum_sendlist].otherbry.." "..players[playernum_sendlist].otherbrushmode.."|ver "..players[playernum_sendlist].otherversion, playernum)
  532.             if jacob1s_mod then send("jver " .. jacob1s_mod, playernum) end
  533.         end
  534.         playernum_sendlist = playernum_sendlist + 1
  535.     end
  536. end
  537.  
  538. function addtobuffer(message,playernumber)
  539.     players[playernumber].timesincelast = os.clock()-players[playernumber].lastpsent
  540.     if players[playernumber].messagebuffer == "" then players[playernumber].messagebuffer=message return end
  541.     if (message~="") then
  542.         players[playernumber].messagebuffer = players[playernumber].messagebuffer.."|"..message
  543.     end
  544. end
  545.  
  546. function sendtoserver(message)
  547.     addtobuffer(message,playernum)
  548.     if (players[playernum].timesincelast<= players[playernum].sendbuffer or (message=="" and players[playernum].messagebuffer=="")) then
  549.         return
  550.     end
  551.     players[playernum].lastpsent = os.clock()
  552.     local sent = client:send(players[playernum].messagebuffer .. "\n")
  553.     if sent then datasent = datasent + sent end
  554. end
  555.  
  556. function sendtoclients(message, clientnum)
  557.     local send_playernum = 2
  558.     while players[send_playernum] ~= nil do
  559.         if (not (players[send_playernum].timesincelast<= players[send_playernum].sendbuffer or (message=="" and players[send_playernum].messagebuffer=="")) and (not clientnum or clientnum == send_playernum) and players[send_playernum].serverclient ~= nil) then
  560.             players[send_playernum].lastpsent = os.clock()
  561.             local sent = players[send_playernum].serverclient:send("p "..myplayernum.."|"..players[send_playernum].messagebuffer .. "\n")
  562.             if sent then datasent = datasent + sent end
  563.             players[send_playernum].messagebuffer = ""
  564.         end
  565.         send_playernum = send_playernum + 1
  566.     end
  567. end
  568.  
  569. function send(message, clientnum)
  570.  
  571.     if not IS_SERVER then
  572.         if client ~= nil then
  573.             sendtoserver(message)
  574.         end
  575.         players[playernum].messagebuffer = ""
  576.         return
  577.     end
  578.  
  579.     if numplayersconnected > 0 then
  580.         if not clientnum then
  581.             local buffer_playernum = 2
  582.             while players[buffer_playernum] ~= nil do
  583.                 if playernum ~= buffer_playernum and players[buffer_playernum].serverclient ~= nil then
  584.                     addtobuffer(message, buffer_playernum)
  585.                 end
  586.                 buffer_playernum = buffer_playernum + 1
  587.             end
  588.         else
  589.             addtobuffer(message, clientnum)
  590.         end
  591.         sendtoclients(message, clientnum)
  592.     else
  593.         players[playernum].messagebuffer = ""
  594.     end
  595. end
  596.  
  597. function open_zoom(event,kmod)
  598.     if event==1 then
  599.         if kmod==256 then zoom_trig= (zoom_trig>=1 and 0 or 2)
  600.         else zoom_trig=1 end
  601.     end
  602.     if event==2 and zoom_trig==1 then zoom_trig = 0 end
  603.     if zoom_trig==0 and zoom_en==1 then zoom_en=0 end--might go in step
  604.     if zoom_en==2 then zoom_en=1 end
  605. end
  606.  
  607. function keyclicky(key,nkey,modifier,event)
  608.     kmod = modifier%1024--ignore numlock and caps lock for now
  609.     --tpt.drawtext(200,200,nkey)
  610.     if not jacob1s_mod and key=="z" then --TPT still can still open zoom with shortcut lock, so we need to as well
  611.         open_zoom(event, kmod)
  612.     end
  613.     --ignore releases and modifiers
  614.     if (event==2 or (nkey>=300 and nkey<=308)) then return true end
  615.     local i = 1
  616.     while textboxes[i] ~= nil do
  617.         if textboxes[i].focus and not textboxes[i].noteditable then
  618.             return chatkeyprocess(key,nkey,textboxes[i])
  619.         end
  620.         i = i + 1
  621.     end
  622.     if jacob1s_mod and key=="z" then -- jacob1's mod fixed bug where zoom could always open even with shortcuts disabled
  623.         open_zoom(event, kmod)
  624.     end
  625.     if nkey == 49 and (kmod == 1 or kmod == 2) then send("cmode 9") -- doesn't check if in debug mode
  626.     elseif nkey > 48 and nkey < 58 then send("cmode ".. nkey-49)
  627.     elseif nkey == 48 then send("cmode 10") end
  628.     if key==" " then send("pause") end
  629.     if key=="f" then send("f") end
  630.     if key=="=" then if kmod == 64 or kmod == 128 then send("resets") else send("resetp") end end
  631.     if nkey==9 then mybrushmode=(mybrushmode+1)%3 send("b "..mybrx.." "..mybry.." "..mybrushmode) end --tab
  632.     if nkey == 91 then --Left bracket
  633.        if kmod == 256 or kmod == 512 then mybrx=mybrx-1 mybry=mybry-1 --alt
  634.        elseif kmod == 1 or kmod == 2 then mybrx=mybrx-1 --shift
  635.        elseif kmod == 64 or kmod == 128 then mybry=mybry-1 --ctrl
  636.        else mybrx=mybrx-math.ceil((mybrx/5)+.1) mybry=mybry-math.ceil((mybry/5)+.1)
  637.        end
  638.        if mybrx < 0 then mybrx = 0 end
  639.        if mybry < 0 then mybry = 0 end
  640.        if zoom_trig>0 then
  641.            ZSIZE = ZSIZE-1
  642.            if ZSIZE<2 then ZSIZE=2 end
  643.            ZFACTOR = math.floor(256/ZSIZE)
  644.        end
  645.        send("b " .. mybrx .. " " .. mybry)
  646.     elseif nkey == 93 then --Right bracket
  647.        if kmod == 256 or kmod == 512 then mybrx=mybrx+1 mybry=mybry+1 --alt
  648.        elseif kmod == 1 or kmod == 2 then mybrx=mybrx+1 --shift
  649.        elseif kmod == 64 or kmod == 128 then mybry=mybry+1 --ctrl
  650.        else mybrx=mybrx+math.ceil((mybrx/5)+.1) mybry=mybry+math.ceil((mybry/5)+.1)
  651.        end
  652.        if mybrx > 800 then mybrx = 800 end
  653.        if mybry > 800 then mybry = 800 end
  654.        if zoom_trig>0 then
  655.            ZSIZE = ZSIZE+1
  656.            if ZSIZE>60 then ZSIZE=60 end
  657.            ZFACTOR = math.floor(256/ZSIZE)
  658.        end
  659.        send("b " .. mybrx .. " " .. mybry)
  660.     end
  661.     if key == "b" and (kmod == 64 or kmod == 128) then
  662.         if olddecoenable == 1 then olddecoenable = 0 else olddecoenable = 1 end
  663.         tpt.decorations_enable(olddecoenable)
  664.         send("deco " .. olddecoenable)
  665.         return false
  666.      end
  667.      if key == "u" then
  668.         if oldaheat == 1 then oldaheat = 0 else oldaheat = 1 end        
  669.         tpt.ambient_heat(oldaheat)
  670.         send("aheat " .. oldaheat)
  671.         return false
  672.      end
  673.      if key == "b" then
  674.         selectingdeco = true
  675.         update_color()
  676.         local i
  677.         for i = 2, 6 do
  678.             textboxes[i].hidden = false
  679.         end
  680.         return false
  681.     end
  682.    return true
  683. end
  684.  
  685. function mouse_coords_window_to_sim(window_x,window_y)
  686.     if (zoom_en>0 and window_x>=zoom_wx and window_y>=zoom_wy and window_x<(zoom_wx+ZFACTOR*ZSIZE) and window_y<(zoom_wy+ZFACTOR*ZSIZE)) then
  687.         return (math.floor((window_x-zoom_wx)/ZFACTOR)+zoom_x) , (math.floor((window_y-zoom_wy)/ZFACTOR)+zoom_y)
  688.     else
  689.         return window_x,window_y
  690.     end
  691. end
  692.  
  693. local releasestrings = {[1]="l ",[2]="lr ",[3]="bo ",[4]="br "}
  694. function mouseclicky(mousex,mousey,button,event,mouse_wheel)
  695.     wheel = mouse_wheel --wheel should be set to 0 after all used per frame (if used outside this function)
  696.     --no need for wheel checks to change brush size, we can get the size directly
  697.     --tpt.drawtext(200,200,tostring(button))
  698.     if zoom_trig>0 then
  699.         ZSIZE = ZSIZE+wheel
  700.         if ZSIZE>60 then ZSIZE=60 end
  701.         if ZSIZE<2 then ZSIZE=2 end
  702.         ZFACTOR = math.floor(256/ZSIZE)
  703.         if zoom_en<2 then zoom_en=1 end
  704.     end
  705.     if event==2 and zoom_trig>0 and zoom_en<2 then
  706.         local x = mousex-math.floor(ZSIZE/2) local y = mousey-math.floor(ZSIZE/2)
  707.         if x<0 then x=0 end if y<0 then y=0 end
  708.         if x>612-ZSIZE then x=612-ZSIZE end if y>384-ZSIZE then y=384-ZSIZE end
  709.         zoom_x = x
  710.         zoom_y = y
  711.         zoom_wx = (x<306) and 612-ZSIZE*ZFACTOR or 0
  712.         zoom_wy = 0
  713.         zoom_en = 2
  714.         zoom_trig=0
  715.         return true
  716.     end
  717.     if zoom_trig>0 then return true end
  718.     --because this function will now trigger on mouse wheel, the event can possibly be 0
  719.     if event==0 then return true end
  720.     if players[1].otheruser ~= nil and (disabled[myleft] and button==1 or disabled[myright] and button==4) and mousex < 612 and mousey < 384 then
  721.         infotext = "This element does NOT send to your partner" infoalpha=255 return false
  722.     end
  723.     mousex,mousey = mouse_coords_window_to_sim(mousex,mousey)
  724.     if releasetype > 0 then
  725.         if event==2 then
  726.             send(releasestrings[releasetype] .. startx .. " " .. starty .. " " .. mousex .. " " .. mousey)
  727.             releasetype = 0
  728.         end
  729.         return true
  730.     end
  731.     if (event==2) then
  732.         return true
  733.     end
  734.    
  735.     local i = 1
  736.     if event~=3 then
  737.         tpt.set_shortcuts(1)
  738.         local i = 1
  739.         while textboxes[i] ~= nil do
  740.             textboxes[i].focus = false
  741.             i = i + 1
  742.         end
  743.     end
  744.     i = 1
  745.     while textboxes[i] ~= nil do
  746.         if not textboxes[i].hidden and not textboxes[i].noteditable and mousex>textboxes[i].x and mousex<textboxes[i].x+textboxes[i].width and mousey>textboxes[i].y and mousey<textboxes[i].y+textboxes[i].height then
  747.             if event==3 and not textboxes[i].focus then return true end
  748.             textboxes[i].focus = true
  749.             tpt.set_shortcuts(0)
  750.             return false
  751.         end
  752.         i = i + 1
  753.     end
  754.    
  755.     if event == 1 and selectingdeco and mousex > 184 and mousex < 428 and mousey > 199 and mousey < 215 then
  756.         selectingdeco = false
  757.         drawingdeco = true
  758.         local i
  759.         for i = 2, 6 do
  760.             textboxes[i].focus = false
  761.             textboxes[i].hidden = true
  762.         end
  763.     end
  764.     if (mousey > 404 and event == 1) then
  765.         --clear button
  766.         if (mousex >= 486 and mousex <= 502) then
  767.             send("clear")
  768.             return true
  769.         --pause button
  770.         elseif (mousex >= 613) then
  771.             send("pause")
  772.             return true
  773.         end
  774.     end
  775.     if (mousex > 612 and mousex < 628 and event == 1) then
  776.         --chat hide button
  777.         local chaty = 169
  778.         if jacob1s_mod then chaty = chaty - 17 end
  779.         if (mousey>=chaty and mousey<=chaty+14) then
  780.             textboxes[1].hidden = not textboxes[1].hidden
  781.             if not textboxes[1].hidden then textboxes[1].focus = true end
  782.         end
  783.  
  784.         local extra = 0 if jacob1s_mod then extra = 16 end
  785.         if (mousey > 32+extra and mousey < 48+extra) then
  786.            if olddecoenable == 1 then olddecoenable = 0 else olddecoenable = 1 end
  787.            tpt.decorations_enable(olddecoenable)
  788.            send("deco " .. olddecoenable)
  789.            return false
  790.         end
  791.         if (mousey > 48+extra and mousey < 64+extra) then
  792.            if oldngrav == 1 then oldngrav = 0 else oldngrav = 1 end
  793.            tpt.newtonian_gravity(oldngrav)
  794.            send("ngrav " .. oldngrav)
  795.            return false
  796.         end
  797.         if (mousey > 64+extra and mousey < 80+extra) then
  798.            if oldaheat == 1 then oldaheat = 0 else oldaheat = 1 end
  799.            tpt.ambient_heat(oldaheat)
  800.            send("aheat " .. oldaheat)
  801.            return false
  802.         end
  803.     end
  804.  
  805.     if (mousey >= 384 or mousex >= 612) then
  806.         return true
  807.     end
  808.  
  809.     if jacob1s_mod and drawingdeco then
  810.         if button == 1 then
  811.             tpt.set_selected(248)
  812.         elseif button == 4 then
  813.             tpt.set_selected(249)
  814.         end
  815.     end
  816.  
  817.     if (button%2 == 1) then
  818.         if (kmod == 1) then startx,starty = mousex,mousey releasetype=1 return true end
  819.         if (kmod == 64) then startx,starty = mousex,mousey releasetype=3 return true end
  820.         if (kmod == 65) then send("ff "..mousex.." "..mousey.." "..sleft) return true end
  821.         send("d " .. (mousex + mousey*1024) ..  (event==1 and " 1" or "") )
  822.     elseif (button == 4) then
  823.         if (kmod == 1) then startx,starty = mousex,mousey releasetype=2 return true end
  824.         if (kmod == 64) then startx,starty = mousex,mousey releasetype=4 return true end
  825.         if (kmod == 65) then send("ff "..mousex.." "..mousey.." "..sright) return true end
  826.         send("r " .. (mousex + mousey*1024) ..  (event==1 and " 1" or "")  )
  827.     end
  828. end
  829.  
  830. function runluacode(luacode)
  831.     local env = {
  832.         pcall = pcall,
  833.         tonumber = tonumber,
  834.         tostring = tostring,
  835.         string = string,
  836.         table = table,
  837.         math = math,
  838.         os = { clock = os.clock, difftime = os.difftime, time = os.time, date = os.date },
  839.         tpt = tpt
  840.     }
  841.     if luacode:byte(1) == 27 then return nil end
  842.     local func, message = loadstring(luacode)
  843.     if not func then return nil end
  844.     setfenv(func, env)
  845.     pcall(func)
  846. end
  847.  
  848. PT_R = 76 PT_G = 230 PT_B = 167 PT_A = 255
  849.  
  850. function choosecolor()
  851.    tpt.fillrect(182,126,248,91,0,0,0,160) -- make middle dimmer
  852.    tpt.drawrect(184,128,244,87,192,192,192) -- outside box
  853.    tpt.drawrect(184,199,244,0,192,192,192) -- top of OK button
  854.    tpt.drawtext(189,204,"OK")
  855.    tpt.fillrect(384,153,37,38,PT_R,PT_G,PT_B,PT_A) -- Color
  856.    tpt.drawrect(384,153,37,37,192,192,192) -- Color box
  857.    tpt.drawtext(192,136,"Change decoration color",160,160,255)
  858. end
  859.  
  860. function update_color()
  861.     local color = PT_A*16777216 + PT_R*65536 + PT_G*256 + PT_B
  862.     textboxes[6].text = string.format("0x%X", color)
  863.     if jacob1s_mod then tpt.set_decocol(color) end
  864.     drawingdeco = true
  865.     send("decocol "..color)
  866. end
  867. function set_colr(textbox)
  868.     local col = tonumber(textbox.text) if col then if col < 0 then col = 0 elseif col > 255 then col = 255 end PT_R = col textbox.text = tostring(col)
  869.     else textbox.text = "0" PT_R = 0 end textbox.cursorpos = string.len(textbox.text) update_color()
  870. end
  871. function set_colg(textbox)
  872.     local col = tonumber(textbox.text) if col then if col < 0 then col = 0 elseif col > 255 then col = 255 end PT_G = col textbox.text = tostring(col)
  873.     else textbox.text = "0" PT_G = 0 end textbox.cursorpos = string.len(textbox.text) update_color()
  874. end
  875. function set_colb(textbox)
  876.     local col = tonumber(textbox.text) if col then if col < 0 then col = 0 elseif col > 255 then col = 255 end PT_B = col textbox.text = tostring(col)
  877.     else textbox.text = "0" PT_B = 0 end textbox.cursorpos = string.len(textbox.text) update_color()
  878. end
  879. function set_cola(textbox)
  880.     local col = tonumber(textbox.text) if col then if col < 0 then col = 0 elseif col > 255 then col = 255 end PT_A = col textbox.text = tostring(col)
  881.     else textbox.text = "0" PT_A = 0 end textbox.cursorpos = string.len(textbox.text) update_color()
  882. end
  883.  
  884. function movechatcursor(amount,textbox)
  885.     textbox.cursorpos = textbox.cursorpos+amount
  886.     if textbox.cursorpos>string.len(textbox.text) then textbox.cursorpos = string.len(textbox.text) return end
  887.     if textbox.cursorpos<0 then textbox.cursorpos = 0 return end
  888. end
  889.  
  890. function chatkeyprocess(key,nkey,textbox)
  891.     --replace some keys for specific keyboard layouts, make a list later
  892.     if KEYBOARD==2 then if key=="=" then key="´" end if key=="\\" then key="'" end if key=="]" then key="¨" end end
  893.     if nkey==275 then movechatcursor(1,textbox) return false end
  894.     if nkey==276 then movechatcursor(-1,textbox) return false end
  895.     if nkey==27 then textbox.focus=false tpt.set_shortcuts(1) return false end
  896.     if nkey==8 then textbox.text = textbox.text:sub(1,textbox.cursorpos-1)..textbox.text:sub(textbox.cursorpos+1) movechatcursor(-1,textbox) return false end
  897.     if nkey==127 then textbox.text = textbox.text:sub(1,textbox.cursorpos)..textbox.text:sub(textbox.cursorpos+2)  return false end
  898.     if (nkey==13 or nkey==271) and textbox.focus then --enter, about to send, check for commands
  899.         if textbox.onenter then textbox.onenter(textbox) end
  900.     end
  901.     --tpt.drawtext(200,210,nkey)
  902.     if nkey<32 or nkey>=127 then return false end
  903.     local addkey = (kmod==1 or kmod==2) and shift(key) or key
  904.     if (math.floor(kmod/512))==1 then addkey=altgr(key) end
  905.     if tpt.textwidth(textbox.text .. addkey)<760 then textbox.text=textbox.text:sub(1,textbox.cursorpos)..addkey..textbox.text:sub(textbox.cursorpos+1) movechatcursor(1,textbox) end
  906.  
  907.     return false
  908. end
  909.  
  910. function chatbox_commands(textbox)
  911.     if textbox.text == "" then return end
  912.     if players[1].otheruser ~= nil and textbox.text:find("/c") then
  913.         local ip = "127.0.0.1" --textbox.text:sub(4,textbox.text:find(" ",4))
  914.         local port = textbox.text:sub(4,textbox.text:find(" ",4)) --textbox.text:sub(textbox.text:find(" ",4)+1)
  915.         if tonumber(port) then connect(ip,tonumber(port)) else infotext="Bad command" infoalpha=255 end
  916.         textbox.text = "" textbox.cursorpos = 0
  917.         return
  918.     end
  919.     if textbox.text:find("tpt.") then
  920.         send("cm "..textbox.text)
  921.         table.insert(chatbox_messages,textbox.text)
  922.         runluacode(textbox.text)
  923.         textbox.text = "" textbox.cursorpos = 0
  924.         return
  925.     end
  926.     send("ch "..textbox.text) table.insert(chatbox_messages,textbox.text) textbox.text = ""
  927. end
  928.  
  929. function update_chatbox(textbox)
  930.     --icon on right
  931.     local chaty = 169
  932.     if jacob1s_mod then chaty = chaty - 17 end
  933.     if textbox.hidden then
  934.         if chatbox_newmessage then tpt.drawrect(613,chaty,14,14,255,0,0) else tpt.drawrect(613,chaty,14,14,255,255,255) end
  935.         tpt.drawline(614,chaty+6,627,chaty+6,255,255,255,255)
  936.         tpt.drawline(614,chaty+6,617,chaty+3,255,255,255,255)
  937.         tpt.drawline(614,chaty+6,617,chaty+9,255,255,255,255)
  938.     else
  939.         chatbox_newmessage=false
  940.         tpt.drawrect(613,chaty,14,14,255,255,255,255)
  941.         tpt.drawline(614,chaty+6,627,chaty+6,255,255,255,255)
  942.         tpt.drawline(627,chaty+6,624,chaty+3,255,255,255,255)
  943.         tpt.drawline(627,chaty+6,624,chaty+9,255,255,255,255)
  944.     end
  945.     --the main box
  946.     if not textbox.hidden then
  947.         tpt.fillrect(455,27,156,157,0,0,0,160)
  948.         tpt.drawrect(455,27,156,157,255,255,255,95)
  949.         tpt.drawrect(456,28,154,155,255,255,255,255)
  950.         tpt.drawline(457,169,609,169,255,255,255,200)
  951.         while #chatbox_messages >15 do table.remove(chatbox_messages,1) end
  952.         local i = 0
  953.         local offset = 0
  954.         while chatbox_messages[i+1]~= nil do
  955.             local mess = chatbox_messages[i+1]
  956.             if mess:find("o:") then --other user message brighter than self
  957.                 local lines = split_message(mess:sub(3))
  958.                 for k=1,#lines do
  959.                     tpt.drawtext(458,30 + (i+offset+(k-1))*9,lines[k])
  960.                     if k==#lines then offset=offset+(k-1) end
  961.                 end
  962.             else
  963.                 local lines = split_message(mess)
  964.                 for k=1,#lines do
  965.                     tpt.drawtext( 609 - tpt.textwidth(lines[k]) ,30 + (i+offset+(k-1))*9,lines[k],200,200,200)
  966.                     if k==#lines then offset=offset+(k-1) end
  967.                 end
  968.             end
  969.             if i+offset>14 then table.remove(chatbox_messages,1) end --crappy line handling
  970.             i = i+1
  971.         end
  972.     end
  973. end
  974.  
  975. function update_textbox(textbox) -- x = 456, y = 169, width = 154, height = 14
  976.     --display only last characters in overflowing textbox
  977.     local width=tpt.textwidth(textbox.text)
  978.     local display_textbox = textbox.text
  979.     local display_cursorpos = textbox.cursorpos
  980.     while width>textbox.width-6 do
  981.         display_textbox = display_textbox:sub(2)
  982.         width=tpt.textwidth(display_textbox)
  983.         display_cursorpos = display_cursorpos - 1
  984.     end
  985.     tpt.drawtext(textbox.x+4,textbox.y+(textbox.height-10)/2+2,display_textbox)
  986.     if textbox.focus then
  987.         if (os.clock()*1000)%1000 > 500 then
  988.             local cursoradjust=tpt.textwidth(display_textbox:sub(1,display_cursorpos))+1
  989.             tpt.drawline(textbox.x+3+cursoradjust,textbox.y+2,textbox.x+3+cursoradjust,textbox.y+textbox.height-2,255,255,255)
  990.         end
  991.         tpt.drawrect(textbox.x,textbox.y,textbox.width,textbox.height,255,255,0,255)
  992.     elseif not textbox.isthechatbox then --special case for this lua script
  993.         tpt.drawrect(textbox.x,textbox.y,textbox.width,textbox.height,192,192,192,255)
  994.     end
  995. end
  996.  
  997. textboxes = {}
  998. chatbox = { text = "", cursorpos = 0, focus = false, x = 456, y = 169, width = 154, height = 14, hidden = false, isthechatbox = true, onenter = chatbox_commands}
  999. local textr = { text = "76",  cursorpos = 2, focus = false, x = 192, y = 153, width = 45, height = 17, hidden = true, onenter = set_colr}
  1000. local textg = { text = "230", cursorpos = 3, focus = false, x = 240, y = 153, width = 45, height = 17, hidden = true, onenter = set_colg}
  1001. local textb = { text = "167", cursorpos = 3, focus = false, x = 288, y = 153, width = 45, height = 17, hidden = true, onenter = set_colb}
  1002. local texta = { text = "255", cursorpos = 3, focus = false, x = 336, y = 153, width = 45, height = 17, hidden = true, onenter = set_cola}
  1003. local texthex = { text = "", x = 192, y = 172, width = 189, height = 17, hidden = true, noteditable = true}
  1004. table.insert(textboxes, chatbox)
  1005. table.insert(textboxes, textr)
  1006. table.insert(textboxes, textg)
  1007. table.insert(textboxes, textb)
  1008. table.insert(textboxes, texta)
  1009. table.insert(textboxes, texthex)
  1010.  
  1011. if tpt.version.jacob1s_mod then
  1012.    disabled = { [226]=true,[236]=true,[239]=true,[241]=true,[243]=true,[244]=true,[246]=true,[250]=true,[251]=true,[252]=true,[253]=true}
  1013.  
  1014.    --create_line = tpt.create_line
  1015.    function create_line(x1,y1,x2,y2,rx,ry,c,brush)
  1016.       local olddeco
  1017.       if c == 248 then olddeco = tpt.set_decocol() tpt.set_decocol(players[playernum].otherdeco) end
  1018.       tpt.create_line(x1,y1,x2,y2,rx,ry,c,brush)
  1019.       if c == 248 then tpt.set_decocol(olddeco) end
  1020.       --return ret
  1021.    end
  1022.  
  1023.    function drawstuff(x,y,rx,ry,c,fillbool,brush)
  1024.       local fill = 1
  1025.       local olddeco
  1026.       if fillbool == false then
  1027.          fill = 0
  1028.       end
  1029.       if c == 248 then olddeco = tpt.set_decocol() tpt.set_decocol(players[playernum].otherdeco) end
  1030.       tpt.create_parts(x,y,rx,ry,c,fill,brush)
  1031.       if c == 248 then tpt.set_decocol(olddeco) end
  1032.       --return ret
  1033.    end
  1034.  
  1035.    floodparts = tpt.floodfill
  1036.  
  1037.    clearsim = tpt.clear_sim
  1038.  
  1039.    function create_box(x1,y1,x2,y2,c)
  1040.       local i = 0 local j = 0
  1041.       if x1>x2 then i=x2 x2=x1 x1=i end
  1042.       if y1>y2 then j=y2 y2=y1 y1=j end
  1043.       for j=y1, y2 do
  1044.          for i=x1, x2 do
  1045.            tpt.create_parts(i,j,0,0,c,1)
  1046.          end
  1047.       end
  1048.    end
  1049.  
  1050.    jacob1s_mod = tpt.version.jacob1s_mod
  1051.  
  1052. else -- functions not needed when using jacob1's mod
  1053.  
  1054. energytypes = { [18]=true, [31]=true, [136]=true, }
  1055. validwalls = { [222]=true, [223]=true, [224]=true, [225]=true, [227]=true, [228]=true, [229]=true, [230]=true, [231]=true, [232]=true, [233]=true, [234]=true, [235]=true, [240]=true, [242]=true, [245]=true, }
  1056. tools = { [236]=true, [237]=true, [238]=true, [239]=true, }
  1057. disabled = { [226]=true,[236]=true,[239]=true,[241]=true,[243]=true,[244]=true,[246]=true,[250]=true,[251]=true,[252]=true,[253]=true}
  1058. setctype = { [9]=true,[74]=true,[83]=true,[85]=true,[93]=true,[153]=true,}
  1059.  
  1060. function create(x,y,c,small)
  1061.     local t = c%256
  1062.     local v = math.floor(c/256)
  1063.     if t==237 or t==238 then --heat and cool!
  1064.         local temp = tpt.get_property("type",x,y)>0 and tpt.get_property("temp",x,y) or nil
  1065.         if t==237 and temp~=nil and temp<9999 then
  1066.             local heatchange = 4 --implement more temp changes later (ctrl-shift)
  1067.             tpt.set_property("temp",math.min(temp+heatchange,9999),x,y)
  1068.         elseif t==238 and temp~=nil and temp>0 then
  1069.             local heatchange = 4
  1070.             tpt.set_property("temp",math.max(temp-heatchange,0),x,y)
  1071.         end
  1072.         return
  1073.     end
  1074.     if t==248 or t == 249 then --Decoration
  1075.         if t==248 then
  1076.             tpt.set_property("dcolour",players[playernum].otherdeco,x,y)
  1077.         elseif t==249 then
  1078.             tpt.set_property("dcolour",0,x,y)
  1079.         end
  1080.         return
  1081.     end
  1082.     if small then --set ctype for CLNE types if smallish brush
  1083.         if not setctype[c] then
  1084.             local cm = tpt.get_property("type",x,y)
  1085.             if setctype[cm] then
  1086.                 if (cm==74 or cm==153) and (c==35 or c==36) then return end --don't give PCLN ctypes of PSCN or NSCN
  1087.                 tpt.set_property("ctype",c,x,y)
  1088.                 return
  1089.             end
  1090.         end
  1091.     end
  1092.     if t==0 then
  1093.         tpt.delete(x,y)
  1094.     else
  1095.         local i = tpt.create(x,y,t)
  1096.         --special case for GoL creation
  1097.         if t==78 and i>=0 then tpt.set_property("ctype",v,i) tpt.set_property("tmp",GoLrule[(v+2)][10],i) end
  1098.     end
  1099. end
  1100.  
  1101. function create_line(x1,y1,x2,y2,rx,ry,c,brush) -- Taken From Powder Toy Source Code
  1102.    if c == 87 or c == 158 then return end --never do lines of FIGH and LIGH
  1103.    local cp = math.abs(y2-y1)>math.abs(x2-x1)
  1104.    local x = 0 local y = 0 local dx = 0 local dy = 0 local sy = 0 local e = 0.0 local de = 0.0 local first = true
  1105.    if cp then y = x1 x1 = y1 y1 = y y = x2 x2 = y2 y2 = y end
  1106.    if x1 > x2 then y = x1 x1 = x2 x2 = y y = y1 y1 = y2 y2 = y end
  1107.    dx = x2 - x1 dy = math.abs(y2 - y1) if dx ~= 0 then de = dy/dx end
  1108.    y = y1 if y1 < y2 then sy = 1 else sy = -1 end
  1109.    for x = x1, x2 do
  1110.       if cp then
  1111.          drawstuff(y,x,rx,ry,c,first,brush)
  1112.       else
  1113.          drawstuff(x,y,rx,ry,c,first,brush)
  1114.       end
  1115.       first = false
  1116.       e = e + de
  1117.       if e >= 0.5 then
  1118.          y = y + sy
  1119.          e = e - 1
  1120.          if y1<y2 then
  1121.              if y>y2 then return end
  1122.          elseif y<y2 then return end
  1123.          if (rx+ry)==0 or c>=222 then
  1124.             if cp then
  1125.                drawstuff(y,x,rx,ry,c,first,brush)
  1126.             else
  1127.                drawstuff(x,y,rx,ry,c,first,brush)
  1128.             end
  1129.          end
  1130.       end
  1131.    end
  1132. end
  1133.  
  1134. function create_box(x1,y1,x2,y2,c)
  1135.    local i = 0 local j = 0
  1136.    if x1>x2 then i=x2 x2=x1 x1=i end
  1137.    if y1>y2 then j=y2 y2=y1 y1=j end
  1138.    for j=y1, y2 do
  1139.       for i=x1, x2 do
  1140.         create(i,j,c)
  1141.       end
  1142.    end
  1143. end
  1144.  
  1145. function incurrentbrush(i,j,rx,ry,brush)
  1146.     if brush==0 then
  1147.         return (math.pow(i,2)*math.pow(ry,2)+math.pow(j,2)*math.pow(rx,2)<=math.pow(rx,2)*math.pow(ry,2))
  1148.     elseif brush==1 then
  1149.         return (math.abs(i)<=rx and math.abs(j)<=ry)
  1150.     elseif brush==2 then
  1151.         return ((math.abs((rx+2*i)*ry+rx*j) + math.abs(2*rx*(j-ry)) + math.abs((rx-2*i)*ry+rx*j))<=(4*rx*ry))
  1152.     else
  1153.         return false
  1154.     end
  1155. end
  1156.  
  1157. function drawstuff(x,y,rx,ry,c,fill,brush) -- Draws or erases elements
  1158.    local energycheck = energytypes[c]
  1159.    local small = (rx+ry)<=16
  1160.    if c == 87 or c == 158 then create(x,y,c) return end --only draw one pixel of FIGH and LIGH
  1161.    --walls!
  1162.    local dw = false local b = 0
  1163.    if validwalls[c] then
  1164.       dw = true
  1165.       if c~=230 then b = c-100 end
  1166.    end
  1167.    if tools[c] then fill = true end
  1168.    if dw then
  1169.       local r=math.floor(rx/4)
  1170.       local wx = math.floor(x/4)- math.floor(r/2)
  1171.       local wy = math.floor(y/4)- math.floor(r/2)
  1172.       if b==125 then
  1173.          wx = wx + math.floor(r/2)
  1174.          wy = wy + math.floor(r/2)
  1175.          for v=-1,1 do
  1176.             for u=-1,1 do
  1177.                 if (wx+u>=0 and wx+u<153 and wy+v>=0 and wy+v<96 and tpt.get_wallmap(wx+u,wy+v)==125) then
  1178.                     return
  1179.                 end end end
  1180.          tpt.set_wallmap(wx,wy,b)
  1181.          return
  1182.       end
  1183.       tpt.set_wallmap(wx,wy,r+1,r+1,b)
  1184.       return
  1185.    end
  1186.    if rx<=0 then--0 radius loop prevention
  1187.       for j=y-ry,y+ry do
  1188.          if valid(x,j,energycheck,c) then
  1189.             create(x,j,c,small) end
  1190.       end
  1191.       return
  1192.    end
  1193.    local tempy = y local oldy = y
  1194.    if brush==2 then tempy=y+ry end
  1195.    for i = x - rx, x do
  1196.       oldy = tempy
  1197.       local check = incurrentbrush(i-x,tempy-y,rx,ry,brush)
  1198.       if check then
  1199.           while check do
  1200.              tempy = tempy - 1
  1201.              check = incurrentbrush(i-x,tempy-y,rx,ry,brush)
  1202.           end
  1203.           tempy = tempy + 1
  1204.           if fill then
  1205.              local jmax = 2*y - tempy
  1206.              if brush == 2 then jmax=y+ry end
  1207.              for j = tempy, jmax do
  1208.                 if valid(i,j,energycheck,c) then
  1209.                    create(i,j,c,small) end
  1210.                 if i~=x and valid(x+x-i,j,energycheck,c) then
  1211.                    create(x+x-i,j,c,small) end
  1212.              end
  1213.           else
  1214.              if (oldy ~= tempy and brush~=1) or i==x-rx then oldy = oldy - 1 end
  1215.              for j = tempy, oldy+1 do
  1216.                 local i2=2*x-i local j2 = 2*y-j
  1217.                 if brush==2 then j2=y+ry end
  1218.                 if valid(i,j,energycheck,c) then
  1219.                    create(i,j,c,small) end
  1220.                 if i2~=i and valid(i2,j,energycheck,c) then
  1221.                    create(i2,j,c,small) end
  1222.                 if j2~=j and valid(i,j2,energycheck,c) then
  1223.                    create(i,j2,c,small) end
  1224.                 if i2~=i and j2~=j and valid(i2,j2,energycheck,c) then
  1225.                    create(i2,j2,c,small) end
  1226.              end
  1227.           end
  1228.        end
  1229.    end
  1230. end
  1231. function valid(x,y,energycheck,c)
  1232.     if x >= 0 and x < 612 and y >= 0 and y < 384 then
  1233.         if energycheck then
  1234.             if energytypes[tpt.get_property("type",x,y)] then return false end
  1235.         end
  1236.     return true end
  1237. end
  1238. function floodparts(x,y,c,cm,bm)
  1239.     local x1=x local x2=x
  1240.     if cm==-1 then
  1241.         if c==0 then
  1242.             cm = tpt.get_property("type",x,y)
  1243.             if cm==0 then return false end
  1244.         else
  1245.             cm = 0
  1246.         end
  1247.     end
  1248.     --wall check here
  1249.     while x1>=4 do
  1250.         if (tpt.get_property("type",x1-1,y)~=cm) then break end
  1251.         x1 = x1-1
  1252.     end
  1253.     while x2<=608 do
  1254.         if (tpt.get_property("type",x2+1,y)~=cm) then break end
  1255.         x2 = x2+1
  1256.     end
  1257.     for x=x1, x2 do
  1258.         if c==0 then tpt.delete(x,y) end
  1259.         if c>0 and c<222 then create(x,y,c) end
  1260.     end
  1261.     if y>=5 then
  1262.         for x=x1,x2 do
  1263.             if tpt.get_property("type",x,y-1)==cm then
  1264.                 if not floodparts(x,y-1,c,cm,bm) then
  1265.                     return false
  1266.                 end end end
  1267.     end
  1268.     if y<379 then
  1269.         for x=x1,x2 do
  1270.             if tpt.get_property("type",x,y+1)==cm then
  1271.                 if not floodparts(x,y+1,c,cm,bm) then
  1272.                     return false
  1273.                 end end end
  1274.     end
  1275.     return true
  1276. end
  1277.  
  1278. function clearsim()
  1279.     tpt.start_getPartIndex()
  1280.     while tpt.next_getPartIndex() do
  1281.        local index = tpt.getPartIndex()
  1282.        tpt.set_property("type",0,index)
  1283.     end
  1284.     tpt.reset_velocity(0,0,153,96)
  1285.     tpt.set_pressure(0,0,153,96,0)
  1286.     tpt.set_wallmap(0,0,153,96,0)
  1287. end
  1288.  
  1289. end
  1290.  
  1291. tpt.register_keypress(keyclicky)
  1292. tpt.register_mouseclick(mouseclicky)
  1293. tpt.register_step(step)
Advertisement
Add Comment
Please, Sign In to add comment