Advertisement
Piorjade

ComputerCraft MMORPG Client

Jun 26th, 2016
540
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 203.28 KB | None | 0 0
  1. files = {
  2. "Project/startup.lua",
  3. "Project/API/sha",
  4. "Project/game/game.lua",
  5. "Project/game/map",
  6. "Project/maps/editor.lua",
  7. "Project/maps/editorlayout.nfp",
  8. "Project/maps/np",
  9. "Project/maps/house1/data.lvl",
  10. "Project/maps/house1/data.lvlDat",
  11. "Project/maps/house1/editor",
  12. "Project/maps/house2/data.lvl",
  13. "Project/maps/house2/data.lvlDat",
  14. "Project/maps/house2/editor",
  15. }
  16. fileData = {
  17. "side = \"top\" -- PLEASE REPLACE WITH YOUR MODEM SIDE\
  18. \
  19. local function getRunningPath()\
  20. local runningProgram = shell.getRunningProgram()\
  21. local programName = fs.getName(runningProgram)\
  22. return runningProgram:sub( 1, #runningProgram - #programName )\
  23. end\
  24. root = \"/\"\
  25. root = \"/\"..getRunningPath()\
  26. \
  27. os.loadAPI(root..\"/API/sha\")\
  28. \
  29. --[[\
  30. Hello and thanks for trying my experimental game :)\
  31. My goal is to make a multiplayer RPG (which is really hard to make, to be honest)\
  32. \
  33. ]]\
  34. \
  35. --Variablen\
  36. \
  37. rednet.open(side)\
  38. _ver = 2.1\
  39. _verstr = \"2.1\"\
  40. running = true\
  41. oldTerm = term.native()\
  42. connected = false\
  43. tmppw = \"\"\
  44. tmppw2 = \"\"\
  45. servRunning = false\
  46. usrName = \"\"\
  47. servId = 0\
  48. numbrs = {\
  49. \009\"0\",\
  50. \009\"1\",\
  51. \009\"2\",\
  52. \009\"3\",\
  53. \009\"4\",\
  54. \009\"5\",\
  55. \009\"6\",\
  56. \009\"7\",\
  57. \009\"8\",\
  58. \009\"9\",\
  59. }\
  60. msgs = {\
  61. \009\"ping\",\
  62. \009\"true\",\
  63. \009\"username\",\
  64. \009\"exists\",\
  65. \009\"new\",\
  66. \009\"wrong pw\",\
  67. \009\"deleteacc\",\
  68. \009\"changepw\"\
  69. }\
  70. \
  71. --Funktionen\
  72. \
  73. \
  74. function clear(bg, txt)\
  75. \009term.setCursorPos(1,1)\
  76. \009term.setBackgroundColor(bg)\
  77. \009term.setTextColor(txt)\
  78. \009term.clear()\
  79. end\
  80. \
  81. function limitRead(nLimit, replaceChar)\
  82. term.setCursorBlink(true)\
  83. local cX, cY = term.getCursorPos()\
  84. local rString = \"\"\
  85. if replaceChar == \"\" then replaceChar = nil end\
  86. repeat\
  87. local event, p1 = os.pullEvent()\
  88. if event == \"char\" then\
  89. -- Character event\
  90. if #rString + 1 <= nLimit then\
  91. rString = rString .. p1\
  92. write(replaceChar or p1)\
  93. end\
  94. elseif event == \"key\" and p1 == keys.backspace and #rString >= 1 then\
  95. -- Backspace\
  96. rString = string.sub(rString, 1, #rString-1)\
  97. xPos, yPos = term.getCursorPos()\
  98. term.setCursorPos(xPos-1, yPos)\
  99. write(\" \")\
  100. term.setCursorPos(xPos-1, yPos)\
  101. end\
  102. until event == \"key\" and p1 == keys.enter\
  103. term.setCursorBlink(false)\
  104. --print() -- Skip to the next line after clicking enter.\
  105. return rString\
  106. end\
  107. \
  108. function limitReadNumber(nLimit, replaceChar)\
  109. term.setCursorBlink(true)\
  110. local cX, cY = term.getCursorPos()\
  111. local rString = \"\"\
  112. if replaceChar == \"\" then replaceChar = nil end\
  113. repeat\
  114. local event, p1 = os.pullEvent()\
  115. if event == \"char\" then\
  116. -- Character event only numbers\
  117. for _, numbr in ipairs(numbrs) do\
  118. \009if p1 == numbrs[_] then\
  119. \009\009 \009if #rString + 1 <= nLimit then\
  120. \009\009 rString = rString .. p1\
  121. \009 \009 write(replaceChar or p1)\
  122. \009\009 end\
  123. \009\009end\
  124. \009end\
  125. elseif event == \"key\" and p1 == keys.backspace and #rString >= 1 then\
  126. -- Backspace\
  127. rString = string.sub(rString, 1, #rString-1)\
  128. xPos, yPos = term.getCursorPos()\
  129. term.setCursorPos(xPos-1, yPos)\
  130. write(\" \")\
  131. term.setCursorPos(xPos-1, yPos)\
  132. end\
  133. until event == \"key\" and p1 == keys.enter\
  134. term.setCursorBlink(false)\
  135. --print() -- Skip to the next line after clicking enter.\
  136. return rString\
  137. end\
  138. \
  139. function drawLauncher()\
  140. \009running = true\
  141. \009clear(colors.gray, colors.white)\
  142. \009local _p1 = false\
  143. \009local _p2 = false\
  144. \009local _pLogin = false\
  145. \009local _pRegister = false\
  146. \009local function page1()\
  147. \009\009_p1 = true\
  148. \009\009_p2 = false\
  149. \009\009grayWindow = window.create(oldTerm, 10, 5, 25, 10)\
  150. \009\009grayWindow.setBackgroundColor(colors.lightGray)\
  151. \009\009grayWindow.setTextColor(colors.black)\
  152. \009\009grayWindow.clear()\
  153. \009\009term.redirect(grayWindow)\
  154. \009\009term.setCursorPos(2,2)\
  155. \009\009term.setTextColor(colors.lime)\
  156. \009\009term.write(\"Enter server ID & connect.\")\
  157. \009\009idTxtBx = window.create(term.current(), 2, 4, 23, 1)\
  158. \009\009idTxtBx.setBackgroundColor(colors.gray)\
  159. \009\009idTxtBx.setTextColor(colors.lime)\
  160. \009\009idTxtBx.clear()\
  161. \009\009idTxtBx.write(\"Enter server ID...\")\
  162. \009\009term.setCursorPos(2,6)\
  163. \009\009term.setBackgroundColor(colors.gray)\
  164. \009\009term.setTextColor(colors.white)\
  165. \009\009term.write(\"Ping\")\
  166. \009\009term.setBackgroundColor(colors.lime)\
  167. \009\009term.setCursorPos(2,8)\
  168. \009\009term.write(\"Next\")\
  169. \009end\
  170. \
  171. \009local function page2()\
  172. \009\009_p2 = true\
  173. \009\009_p1 = false\
  174. \009\009grayWindow.setBackgroundColor(colors.lightGray)\
  175. \009\009grayWindow.setTextColor(colors.white)\
  176. \009\009grayWindow.clear()\
  177. \009\009term.setCursorPos(2,2)\
  178. \009\009term.setTextColor(colors.lime)\
  179. \009\009term.setBackgroundColor(colors.lightGray)\
  180. \009\009term.write(\"Enter Username\")\
  181. \009\009usrTxtBx = window.create(term.current(), 2, 4, 23, 1)\
  182. \009\009usrTxtBx.setBackgroundColor(colors.gray)\
  183. \009\009usrTxtBx.setTextColor(colors.lime)\
  184. \009\009usrTxtBx.clear()\
  185. \009\009usrTxtBx.write(\"Username...\")\
  186. \009end\
  187. \
  188. \009local function pageRegister()\
  189. \009\009_p2 = false\
  190. \009\009_p1 = false\
  191. \009\009_pLogin = false\
  192. \009\009_pRegister = true\
  193. \
  194. \009\009grayWindow.setBackgroundColor(colors.lightGray)\
  195. \009\009grayWindow.setTextColor(colors.white)\
  196. \009\009grayWindow.clear()\
  197. \009\009term.setCursorPos(2,2)\
  198. \009\009term.setTextColor(colors.lime)\
  199. \009\009term.write(\"Register\")\
  200. \009\009pwTxtBx = window.create(term.current(), 2, 4, 23, 1)\
  201. \009\009pwTxtBx.setBackgroundColor(colors.gray)\
  202. \009\009pwTxtBx.setTextColor(colors.lime)\
  203. \009\009pwTxtBx.clear()\
  204. \009\009pwTxtBx.write(\"Password...\")\
  205. \009\009pwTxtBx2 = window.create(term.current(), 2, 6, 23, 1)\
  206. \009\009pwTxtBx2.setBackgroundColor(colors.gray)\
  207. \009\009pwTxtBx2.setTextColor(colors.lime)\
  208. \009\009pwTxtBx2.clear()\
  209. \009\009pwTxtBx2.write(\"Repeat password...\")\
  210. \009end\
  211. \
  212. \009local function pageLogin()\
  213. \009\009_p2 = false\
  214. \009\009_p1 = false\
  215. \009\009_pRegister = false\
  216. \009\009_pLogin = true\
  217. \009\009grayWindow.setBackgroundColor(colors.lightGray)\
  218. \009\009grayWindow.setTextColor(colors.white)\
  219. \009\009grayWindow.clear()\
  220. \009\009term.setCursorPos(2,2)\
  221. \009\009term.setTextColor(colors.lime)\
  222. \009\009term.write(\"Login: \"..usrName)\
  223. \009\009pwTxtBx = window.create(term.current(), 2, 4, 23, 1)\
  224. \009\009pwTxtBx.setBackgroundColor(colors.gray)\
  225. \009\009pwTxtBx.setTextColor(colors.lime)\
  226. \009\009pwTxtBx.clear()\
  227. \009\009pwTxtBx.write(\"Password...\")\
  228. \009end\
  229. \
  230. \009page1()\
  231. \009while running do\
  232. \009\009local event, button, x, y = os.pullEventRaw(\"mouse_click\")\
  233. \009\009if button == 1 and _p1 and x >= 11 and x <= 33 and y == 8 then\
  234. \009\009\009term.redirect(idTxtBx)\
  235. \009\009\009term.clear()\
  236. \009\009\009term.setCursorPos(1,1)\
  237. \009\009\009servId = limitReadNumber(23)\
  238. \009\009\009term.redirect(grayWindow)\
  239. \009\009\009if #servId > 0 then\
  240. \009\009\009\009servId = tonumber(servId)\
  241. \009\009\009\009succ, t = ping(servId)\
  242. \009\009\009\009if succ then\
  243. \009\009\009\009\009term.setCursorPos(2,6)\
  244. \009\009\009\009\009term.setBackgroundColor(colors.green)\
  245. \009\009\009\009\009term.setTextColor(colors.white)\
  246. \009\009\009\009\009term.write(\"Ping\")\
  247. \009\009\009\009\009connected = true\
  248. \009\009\009\009else\
  249. \009\009\009\009\009term.setCursorPos(2,6)\
  250. \009\009\009\009\009term.setBackgroundColor(colors.red)\
  251. \009\009\009\009\009term.setTextColor(colors.white)\
  252. \009\009\009\009\009term.write(\"Ping\")\
  253. \009\009\009\009\009connected = false\
  254. \009\009\009\009end\
  255. \
  256. \009\009\009end\
  257. \009\009elseif button == 1 and _p1 and connected and x >= 11 and x <= 14 and y == 12 then\
  258. \009\009\009_p1 = false\
  259. \009\009\009_p2 = true\
  260. \009\009\009page2()\
  261. \009\009elseif button == 1 and _p2 and x >= 11 and x <= 33 and y == 8 then\
  262. \009\009\009term.redirect(usrTxtBx)\
  263. \009\009\009term.clear()\
  264. \009\009\009term.setCursorPos(1,1)\
  265. \009\009\009usrName = limitRead(8)\
  266. \009\009\009term.redirect(grayWindow)\
  267. \009\009\009if #usrName > 0 then\
  268. \009\009\009\009succ, t = checkUsrName(usrName)\
  269. \009\009\009\009if succ == \"exists\" then\
  270. \009\009\009\009\009pageLogin()\
  271. \009\009\009\009elseif succ == \"new\" then\
  272. \009\009\009\009\009pageRegister()\
  273. \009\009\009\009elseif succ == \"timeout\" then\
  274. \009\009\009\009\009_p2 = false\
  275. \009\009\009\009\009_p1 = true\
  276. \009\009\009\009\009page1()\
  277. \009\009\009\009else\
  278. \009\009\009\009\009_p2 = false\
  279. \009\009\009\009\009_p1 = true\
  280. \009\009\009\009\009page1()\
  281. \009\009\009\009end\
  282. \009\009\009end\
  283. \009\009elseif button == 1 and _pRegister and x >= 11 and x <= 33 and y == 8 then\
  284. \009\009\009term.redirect(pwTxtBx)\
  285. \009\009\009term.clear()\
  286. \009\009\009term.setCursorPos(1,1)\
  287. \009\009\009tmppw = limitRead(23, \"*\")\
  288. \009\009\009term.redirect(grayWindow)\
  289. \009\009elseif button == 1 and _pRegister and x >= 11 and x <= 33 and y == 10 then\
  290. \009\009\009term.redirect(pwTxtBx2)\
  291. \009\009\009term.clear()\
  292. \009\009\009term.setCursorPos(1,1)\
  293. \009\009\009tmppw2 = limitRead(23, \"*\")\
  294. \009\009\009term.redirect(grayWindow)\
  295. \009\009\009if #tmppw2 > 0 and #tmppw > 0 then\
  296. \009\009\009\009if tmppw == tmppw2 then\
  297. \009\009\009\009\009succ, t = sendRegister()\
  298. \009\009\009\009\009if succ then\
  299. \009\009\009\009\009\009_pRegister = false\
  300. \009\009\009\009\009\009page2()\
  301. \009\009\009\009\009else\
  302. \009\009\009\009\009\009_pRegister = false\
  303. \009\009\009\009\009\009page1()\
  304. \009\009\009\009\009end\
  305. \009\009\009\009else\
  306. \009\009\009\009\009term.redirect(pwTxtBx2)\
  307. \009\009\009\009\009term.setCursorPos(1,1)\
  308. \009\009\009\009\009term.clear()\
  309. \009\009\009\009\009term.setTextColor(colors.red)\
  310. \009\009\009\009\009term.write(\"Password doesn't match.\")\
  311. \009\009\009\009\009term.setTextColor(colors.lime)\
  312. \009\009\009\009\009term.redirect(grayWindow)\
  313. \009\009\009\009end\
  314. \009\009\009end\
  315. \009\009elseif button == 1 and _pLogin and x >= 11 and x <= 33 and y == 8 then\
  316. \009\009\009term.redirect(pwTxtBx)\
  317. \009\009\009term.clear()\
  318. \009\009\009term.setCursorPos(1,1)\
  319. \009\009\009tmppw = limitRead(23, \"*\")\
  320. \009\009\009term.redirect(grayWindow)\
  321. \009\009\009if #tmppw > 0 then\
  322. \009\009\009\009succ, a, b = sendLogin()\
  323. \009\009\009\009if succ == \"success\" then\
  324. \009\009\009\009\009running = false\
  325. \009\009\009\009\009term.redirect(oldTerm)\
  326. \009\009\009\009\009clear(colors.black, colors.white)\
  327. \009\009\009\009\009shell.run(root..\"game/game.lua \"..usrName..\" \"..a..\" \"..root..\" \"..tostring(servId))\
  328. \009\009\009\009\009break\
  329. \009\009\009\009elseif succ == \"wrong pw\" then\
  330. \009\009\009\009\009term.redirect(pwTxtBx)\
  331. \009\009\009\009\009term.clear()\
  332. \009\009\009\009\009term.setCursorPos(1,1)\
  333. \009\009\009\009\009term.setTextColor(colors.red)\
  334. \009\009\009\009\009term.write(\"Wrong Password...\")\
  335. \009\009\009\009\009term.setTextColor(colors.lime)\
  336. \009\009\009\009\009term.redirect(grayWindow)\
  337. \009\009\009\009elseif succ == \"timeout\" then\
  338. \009\009\009\009\009_pLogin = false\
  339. \009\009\009\009\009page1()\
  340. \009\009\009\009end\
  341. \009\009\009end\
  342. \009\009end\
  343. \009end\
  344. end\
  345. \
  346. function ping(id)\
  347. \009rednet.send(id, msgs[1])\
  348. \009id, msg = rednet.receive(3)\
  349. \009if msg == msgs[2] then\
  350. \009\009return true\
  351. \009else\
  352. \009\009return false\
  353. \009end\
  354. end\
  355. \
  356. function sendLogin()\
  357. \009local usrData = {\
  358. \009\009name = \"\",\
  359. \009\009encpw = \"\",\
  360. \009}\
  361. \009usrData.name = usrName\
  362. \009usrData.encpw = sha.sha256(tmppw..usrName)\
  363. \009rednet.send(servId, msgs[4], textutils.serialize(usrData))\
  364. \009id, msg = rednet.receive(3)\
  365. \009if msg == msgs[2] then\
  366. \009\009return \"success\", usrData.encpw\
  367. \009elseif msg == msgs[6] then\
  368. \009\009return \"wrong pw\"\
  369. \009else\
  370. \009\009return \"timeout\"\
  371. \009end\
  372. \
  373. end\
  374. \
  375. function sendRegister()\
  376. \009local usrData = {\
  377. \009\009name = \"\",\
  378. \009\009encpw = \"\",\
  379. \009}\
  380. \009usrData.encpw = sha.sha256(tmppw..usrName)\
  381. \009usrData.name = usrName\
  382. \
  383. \009rednet.send(servId, msgs[5], textutils.serialize(usrData))\
  384. \009id, msg = rednet.receive(3)\
  385. \009if msg == msgs[2] then\
  386. \009\009return true\
  387. \009else\
  388. \009\009return false\
  389. \009end\
  390. end\
  391. \
  392. function checkUsrName(name)\
  393. \009rednet.send(servId, msgs[3], name)\
  394. \009id, msg = rednet.receive(3)\
  395. \009if msg == msgs[4] then\
  396. \009\009return \"exists\"\
  397. \009elseif msg == msgs[5] then\
  398. \
  399. \009\009return \"new\"\
  400. \009else\
  401. \009\009return \"timeout\"\
  402. \009end\
  403. end\
  404. \
  405. --Code\
  406. \
  407. drawLauncher()",
  408. "\009\
  409. \
  410. \
  411. -- \
  412. -- Adaptation of the Secure Hashing Algorithm (SHA-244/256)\
  413. -- Found Here: http://lua-users.org/wiki/SecureHashAlgorithm\
  414. -- \
  415. -- Using an adapted version of the bit library\
  416. -- Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua\
  417. -- \
  418. \
  419. local MOD = 2^32\
  420. local MODM = MOD-1\
  421. \
  422. local function memoize(f)\
  423. local mt = {}\
  424. local t = setmetatable({}, mt)\
  425. function mt:__index(k)\
  426. local v = f(k)\
  427. t[k] = v\
  428. return v\
  429. end\
  430. return t\
  431. end\
  432. \
  433. local function make_bitop_uncached(t, m)\
  434. local function bitop(a, b)\
  435. local res,p = 0,1\
  436. while a ~= 0 and b ~= 0 do\
  437. local am, bm = a % m, b % m\
  438. res = res + t[am][bm] * p\
  439. a = (a - am) / m\
  440. b = (b - bm) / m\
  441. p = p*m\
  442. end\
  443. res = res + (a + b) * p\
  444. return res\
  445. end\
  446. return bitop\
  447. end\
  448. \
  449. local function make_bitop(t)\
  450. local op1 = make_bitop_uncached(t,2^1)\
  451. local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)\
  452. return make_bitop_uncached(op2, 2 ^ (t.n or 1))\
  453. end\
  454. \
  455. local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})\
  456. \
  457. local function bxor(a, b, c, ...)\
  458. local z = nil\
  459. if b then\
  460. a = a % MOD\
  461. b = b % MOD\
  462. z = bxor1(a, b)\
  463. if c then z = bxor(z, c, ...) end\
  464. return z\
  465. elseif a then return a % MOD\
  466. else return 0 end\
  467. end\
  468. \
  469. local function band(a, b, c, ...)\
  470. local z\
  471. if b then\
  472. a = a % MOD\
  473. b = b % MOD\
  474. z = ((a + b) - bxor1(a,b)) / 2\
  475. if c then z = bit32_band(z, c, ...) end\
  476. return z\
  477. elseif a then return a % MOD\
  478. else return MODM end\
  479. end\
  480. \
  481. local function bnot(x) return (-1 - x) % MOD end\
  482. \
  483. local function rshift1(a, disp)\
  484. if disp < 0 then return lshift(a,-disp) end\
  485. return math.floor(a % 2 ^ 32 / 2 ^ disp)\
  486. end\
  487. \
  488. local function rshift(x, disp)\
  489. if disp > 31 or disp < -31 then return 0 end\
  490. return rshift1(x % MOD, disp)\
  491. end\
  492. \
  493. local function lshift(a, disp)\
  494. if disp < 0 then return rshift(a,-disp) end\
  495. return (a * 2 ^ disp) % 2 ^ 32\
  496. end\
  497. \
  498. local function rrotate(x, disp)\
  499. x = x % MOD\
  500. disp = disp % 32\
  501. local low = band(x, 2 ^ disp - 1)\
  502. return rshift(x, disp) + lshift(low, 32 - disp)\
  503. end\
  504. \
  505. local k = {\
  506. 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\
  507. 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\
  508. 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\
  509. 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\
  510. 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\
  511. 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\
  512. 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\
  513. 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\
  514. 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\
  515. 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\
  516. 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\
  517. 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\
  518. 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\
  519. 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\
  520. 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\
  521. 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\
  522. }\
  523. \
  524. local function str2hexa(s)\
  525. return (string.gsub(s, \".\", function(c) return string.format(\"%02x\", string.byte(c)) end))\
  526. end\
  527. \
  528. local function num2s(l, n)\
  529. local s = \"\"\
  530. for i = 1, n do\
  531. local rem = l % 256\
  532. s = string.char(rem) .. s\
  533. l = (l - rem) / 256\
  534. end\
  535. return s\
  536. end\
  537. \
  538. local function s232num(s, i)\
  539. local n = 0\
  540. for i = i, i + 3 do n = n*256 + string.byte(s, i) end\
  541. return n\
  542. end\
  543. \
  544. local function preproc(msg, len)\
  545. local extra = 64 - ((len + 9) % 64)\
  546. len = num2s(8 * len, 8)\
  547. msg = msg .. \"\\128\" .. string.rep(\"\\0\", extra) .. len\
  548. assert(#msg % 64 == 0)\
  549. return msg\
  550. end\
  551. \
  552. local function initH256(H)\
  553. H[1] = 0x6a09e667\
  554. H[2] = 0xbb67ae85\
  555. H[3] = 0x3c6ef372\
  556. H[4] = 0xa54ff53a\
  557. H[5] = 0x510e527f\
  558. H[6] = 0x9b05688c\
  559. H[7] = 0x1f83d9ab\
  560. H[8] = 0x5be0cd19\
  561. return H\
  562. end\
  563. \
  564. local function digestblock(msg, i, H)\
  565. local w = {}\
  566. for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end\
  567. for j = 17, 64 do\
  568. local v = w[j - 15]\
  569. local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))\
  570. v = w[j - 2]\
  571. w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))\
  572. end\
  573. \
  574. local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]\
  575. for i = 1, 64 do\
  576. local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))\
  577. local maj = bxor(band(a, b), band(a, c), band(b, c))\
  578. local t2 = s0 + maj\
  579. local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))\
  580. local ch = bxor (band(e, f), band(bnot(e), g))\
  581. local t1 = h + s1 + ch + k[i] + w[i]\
  582. h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2\
  583. end\
  584. \
  585. H[1] = band(H[1] + a)\
  586. H[2] = band(H[2] + b)\
  587. H[3] = band(H[3] + c)\
  588. H[4] = band(H[4] + d)\
  589. H[5] = band(H[5] + e)\
  590. H[6] = band(H[6] + f)\
  591. H[7] = band(H[7] + g)\
  592. H[8] = band(H[8] + h)\
  593. end\
  594. \
  595. function sha256(msg)\
  596. msg = preproc(msg, #msg)\
  597. local H = initH256({})\
  598. for i = 1, #msg, 64 do digestblock(msg, i, H) end\
  599. return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..\
  600. num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))\
  601. end",
  602. "side = \"top\" --PLEASE CHANGE TO YOUR MODEM SIDE\
  603. os.loadAPI(root..\"API/sha\")\
  604. \
  605. \
  606. \
  607. \
  608. --[[\
  609. MAIN GAME\
  610. PLEASE EXECUTE LAUNCHER FIRST\
  611. ]]\
  612. \
  613. --Variablen\
  614. rednet.open(side)\
  615. _ver = 0.5\
  616. _verstr = \"0.5\"\
  617. running = true\
  618. menu = false\
  619. servId = 0\
  620. chatMax = 0\
  621. chatLeft = 0\
  622. chatMissing = 0\
  623. \
  624. chat = {\
  625. \
  626. }\
  627. \
  628. msgs = {\
  629. \009\"ping\",\
  630. \009\"true\",\
  631. \009\"username\",\
  632. \009\"exists\",\
  633. \009\"new\",\
  634. \009\"wrong pw\",\
  635. \009\"deleteacc\",\
  636. \009\"changepw\",\
  637. \009\"getplayerdata\",\
  638. \009\"spawnplayer\",\
  639. \009\"getworlddata\",\
  640. \009\"uploadplayerdata\",\
  641. \009\"getChat\",\
  642. \009\"sendMessage\"\
  643. }\
  644. \
  645. numbrs = {\
  646. \009\"0\",\
  647. \009\"1\",\
  648. \009\"2\",\
  649. \009\"3\",\
  650. \009\"4\",\
  651. \009\"5\",\
  652. \009\"6\",\
  653. \009\"7\",\
  654. \009\"8\",\
  655. \009\"9\",\
  656. }\
  657. \
  658. usrData = {\
  659. \009name = \"Sir\",\
  660. \009encpw = \"Nobody\",\
  661. }\
  662. \
  663. playerData = {\
  664. \009users = {\
  665. \
  666. \009},\
  667. \009inventory = {\
  668. \
  669. \009},\
  670. \009worlds = {\
  671. \
  672. \009},\
  673. \009posX = {\
  674. \
  675. \009},\
  676. \009posY = {\
  677. \
  678. \009}\
  679. }\
  680. \
  681. mapData = {\
  682. \009\
  683. }\
  684. \
  685. --Hauptfunktionen\
  686. function clear(bg, txt)\
  687. \009term.setCursorPos(1,1)\
  688. \009term.setBackgroundColor(bg)\
  689. \009term.setTextColor(txt)\
  690. \009term.clear()\
  691. end\
  692. \
  693. function limitRead(nLimit, replaceChar)\
  694. term.setCursorBlink(true)\
  695. local cX, cY = term.getCursorPos()\
  696. local rString = \"\"\
  697. if replaceChar == \"\" then replaceChar = nil end\
  698. repeat\
  699. local event, p1 = os.pullEventRaw()\
  700. if event == \"char\" then\
  701. -- Character event\
  702. if #rString + 1 <= nLimit then\
  703. rString = rString .. p1\
  704. write(replaceChar or p1)\
  705. end\
  706. elseif event == \"key\" and p1 == keys.backspace and #rString >= 1 then\
  707. -- Backspace\
  708. rString = string.sub(rString, 1, #rString-1)\
  709. xPos, yPos = term.getCursorPos()\
  710. term.setCursorPos(xPos-1, yPos)\
  711. write(\" \")\
  712. term.setCursorPos(xPos-1, yPos)\
  713. end\
  714. until event == \"key\" and p1 == keys.enter\
  715. term.setCursorBlink(false)\
  716. --print() -- Skip to the next line after clicking enter.\
  717. return rString\
  718. end\
  719. \
  720. function limitReadNumber(nLimit, replaceChar)\
  721. term.setCursorBlink(true)\
  722. local cX, cY = term.getCursorPos()\
  723. local rString = \"\"\
  724. if replaceChar == \"\" then replaceChar = nil end\
  725. repeat\
  726. local event, p1 = os.pullEventRaw()\
  727. if event == \"char\" then\
  728. -- Character event only numbers\
  729. for _, numbr in ipairs(numbrs) do\
  730. \009if p1 == numbrs[_] then\
  731. \009\009 \009if #rString + 1 <= nLimit then\
  732. \009\009 rString = rString .. p1\
  733. \009 \009 write(replaceChar or p1)\
  734. \009\009 end\
  735. \009\009end\
  736. \009end\
  737. elseif event == \"key\" and p1 == keys.backspace and #rString >= 1 then\
  738. -- Backspace\
  739. rString = string.sub(rString, 1, #rString-1)\
  740. xPos, yPos = term.getCursorPos()\
  741. term.setCursorPos(xPos-1, yPos)\
  742. write(\" \")\
  743. term.setCursorPos(xPos-1, yPos)\
  744. end\
  745. until event == \"key\" and p1 == keys.enter\
  746. term.setCursorBlink(false)\
  747. --print() -- Skip to the next line after clicking enter.\
  748. return rString\
  749. end\
  750. \
  751. --Funktionen\
  752. \
  753. function drawIntro(col)\
  754. \009clear(colors.black, colors.white)\
  755. \009term.setTextColor(col)\
  756. \009term.setCursorPos(1,8)\
  757. \009term.write(\"O~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~O\")\
  758. \009term.setCursorPos(1,9)\
  759. \009term.write(\"| A multiplayer RPG |\")\
  760. \009term.setCursorPos(1,10)\
  761. \009term.write(\"| By Piorjade |\")\
  762. \009term.setCursorPos(1,11)\
  763. \009term.write(\"| @2016 |\")\
  764. \009term.setCursorPos(1,12)\
  765. \009term.write(\"O~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~O\")\
  766. end\
  767. \
  768. function redrawMainMenu(c)\
  769. \009if c == 1 then\
  770. \009\009clear(colors.black, colors.white)\
  771. \009\009term.setCursorPos(2, 2)\
  772. \009\009term.write(\"Hello, \"..usrData.name)\
  773. \009\009term.setCursorPos(2, 4)\
  774. \009\009print(\"> Play\")\
  775. \009\009print(\" Change Password\")\
  776. \009\009print(\" Delete User\")\
  777. \009\009print(\" Exit\")\
  778. \009elseif c == 2 then\
  779. \009\009clear(colors.black, colors.white)\
  780. \009\009term.setCursorPos(2, 2)\
  781. \009\009term.write(\"Hello, \"..usrData.name)\
  782. \009\009term.setCursorPos(2, 4)\
  783. \009\009print(\" Play\")\
  784. \009\009print(\" > Change Password\")\
  785. \009\009print(\" Delete User\")\
  786. \009\009print(\" Exit\")\
  787. \009elseif c == 3 then\
  788. \009\009clear(colors.black, colors.white)\
  789. \009\009term.setCursorPos(2, 2)\
  790. \009\009term.write(\"Hello, \"..usrData.name)\
  791. \009\009term.setCursorPos(2, 4)\
  792. \009\009print(\" Play\")\
  793. \009\009print(\" Change Password\")\
  794. \009\009print(\" > Delete User\")\
  795. \009\009print(\" Exit\")\
  796. \009elseif c == 4 then\
  797. \009\009clear(colors.black, colors.white)\
  798. \009\009term.setCursorPos(2, 2)\
  799. \009\009term.write(\"Hello, \"..usrData.name)\
  800. \009\009term.setCursorPos(2, 4)\
  801. \009\009print(\" Play\")\
  802. \009\009print(\" Change Password\")\
  803. \009\009print(\" Delete User\")\
  804. \009\009print(\" > Exit\")\
  805. \009end\
  806. end\
  807. \
  808. function deleteAccount()\
  809. \009rednet.send(servId, msgs[7], textutils.serialize(usrData))\
  810. \009id, msg = rednet.receive(3)\
  811. \009if msg == msgs[2] then\
  812. \009\009return \"success\"\
  813. \009elseif msg == msgs[6] then\
  814. \009\009return \"wrong pw\"\
  815. \009else\
  816. \009\009return \"timeout\"\
  817. \009end\
  818. end\
  819. \
  820. function changePassword(pw)\
  821. \009local changed = {\
  822. \009\009oldData = {\
  823. \009\009\009name = \"\",\
  824. \009\009\009encpw = \"\",\
  825. \
  826. \009\009},\
  827. \009\009newData = {\
  828. \009\009\009name = \"\",\
  829. \009\009\009encpw = \"\",\
  830. \009\009},\
  831. \009}\
  832. \
  833. \009changed.oldData = usrData\
  834. \009changed.newData.name = usrData.name\
  835. \009changed.newData.encpw = sha.sha256(pw)\
  836. \009rednet.send(servId, msgs[8], textutils.serialize(changed))\
  837. \009id, msg = rednet.receive(3)\
  838. \009if msg == msgs[2] then\
  839. \009\009usrData = changed.newData\
  840. \009\009return \"success\"\
  841. \009elseif msg == msgs[6] then\
  842. \009\009return \"wrong pw\"\
  843. \009else\
  844. \009\009return \"timeout\"\
  845. \009end\
  846. \
  847. end\
  848. \
  849. function drawMainMenu()\
  850. \009local timer = 0.08\
  851. \009drawIntro(colors.black)\
  852. \009sleep(timer)\
  853. \009drawIntro(colors.gray)\
  854. \009sleep(timer)\
  855. \009drawIntro(colors.lightGray)\
  856. \009sleep(timer)\
  857. \009drawIntro(colors.white)\
  858. \009sleep(2.25)\
  859. \009drawIntro(colors.lightGray)\
  860. \009sleep(timer)\
  861. \009drawIntro(colors.gray)\
  862. \009sleep(timer)\
  863. \009drawIntro(colors.black)\
  864. \
  865. \009redrawMainMenu(1)\
  866. \009local _mm = 1\
  867. \009menu = true\
  868. \
  869. \009while menu do\
  870. \009\009local event, a, b, c = os.pullEventRaw(\"key\")\
  871. \009\009if a == keys.down and _mm < 4 then\
  872. \009\009\009redrawMainMenu(_mm+1)\
  873. \009\009\009_mm = _mm+1\
  874. \009\009elseif a == keys.up and _mm > 1 then\
  875. \009\009\009redrawMainMenu(_mm-1)\
  876. \009\009\009_mm = _mm-1\
  877. \009\009elseif a == keys.enter and _mm == 1 then\
  878. \009\009\009menu = false\
  879. \009\009\009drawGame()\
  880. \009\009\009--do stuff\
  881. \
  882. \009\009elseif a == keys.enter and _mm == 2 then\
  883. \009\009\009term.setCursorPos(20, 5)\
  884. \009\009\009local tmppw = limitRead(23, \"*\")\
  885. \009\009\009if #tmppw > 0 then\
  886. \009\009\009\009succ = changePassword(tmppw)\
  887. \009\009\009\009if succ == \"success\" then\
  888. \009\009\009\009\009term.setCursorPos(20, 6)\
  889. \009\009\009\009\009term.write(\"Success.\")\
  890. \009\009\009\009\009sleep(1.5)\
  891. \009\009\009\009\009shell.run(root..\"game/game.lua \"..usrData.name..\" \"..usrData.encpw..\" \"..root..\" 1\")\
  892. \009\009\009\009elseif succ == \"wrong pw\" then\
  893. \009\009\009\009\009menu = false\
  894. \009\009\009\009\009clear(colors.black, colors.white)\
  895. \009\009\009\009\009print(\"Error: wrong password!\")\
  896. \009\009\009\009\009sleep(1.5)\
  897. \009\009\009\009\009clear(colors.black, colors.white)\
  898. \009\009\009\009\009break\
  899. \009\009\009\009elseif succ == \"timeout\" then\
  900. \009\009\009\009\009menu = false\
  901. \009\009\009\009\009clear(colors.black, colors.white)\
  902. \009\009\009\009\009print(\"Error: Server timed out.\")\
  903. \009\009\009\009\009sleep(1.5)\
  904. \009\009\009\009\009clear(colors.black, colors.white)\
  905. \009\009\009\009\009break\
  906. \009\009\009\009end\
  907. \009\009\009end\
  908. \
  909. \009\009elseif a == keys.enter and _mm == 3 then\
  910. \009\009\009succ = deleteAccount()\
  911. \009\009\009if succ == \"success\" then\
  912. \009\009\009\009menu = false\
  913. \009\009\009\009clear(colors.black, colors.white)\
  914. \009\009\009\009print(\"Successfully deleted your account, thanks for playing.\")\
  915. \009\009\009\009sleep(1.5)\
  916. \009\009\009\009clear(colors.black, colors.white)\
  917. \009\009\009\009break\
  918. \009\009\009elseif succ == \"wrong pw\" then\
  919. \009\009\009\009menu = false\
  920. \009\009\009\009clear(colors.black, colors.white)\
  921. \009\009\009\009print(\"Error: wrong password!\")\
  922. \009\009\009\009sleep(1.5)\
  923. \009\009\009\009clear(colors.black, colors.white)\
  924. \009\009\009\009break\
  925. \009\009\009elseif succ == \"timeout\" then\
  926. \009\009\009\009menu = false\
  927. \009\009\009\009clear(colors.black, colors.white)\
  928. \009\009\009\009print(\"Error: Server timed out.\")\
  929. \009\009\009\009sleep(1.5)\
  930. \009\009\009\009clear(colors.black, colors.white)\
  931. \009\009\009\009break\
  932. \009\009\009end\
  933. \
  934. \009\009elseif a == keys.enter and _mm == 4 then\
  935. \009\009\009clear(colors.black, colors.white)\
  936. \009\009\009print(\"Thank you for playing.\")\
  937. \009\009\009break\
  938. \009\009end\
  939. \009end\
  940. end\
  941. \
  942. function sendspawn()\
  943. \009rednet.send(servId, msgs[10], usrData.name)\
  944. \009local id, msg, msg2 = rednet.receive(3)\
  945. \009if msg == msgs[2] then\
  946. \009\009playerData = textutils.unserialize(msg2)\
  947. \009\009term.setCursorPos(31,8)\
  948. \009\009return true\
  949. \009end\
  950. end\
  951. \
  952. function getworld()\
  953. \009local usrnmbr = \"bob\"\
  954. \009local found = false\
  955. \009--[[for _, usr in ipairs(playerData.users) do\
  956. \009\009if usr == usrData.name then\
  957. \009\009\009usrnmbr = _\
  958. \009\009\009found = true\
  959. \009\009\009break\
  960. \009\009end\
  961. \009end\
  962. \009if found == false then print(\"player not found\") else print(\"found\") end]]\
  963. \
  964. \009\
  965. \009pInWorldList = window.create(oldTerm, 27, 1, 25, 9)\
  966. \009pInWorldList.setBackgroundColor(colors.gray)\
  967. \009pInWorldList.setTextColor(colors.lime)\
  968. \009pInWorldList.clear()\
  969. \
  970. \009--[[\
  971. \009\009\009\009CLIENT METHOD\
  972. \
  973. \009\009\009\009This method loads the maplayout and the data directly from the client.\
  974. \009\009\009\009I decided to use this while I was testing, because the server sometimes\
  975. \009\009\009\009failed to send the map. (more info in the SERVER METHOD comment)\
  976. \009]]\
  977. \
  978. \009local file = fs.open(root..\"maps/\"..playerData.worlds[usrData.name]..\"/data.lvlDat\",\"r\")\
  979. \009local dat = file.readAll()\
  980. \009mapData = textutils.unserialize(dat)\
  981. \009file.close()\
  982. \009_map = paintutils.loadImage(root..\"maps/\"..playerData.worlds[usrData.name]..\"/data.lvl\")\
  983. \009term.redirect(mapWindow)\
  984. \009clear(colors.black, colors.white)\
  985. \009paintutils.drawImage(_map, 1, 1)\
  986. \009term.redirect(oldTerm)\
  987. \009redrawEntitites()\
  988. \009--[[\
  989. \009\009\009\009SERVER METHOD\
  990. \
  991. \009\009\009\009This method use(d) rednet to DOWNLOAD the map from the server,\
  992. \009\009\009\009so only the server had to update the maps and the Client was basically\
  993. \009\009\009\009universal for ALL servers\
  994. \
  995. \009\009\009\009The problem here is that (at least for me in CCEmuRedux) the server sometimes failed\
  996. \009\009\009\009to send the map-data and layout, which leads to a black screen and no ability to move\
  997. \
  998. \
  999. \009\009\009\009If someone is able to fix this, please PM me on the forum, write a reply on the official topic,\
  1000. \009\009\009\009or try to commit the fix on GitHub (idk how that works for unauthorized people lol)\
  1001. \009]]\
  1002. \
  1003. \
  1004. \
  1005. \009--[[rednet.send(servId, msgs[11], playerData.worlds[usrData.name])\
  1006. \
  1007. \009id, msg, msg2 = rednet.receive(3)\
  1008. \009if msg == msgs[2] then\
  1009. \009\009term.setCursorPos(5,16)\
  1010. \009\009term.write(\"TRUE\")\
  1011. \009\009local map = textutils.unserialize(msg2)\
  1012. \009\009local file = fs.open(root..\"game/map\",\"w\")\
  1013. \009\009file.write(map.layout) \009\009\009\009\009\
  1014. \009\009file.close()\009\009\009\009\009\009\009\009\009\009\009\009\009BUG WITH THIS: the server sometimes sends an empty map layout which leads to breaking the game\
  1015. \009\009mapData = map.data\
  1016. \009\009_map = paintutils.loadImage(root..\"game/map\")\
  1017. \009\009sleep(0.1)\
  1018. \009\009--fs.delete(root..\"game/map\")\
  1019. \009\009clear(colors.black, colors.white)\
  1020. \009\009paintutils.drawImage(_map, 1, 1)\
  1021. \009\009--local file = fs.open(\"/tmp\",\"w\")\
  1022. \009\009--file.write(textutils.serialize(mapData))\009\009\009ENABLE FOR DEBUGGING\
  1023. \009\009--file.close()\
  1024. \009\009redrawEntitites()\
  1025. \009end]]\
  1026. end\
  1027. \
  1028. function redrawMap()\
  1029. \009term.redirect(mapWindow)\
  1030. \009paintutils.drawImage(_map, 1, 1)\
  1031. \009term.redirect(oldTerm)\
  1032. end\
  1033. \
  1034. function redrawEntitites()\
  1035. \009term.redirect(mapWindow)\
  1036. \009local counter = 0\
  1037. \009local myworld = playerData.worlds[usrData.name]\
  1038. \009--[[for _, player in pairs(playerData.users) do\
  1039. \009\009if player == usrData.name then\
  1040. \009\009\009myworld = playerData.worlds[player]\
  1041. \009\009end\
  1042. \009\009\
  1043. \009end]]\
  1044. \009for _, player in pairs(playerData.users) do\
  1045. \009\009if playerData.worlds[player] == myworld then\
  1046. \009\009\009local x = playerData.posX[_]\
  1047. \009\009\009local y = playerData.posY[_]\
  1048. \009\009\009term.setCursorPos(tonumber(x), tonumber(y))\
  1049. \009\009\009term.setTextColor(colors.white)\
  1050. \009\009\009term.setBackgroundColor(colors.black)\
  1051. \009\009\009term.write(\"P\")\
  1052. \009\009\009term.redirect(pInWorldList)\
  1053. \009\009\009term.setCursorPos(1,1+counter)\
  1054. \009\009\009term.setTextColor(colors.lime)\
  1055. \009\009\009term.setBackgroundColor(colors.gray)\
  1056. \009\009\009term.write(player)\
  1057. \009\009\009term.setBackgroundColor(colors.black)\
  1058. \009\009\009term.setTextColor(colors.white)\
  1059. \009\009\009term.redirect(mapWindow)\
  1060. \009\009\009counter = counter+1\
  1061. \009\009end\
  1062. \009end\
  1063. \009for _, ladderY in ipairs(mapData.laddersY) do\
  1064. \009\009term.setCursorPos(mapData.laddersX[_], ladderY)\
  1065. \009\009term.setBackgroundColor(colors.brown)\
  1066. \009\009term.setTextColor(colors.yellow)\
  1067. \009\009term.write(\"H\")\
  1068. \009end\
  1069. \009term.redirect(oldTerm)\
  1070. end\
  1071. \
  1072. function getEntities()\
  1073. \009while true do\
  1074. \009\009sleep(0.1)\
  1075. \009\009rednet.send(servId, msgs[9])\
  1076. \009\009id, msg, msg2 = rednet.receive(0.1)\
  1077. \009\009if msg == msgs[2] then\
  1078. \009\009\009playerData = textutils.unserialize(msg2)\
  1079. \009\009\009local counter = 0\
  1080. \009\009\009term.setBackgroundColor(colors.black)\
  1081. \009\009\009term.setTextColor(colors.white)\
  1082. \009\009\009redrawMap()\
  1083. \009\009\009redrawEntitites()\
  1084. \009\009--[[else\
  1085. \009\009\009clear(colors.black, colors.white)\
  1086. \009\009\009print(\"Timeout.\")\
  1087. \009\009\009sleep(1.5)\
  1088. \009\009\009os.reboot()]]\
  1089. \009\009end\
  1090. \009end\
  1091. end\009\
  1092. \
  1093. function uploadEntities()\
  1094. \009local changed = {\
  1095. \009\009playerData = {\
  1096. \
  1097. \009\009},\
  1098. \009\009changer = {\
  1099. \009\009\009name = \"\",\
  1100. \009\009}\
  1101. \009}\
  1102. \
  1103. \009changed.playerData = playerData\
  1104. \009changed.changer.name = usrData.name\
  1105. \
  1106. \009rednet.send(servId, msgs[12], textutils.serialize(changed))\
  1107. \
  1108. \009id, msg = rednet.receive(0.1)\
  1109. \
  1110. \009--[[if msg ~=msgs[2] then\
  1111. \009\009clear(colors.black, colors.white)\
  1112. \009\009print(\"Timeout.\")\
  1113. \009end]]\
  1114. end\
  1115. \
  1116. function move()\
  1117. \009local lagfaktor = 0.2\
  1118. \009while true do\
  1119. \009\009local event, key = os.pullEvent(\"key_up\")\
  1120. \009\009local usrnmbr = 0\
  1121. \009\009if key == keys.right then\
  1122. \009\009\009--[[for _, usr in pairs(playerData.users) do\
  1123. \009\009\009\009if usr == usrData.name then\
  1124. \009\009\009\009\009usrnmbr = _\
  1125. \009\009\009\009end\
  1126. \009\009\009end]]\
  1127. \009\009\009oldX = tonumber(playerData.posX[usrData.name])\
  1128. \009\009\009oldY = tonumber(playerData.posY[usrData.name])\
  1129. \009\009\009local block = false\
  1130. \009\009\009for _, bY in ipairs(mapData.blocksY) do\
  1131. \009\009\009\009\009if oldX+1 == mapData.blocksX[_] and oldY == bY then\
  1132. \009\009\009\009\009\009term.setCursorPos(27, 3)\
  1133. \009\009\009\009\009\009term.setTextColor(colors.white)\
  1134. \009\009\009\009\009\009term.write(\"BLOCK\")\
  1135. \009\009\009\009\009\009block = true\
  1136. \009\009\009\009\009\009break\
  1137. \009\009\009\009\009else\
  1138. \009\009\009\009\009\009block = false\
  1139. \009\009\009\009\009end\
  1140. \009\009\009end\
  1141. \009\009\009if block ~= true then\
  1142. \009\009\009\009term.setCursorPos(27, 3)\
  1143. \009\009\009\009term.setTextColor(colors.white)\
  1144. \009\009\009\009term.write(\"BLECK\")\
  1145. \009\009\009\009playerData.posX[usrData.name] = playerData.posX[usrData.name]+1\
  1146. \009\009\009\009uploadEntities()\
  1147. \009\009\009\009redrawMap()\
  1148. \009\009\009\009redrawEntitites()\
  1149. \009\009\009end\009\
  1150. \009\009\009sleep(lagfaktor)\
  1151. \009\009elseif key == keys.left then\
  1152. \009\009\009--[[for _, usr in ipairs(playerData.users) do\
  1153. \009\009\009\009if usr == usrData.name then\
  1154. \009\009\009\009\009usrnmbr = _\
  1155. \009\009\009\009end\
  1156. \009\009\009end]]\
  1157. \009\009\009oldX = tonumber(playerData.posX[usrData.name])\
  1158. \009\009\009oldY = tonumber(playerData.posY[usrData.name])\
  1159. \009\009\009local block = false\
  1160. \009\009\009for _, bY in ipairs(mapData.blocksY) do\
  1161. \009\009\009\009\009if oldX-1 == mapData.blocksX[_] and oldY == bY then\
  1162. \009\009\009\009\009\009term.setCursorPos(27, 3)\
  1163. \009\009\009\009\009\009term.setTextColor(colors.white)\
  1164. \009\009\009\009\009\009term.write(\"BLOCK\")\
  1165. \009\009\009\009\009\009block = true\
  1166. \009\009\009\009\009\009break\
  1167. \009\009\009\009\009else\
  1168. \009\009\009\009\009\009block = false\
  1169. \009\009\009\009\009end\
  1170. \009\009\009end\
  1171. \009\009\009if block ~= true then\
  1172. \009\009\009\009term.setCursorPos(27, 3)\
  1173. \009\009\009\009term.setTextColor(colors.white)\
  1174. \009\009\009\009term.write(\"BLECK\")\
  1175. \009\009\009\009playerData.posX[usrData.name] = playerData.posX[usrData.name]-1\
  1176. \009\009\009\009uploadEntities()\
  1177. \009\009\009\009redrawMap()\
  1178. \009\009\009\009redrawEntitites()\
  1179. \009\009\009end\009\
  1180. \009\009\009sleep(lagfaktor)\
  1181. \009\009elseif key == keys.down then\
  1182. \009\009\009oldY = tonumber(playerData.posY[usrData.name])\
  1183. \009\009\009oldX = tonumber(playerData.posX[usrData.name])\
  1184. \009\009\009local block = false\
  1185. \009\009\009for _, bY in ipairs(mapData.blocksY) do\
  1186. \009\009\009\009\009if oldY+1 == bY and oldX == mapData.blocksX[_] then\
  1187. \009\009\009\009\009\009term.setCursorPos(27, 3)\
  1188. \009\009\009\009\009\009term.setTextColor(colors.white)\
  1189. \009\009\009\009\009\009term.write(\"BLOCK\")\
  1190. \009\009\009\009\009\009block = true\
  1191. \009\009\009\009\009\009break\
  1192. \009\009\009\009\009else\
  1193. \009\009\009\009\009\009\
  1194. \009\009\009\009\009\009block = false\
  1195. \009\009\009\009\009end\
  1196. \009\009\009end\
  1197. \009\009\009if block ~= true then\
  1198. \009\009\009\009term.setCursorPos(27, 3)\
  1199. \009\009\009\009term.setTextColor(colors.white)\
  1200. \009\009\009\009term.write(\"BLECK\")\
  1201. \
  1202. \009\009\009\009playerData.posY[usrData.name] = playerData.posY[usrData.name]+1\
  1203. \009\009\009\009uploadEntities()\
  1204. \009\009\009\009redrawMap()\
  1205. \009\009\009\009redrawEntitites()\
  1206. \009\009\009end\
  1207. \009\009\009sleep(lagfaktor)\
  1208. \009\009elseif key == keys.up then\
  1209. \009\009\009oldY = tonumber(playerData.posY[usrData.name])\
  1210. \009\009\009oldX = tonumber(playerData.posX[usrData.name])\
  1211. \009\009\009local block = false\
  1212. \009\009\009for _, bY in ipairs(mapData.blocksY) do\
  1213. \009\009\009\009\009if oldY-1 == bY and oldX == mapData.blocksX[_] then\
  1214. \009\009\009\009\009\009term.setCursorPos(27, 3)\
  1215. \009\009\009\009\009\009term.setTextColor(colors.white)\
  1216. \009\009\009\009\009\009term.write(\"BLOCK\")\
  1217. \009\009\009\009\009\009block = true\
  1218. \009\009\009\009\009\009break\
  1219. \009\009\009\009\009else\
  1220. \009\009\009\009\009\009\
  1221. \009\009\009\009\009\009block = false\
  1222. \009\009\009\009\009end\
  1223. \009\009\009end\
  1224. \009\009\009if block ~= true then\
  1225. \009\009\009\009term.setCursorPos(27, 3)\
  1226. \009\009\009\009term.setTextColor(colors.white)\
  1227. \009\009\009\009term.write(\"BLECK\")\
  1228. \
  1229. \009\009\009\009playerData.posY[usrData.name] = playerData.posY[usrData.name]-1\
  1230. \009\009\009\009uploadEntities()\
  1231. \009\009\009\009redrawMap()\
  1232. \009\009\009\009redrawEntitites()\
  1233. \009\009\009end\
  1234. \009\009\009sleep(lagfaktor)\
  1235. \009\009elseif key == keys.enter then\
  1236. \009\009\009oldY = tonumber(playerData.posY[usrData.name])\
  1237. \009\009\009oldX = tonumber(playerData.posX[usrData.name])\
  1238. \009\009\009local block = true\
  1239. \009\009\009local ladderdest = \"house1\"\
  1240. \009\009\009for _, bY in ipairs(mapData.laddersY) do\
  1241. \009\009\009\009if oldY == bY+1 and oldX == mapData.laddersX[_] or oldY == bY-1 and oldX == mapData.laddersX[_] or oldY == bY and oldX == mapData.laddersX[_]-1 or oldY == bY and oldX == mapData.laddersX[_]+1 then\
  1242. \009\009\009\009\009term.setCursorPos(27,3)\
  1243. \009\009\009\009\009term.setTextColor(colors.white)\
  1244. \009\009\009\009\009term.write(\"BLACK\")\
  1245. \009\009\009\009\009block = false\
  1246. \009\009\009\009\009ladderdest = mapData.ladderDestination[_]\
  1247. \009\009\009\009\009\009break\
  1248. \009\009\009\009else\
  1249. \
  1250. \009\009\009\009\009block = true\
  1251. \009\009\009\009end\
  1252. \009\009\009end\
  1253. \009\009\009if block ~= true then\
  1254. \009\009\009\009playerData.worlds[usrData.name] = ladderdest\
  1255. \009\009\009\009uploadEntities()\
  1256. \009\009\009\009--drawGame()\
  1257. \009\009\009\009getworld()\
  1258. \009\009\009\009--[[redrawMap()\
  1259. \009\009\009\009redrawEntitites()]]\
  1260. \009\009\009end\
  1261. \009\009\009sleep(lagfaktor)\
  1262. \009\009end\
  1263. \
  1264. \009end\
  1265. end\
  1266. \
  1267. function getChat()\
  1268. \009while true do\
  1269. \
  1270. \009\009local id, msg, msg2 = rednet.receive(tostring(servId), 0.1)\
  1271. \009\009if tonumber(msg2) == servId then\
  1272. \009\009\009chatWindow.scroll(-1)\
  1273. \009\009\009chatWindow.setCursorPos(1,1)\
  1274. \009\009\009term.redirect(chatWindow)\
  1275. \009\009\009term.write(msg)\
  1276. \009\009\009term.redirect(oldTerm)\
  1277. \009\009end\
  1278. \009end\
  1279. end\
  1280. \
  1281. \
  1282. function sendMessage()\
  1283. \009--while true do\
  1284. \009\009--local _, k = os.pullEvent(\"key\")\
  1285. \009\009--if k == keys.t then\
  1286. \009\009\009--reading = true\
  1287. \009\009\009term.redirect(chatBox)\
  1288. \009\009\009term.setBackgroundColor(colors.lightGray)\
  1289. \009\009\009term.setTextColor(colors.lime)\
  1290. \009\009\009term.clear()\
  1291. \009\009\009term.setCursorPos(1,1)\
  1292. \009\009\009term.write(\"> \")\
  1293. \009\009\009term.setCursorBlink(true)\
  1294. \009\009\009local e = limitRead(15)\
  1295. \009\009\009term.setCursorBlink(false)\
  1296. \009\009\009--reading = false\
  1297. \009\009\009term.redirect(oldTerm)\
  1298. \009\009\009\
  1299. \009\009\009chatWindow.scroll(-1)\
  1300. \009\009\009chatWindow.setCursorPos(1,1)\
  1301. \009\009\009chatWindow.setBackgroundColor(colors.gray)\
  1302. \009\009\009chatWindow.setTextColor(colors.lime)\
  1303. \009\009\009chatWindow.write(usrData.name..\": \"..e)\
  1304. \009\009\009\
  1305. \009\009\009rednet.broadcast(usrData.name..\": \"..e, tostring(servId))\
  1306. \009\009\009\
  1307. \009\009--end\
  1308. \009--end\
  1309. end\
  1310. \
  1311. function drawGame()\
  1312. \009clear(colors.black, colors.white)\
  1313. \009game = true\
  1314. \009a = sendspawn()\
  1315. \009if a == false then\
  1316. \009\009print(\"Error: Unknown.\")\
  1317. \009\009game= false\
  1318. \009end\
  1319. \009\
  1320. \009chatWindow = window.create(oldTerm, 1, 11, 25, 8)\
  1321. \009chatWindow.setBackgroundColor(colors.gray)\
  1322. \009chatWindow.setTextColor(colors.lime)\
  1323. \009chatWindow.clear()\
  1324. \009chatBox = window.create(oldTerm, 1, 19, 25, 1)\
  1325. \009chatBox.setBackgroundColor(colors.lightGray)\
  1326. \009chatBox.setTextColor(colors.lime)\
  1327. \009chatBox.clear()\
  1328. \009mapWindow = window.create(oldTerm, 1, 1, 25, 9)\
  1329. \009mapWindow.setBackgroundColor(colors.black)\
  1330. \009mapWindow.setTextColor(colors.white)\
  1331. \009mapWindow.clear()\
  1332. \009getworld()\
  1333. \009local c1 = coroutine.create(getEntities)\
  1334. \009local c2 = coroutine.create(move)\
  1335. \009local c3 = coroutine.create(getChat)\
  1336. \009local c5 = coroutine.create(sendMessage)\
  1337. \
  1338. \009local evt = {}\
  1339. \009while true do\
  1340. \009\009\
  1341. \009\009if evt[2] ~= keys.t or evt[2] ~= keys.delete then\
  1342. \009\009\009coroutine.resume(c1, unpack(evt))\
  1343. \009\009\009coroutine.resume(c2, unpack(evt))\
  1344. \009\009\009coroutine.resume(c3, unpack(evt))\
  1345. \009\009end\
  1346. \009\009--coroutine.resume(c5, unpack(evt))\
  1347. \009\009evt = {os.pullEvent()}\
  1348. \009\009if evt[1] == \"key\" and evt[2] == keys.delete then\
  1349. \009\009\009clear(colors.black, colors.white)\
  1350. \009\009\009break\
  1351. \009\009elseif evt[1] == \"key\" and evt[2] == keys.t then\
  1352. \009\009\009sendMessage()\
  1353. \009\009\009evt = {}\
  1354. \009\009\009c1 = nil\
  1355. \009\009\009c2 = nil\
  1356. \009\009\009c3 = nil\
  1357. \009\009\009c1 = coroutine.create(getEntities)\
  1358. \009\009\009c2 = coroutine.create(move)\
  1359. \009\009\009c3 = coroutine.create(getChat)\
  1360. \009\009\009coroutine.resume(c1, unpack(evt))\
  1361. \009\009\009coroutine.resume(c2, unpack(evt))\
  1362. \009\009\009coroutine.resume(c3, unpack(evt))\
  1363. \009\009end\
  1364. \009end\
  1365. end\
  1366. \
  1367. --Code\
  1368. \
  1369. \
  1370. local args = {...}\
  1371. \
  1372. if #args == 4 then\
  1373. \009root = args[3]\
  1374. \009servId = tonumber(args[4])\
  1375. \009os.loadAPI(root..\"/API/sha\")\
  1376. \009usrData.name = args[1]\
  1377. \009usrData.encpw = args[2]\
  1378. \009--do stuff\
  1379. else\
  1380. \009clear(colors.black, colors.white)\
  1381. \009print(\"Please execute the launcher...\")\
  1382. end\
  1383. oldTerm = term.native()\
  1384. drawMainMenu()",
  1385. "",
  1386. "--[[\
  1387. Map maker for my MMORPG\
  1388. Intended to be used by gameserver-owners!\
  1389. ]]\
  1390. \
  1391. --Variablen\
  1392. \
  1393. objects = {\
  1394. \009[\"door\"] = true,\
  1395. \009[\"ladder\"] = true,\
  1396. \009[\"wall\"] = true,\
  1397. \009[\"remove\"] = true\
  1398. }\
  1399. \
  1400. mapData = {\
  1401. \009blocksX = {\
  1402. \
  1403. \009},\
  1404. \009blocksY = {\
  1405. \
  1406. \009},\
  1407. \009laddersX = {\
  1408. \
  1409. \009},\
  1410. \009laddersY = {\
  1411. \
  1412. \009},\
  1413. \009ladderDestination = {\
  1414. \
  1415. \009},\
  1416. \009doorsX = {\
  1417. \
  1418. \009},\
  1419. \009doorsY = {\
  1420. \
  1421. \009},\
  1422. \009spawnX = 1,\
  1423. \009spawnY = 1,\
  1424. }\
  1425. \
  1426. selectedObj = \"\"\
  1427. \
  1428. --Funktionen\
  1429. \
  1430. function limitRead(nLimit, replaceChar)\
  1431. term.setCursorBlink(true)\
  1432. local cX, cY = term.getCursorPos()\
  1433. local rString = \"\"\
  1434. if replaceChar == \"\" then replaceChar = nil end\
  1435. repeat\
  1436. local event, p1 = os.pullEventRaw()\
  1437. if event == \"char\" then\
  1438. -- Character event\
  1439. if #rString + 1 <= nLimit then\
  1440. rString = rString .. p1\
  1441. write(replaceChar or p1)\
  1442. end\
  1443. elseif event == \"key\" and p1 == keys.backspace and #rString >= 1 then\
  1444. -- Backspace\
  1445. rString = string.sub(rString, 1, #rString-1)\
  1446. xPos, yPos = term.getCursorPos()\
  1447. term.setCursorPos(xPos-1, yPos)\
  1448. write(\" \")\
  1449. term.setCursorPos(xPos-1, yPos)\
  1450. end\
  1451. until event == \"key\" and p1 == keys.enter\
  1452. term.setCursorBlink(false)\
  1453. --print() -- Skip to the next line after clicking enter.\
  1454. return rString\
  1455. end\
  1456. \
  1457. function clear(bg, fg)\
  1458. \009term.setCursorPos(1,1)\
  1459. \009term.setBackgroundColor(bg)\
  1460. \009term.setTextColor(colors.white)\
  1461. \009term.clear()\
  1462. end\
  1463. \
  1464. function editor()\
  1465. \009clear(colors.black, colors.white)\
  1466. \009editing = true\
  1467. \009oldTerm = term.native()\
  1468. \009paintutils.drawImage(_layout, 1, 1)\
  1469. \009mapWindow = window.create(oldTerm, 1, 1, 25, 9)\
  1470. \009term.redirect(mapWindow)\
  1471. \009paintutils.drawImage(_map, 1, 1)\
  1472. \009maxX = 25\
  1473. \009maxY = 9\
  1474. \009term.redirect(oldTerm)\
  1475. \009searchBox = window.create(oldTerm, 2, 12, 23, 1)\
  1476. \009searchBox.setBackgroundColor(colors.gray)\
  1477. \009searchBox.setTextColor(colors.lime)\
  1478. \009searchBox.clear()\
  1479. \009searchBox.write(\"Enter function...\")\
  1480. \009while true do\
  1481. \009\009local event, button, x, y = os.pullEventRaw()\
  1482. \
  1483. \009\009if event == \"mouse_click\" and button == 1 and x >= 2 and x <= 24 and y == 12 then\
  1484. \009\009\009term.redirect(searchBox)\
  1485. \009\009\009term.setCursorPos(1,1)\
  1486. \009\009\009term.clear()\
  1487. \009\009\009local eingabe = limitRead(23)\
  1488. \009\009\009if #eingabe > 0 then\
  1489. \009\009\009\009for key, a in pairs(objects) do\
  1490. \009\009\009\009\009if eingabe == key then\
  1491. \009\009\009\009\009\009selectedObj = eingabe\
  1492. \009\009\009\009\009\009term.setCursorPos(1,1)\
  1493. \009\009\009\009\009\009term.clear()\
  1494. \009\009\009\009\009\009term.write(selectedObj)\
  1495. \009\009\009\009\009\009break\
  1496. \009\009\009\009\009else\
  1497. \009\009\009\009\009\009term.setCursorPos(1,1)\
  1498. \009\009\009\009\009\009term.clear()\
  1499. \009\009\009\009\009\009term.write(\"Object not found.\")\
  1500. \009\009\009\009\009end\
  1501. \009\009\009\009end\
  1502. \009\009\009end\
  1503. \009\009\009term.redirect(oldTerm)\
  1504. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 1 and x <= 25 and y >= 1 and y <= 9 then\
  1505. \009\009\009if selectedObj ~= \"\" then\
  1506. \009\009\009\009if selectedObj == \"wall\" then\
  1507. \009\009\009\009\009term.setCursorPos(x, y)\
  1508. \009\009\009\009\009term.setBackgroundColor(colors.brown)\
  1509. \009\009\009\009\009term.setTextColor(colors.white)\
  1510. \009\009\009\009\009term.write(\"W\")\
  1511. \009\009\009\009\009table.insert(mapData.blocksX, x)\
  1512. \009\009\009\009\009table.insert(mapData.blocksY, y)\
  1513. \009\009\009\009\009redrawBlocks()\
  1514. \009\009\009\009elseif selectedObj == \"remove\" then\
  1515. \009\009\009\009\009for _, a in ipairs(mapData.blocksX) do\
  1516. \009\009\009\009\009\009if a == x and y == mapData.blocksY[_] then\
  1517. \009\009\009\009\009\009\009table.remove(mapData.blocksX, _)\
  1518. \009\009\009\009\009\009\009table.remove(mapData.blocksY, _)\
  1519. \009\009\009\009\009\009\009paintutils.drawImage(_map, 1, 1)\
  1520. \009\009\009\009\009\009\009redrawBlocks()\
  1521. \009\009\009\009\009\009end\
  1522. \009\009\009\009\009end\
  1523. \009\009\009\009\009for _, a in ipairs(mapData.laddersX) do\
  1524. \009\009\009\009\009\009if a == x and y == mapData.laddersY[_] then\
  1525. \009\009\009\009\009\009\009table.remove(mapData.laddersX, _)\
  1526. \009\009\009\009\009\009\009table.remove(mapData.laddersY, _)\
  1527. \009\009\009\009\009\009\009paintutils.drawImage(_map, 1, 1)\
  1528. \009\009\009\009\009\009\009redrawBlocks()\
  1529. \009\009\009\009\009\009end\
  1530. \009\009\009\009\009end\
  1531. \009\009\009\009elseif selectedObj == \"ladder\" then\
  1532. \009\009\009\009\009term.setCursorPos(x, y)\
  1533. \009\009\009\009\009term.setBackgroundColor(colors.brown)\
  1534. \009\009\009\009\009term.setTextColor(colors.white)\
  1535. \009\009\009\009\009term.write(\"H\")\
  1536. \009\009\009\009\009term.redirect(searchBox)\
  1537. \009\009\009\009\009term.setCursorPos(1,1)\
  1538. \009\009\009\009\009term.clear()\
  1539. \009\009\009\009\009term.write(\"Please write destination\")\
  1540. \009\009\009\009\009sleep(2)\
  1541. \009\009\009\009\009term.setCursorPos(1,1)\
  1542. \009\009\009\009\009term.clear()\
  1543. \009\009\009\009\009repeat\
  1544. \009\009\009\009\009\009local eingabe = limitRead(23)\
  1545. \009\009\009\009\009\009term.setCursorPos(1,1)\
  1546. \009\009\009\009\009\009term.clear()\
  1547. \009\009\009\009\009until #eingabe > 0\
  1548. \009\009\009\009\009term.redirect(oldTerm)\
  1549. \009\009\009\009\009table.insert(mapData.laddersX, x)\
  1550. \009\009\009\009\009table.insert(mapData.laddersY, y)\
  1551. \009\009\009\009\009table.insert(mapData.ladderDestination, eingabe)\
  1552. \009\009\009\009\009redrawBlocks()\
  1553. \009\009\009\009end\
  1554. \009\009\009end\
  1555. \009\009elseif event == \"key\" and button == keys.delete then\
  1556. \009\009\009local file = fs.open(fldr..\"data.lvlDat\",\"w\")\
  1557. \009\009\009file.write(textutils.serialize(mapData))\
  1558. \009\009\009file.close()\
  1559. \
  1560. \009\009\009break\
  1561. \009\009end\
  1562. \009end\
  1563. end\
  1564. \
  1565. function redrawBlocks()\
  1566. \009for _, x in ipairs(mapData.blocksX) do\
  1567. \009\009term.setCursorPos(x, mapData.blocksY[_])\
  1568. \009\009term.setBackgroundColor(colors.brown)\
  1569. \009\009term.setTextColor(colors.white)\
  1570. \009\009term.write(\"W\")\
  1571. \009end\
  1572. \009for _, x in ipairs(mapData.laddersX) do\
  1573. \009\009term.setCursorPos(x, mapData.laddersY[_])\
  1574. \009\009term.setBackgroundColor(colors.black)\
  1575. \009\009term.setTextColor(colors.white)\
  1576. \009\009term.write(\"L\")\
  1577. \009end\
  1578. end\
  1579. \
  1580. \
  1581. --Code\
  1582. \
  1583. local args = {...}\
  1584. \
  1585. if #args ~= 2 then\
  1586. \009print(\"Usage: <thisfile> <pathToMapPicture> <editorLayoutDirectory>\")\
  1587. else\
  1588. \009if fs.exists(args[1]) then\
  1589. \009\009fldr = args[1]\
  1590. \009\009_map = paintutils.loadImage(args[1]..\"data.lvl\")\
  1591. \009\009_layout = paintutils.loadImage(args[2])\
  1592. \009\009editor()\
  1593. \009end\
  1594. \009--do stuff\
  1595. end",
  1596. "bbbbb 7 \
  1597. bbbbbbbbbbbbbbbbbbbbbbbbb7 \
  1598. 7 \
  1599. 7 \
  1600. 7 \
  1601. 7 \
  1602. 7 \
  1603. 7 \
  1604. 7 \
  1605. 777777777777777777777777777777777777777777777777777\
  1606. 7 \
  1607. 7 \
  1608. 7 \
  1609. 7 \
  1610. 7 \
  1611. 7 \
  1612. 7 \
  1613. 7 \
  1614. 7 ",
  1615. "--[[\
  1616. NPaintPro\
  1617. By NitrogenFingers\
  1618. ]]--\
  1619. \
  1620. --The screen size\
  1621. local w,h = term.getSize()\
  1622. --Whether or not the program is currently waiting on user input\
  1623. local inMenu = false\
  1624. --Whether or not a drop down menu is active\
  1625. local inDropDown = false\
  1626. --Whether or not animation tools are enabled (use -a to turn them on)\
  1627. local animated = false\
  1628. --Whether or not the text tools are enabled (use -t to turn them on)\
  1629. local textual = false\
  1630. --Whether or not \"blueprint\" display mode is on\
  1631. local blueprint = false\
  1632. --Whether or not the \"layer\" display is on\
  1633. local layerDisplay = false\
  1634. --Whether or not the interface is presently hidden\
  1635. local interfaceHidden = false\
  1636. --Whether or not the \"direction\" display is on\
  1637. local printDirection = false\
  1638. --The tool/mode npaintpro is currently in. Default is \"paint\"\
  1639. --For a list of modes, check out the help file\
  1640. local state = \"paint\"\
  1641. --Whether or not the program is presently running\
  1642. local isRunning = true\
  1643. --The rednet address of the 3D printer, if one has been attached\
  1644. local printer = nil\
  1645. \
  1646. --The list of every frame, containing every image in the picture/animation\
  1647. --Note: nfp files always have the picture at frame 1\
  1648. local frames = { }\
  1649. --How many frames are currently in the given animation.\
  1650. local frameCount = 1\
  1651. --The Colour Picker column\
  1652. local column = {}\
  1653. --The offset of visible colours in the picker column, if the screen cannot fit all 16\
  1654. local columnoffset = 0\
  1655. --The currently selected left and right colours\
  1656. local lSel,rSel = colours.white,nil\
  1657. --The amount of scrolling on the X and Y axis\
  1658. local sx,sy = 0,0\
  1659. --The alpha channel colour\
  1660. --Change this to change default canvas colour\
  1661. local alphaC = colours.black\
  1662. --The currently selected frame. Default is 1\
  1663. local sFrame = 1\
  1664. --The contents of the image buffer- contains contents, width and height\
  1665. local buffer = nil\
  1666. --The position, width and height of the selection rectangle\
  1667. local selectrect = nil\
  1668. \
  1669. --Whether or not text tools are enabled for this document\
  1670. local textEnabled = false\
  1671. --The X and Y positions of the text cursor\
  1672. local textCurX, textCurY = 1,1\
  1673. \
  1674. --The currently calculated required materials\
  1675. local requiredMaterials = {}\
  1676. --Whether or not required materials are being displayed in the pallette\
  1677. local requirementsDisplayed = false\
  1678. --A list of the rednet ID's all in-range printers located\
  1679. local printerList = { }\
  1680. --A list of the names of all in-range printers located. Same as the printerList in reference\
  1681. local printerNames = { }\
  1682. --The selected printer\
  1683. local selectedPrinter = 1\
  1684. --The X,Y,Z and facing of the printer\
  1685. local px,py,pz,pfx,pfz = 0,0,0,0,0\
  1686. --The form of layering used\
  1687. local layering = \"up\"\
  1688. \
  1689. --The animation state of the selection rectangle and image buffer\
  1690. local rectblink = 0\
  1691. --The ID for the timer\
  1692. local recttimer = nil\
  1693. --The radius of the brush tool\
  1694. local brushsize = 3\
  1695. --Whether or not \"record\" mode is activated (animation mode only)\
  1696. local record = false\
  1697. --The time between each frame when in play mode (animation mode only)\
  1698. local animtime = 0.3\
  1699. \
  1700. --The current \"cursor position\" in text mode\
  1701. local cursorTexX,cursorTexY = 1,1\
  1702. \
  1703. --A list of hexidecimal conversions from numbers to hex digits\
  1704. local hexnums = { [10] = \"a\", [11] = \"b\", [12] = \"c\", [13] = \"d\", [14] = \"e\" , [15] = \"f\" }\
  1705. --The NPaintPro logo (divine, isn't it?)\
  1706. local logo = {\
  1707. \"fcc 3 339\";\
  1708. \" fcc 9333 33\";\
  1709. \" fcc 933 333 33\";\
  1710. \" fcc 933 33 33\";\
  1711. \" fcc 933 33 33\";\
  1712. \" c88 333 93333\";\
  1713. \" 888 333 9333\";\
  1714. \" 333 3 333 939\";\
  1715. }\
  1716. --The Layer Up and Layer Forward printing icons\
  1717. local layerUpIcon = {\
  1718. \"0000000\";\
  1719. \"0088880\";\
  1720. \"0888870\";\
  1721. \"07777f0\";\
  1722. \"0ffff00\";\
  1723. \"0000000\";\
  1724. }\
  1725. local layerForwardIcon = {\
  1726. \"0000000\";\
  1727. \"000fff0\";\
  1728. \"00777f0\";\
  1729. \"0888700\";\
  1730. \"0888000\";\
  1731. \"0000000\";\
  1732. }\
  1733. --The available menu options in the ctrl menu\
  1734. local mChoices = {\"Save\",\"Exit\"}\
  1735. --The available modes from the dropdown menu- tables indicate submenus (include a name!)\
  1736. local ddModes = { { \"paint\", \"brush\", \"pippette\", \"flood\", \"move\", \"clear\", \"select\", name = \"painting\" }, { \"alpha to left\", \"alpha to right\", \"hide interface\", name = \"display\" }, \"help\", { \"print\", \"save\", \"exit\", name = \"file\" }, name = \"menu\" }\
  1737. --The available modes from the selection right-click menu\
  1738. local srModes = { \"cut\", \"copy\", \"paste\", \"clear\", \"hide\", name = \"selection\" }\
  1739. --The list of available help topics for each mode 127\
  1740. local helpTopics = {\
  1741. [1] = {\
  1742. name = \"Paint Mode\",\
  1743. key = nil,\
  1744. animonly = false,\
  1745. textonly = false,\
  1746. message = \"The default mode for NPaintPro, for painting pixels.\"\
  1747. ..\" Controls here that are not overridden will apply for all other modes. Leaving a mode by selecting that mode \"\
  1748. ..\" again will always send the user back to paint mode.\",\
  1749. controls = {\
  1750. { \"Arrow keys\", \"Scroll the canvas\" },\
  1751. { \"Left Click\", \"Paint/select left colour\" },\
  1752. { \"Right Click\", \"Paint/select right colour\" },\
  1753. { \"Z Key\", \"Clear image on screen\" },\
  1754. { \"Tab Key\", \"Hide selection rectangle if visible\" },\
  1755. { \"Q Key\", \"Set alpha mask to left colour\" },\
  1756. { \"W Key\", \"Set alpha mask to right colour\" },\
  1757. { \"Number Keys\", \"Swich between frames 1-9\" },\
  1758. { \"</> keys\", \"Move to the next/last frame\" },\
  1759. { \"R Key\", \"Removes every frame after the current frame\"}\
  1760. }\
  1761. },\
  1762. [2] = {\
  1763. name = \"Brush Mode\",\
  1764. key = \"b\",\
  1765. animonly = false,\
  1766. textonly = false,\
  1767. message = \"Brush mode allows painting a circular area of variable diameter rather than a single pixel, working in \"..\
  1768. \"the exact same way as paint mode in all other regards.\",\
  1769. controls = {\
  1770. { \"Left Click\", \"Paints a brush blob with the left colour\" },\
  1771. { \"Right Click\", \"Paints a brush blob with the right colour\" },\
  1772. { \"Number Keys\", \"Changes the radius of the brush blob from 2-9\" }\
  1773. }\
  1774. },\
  1775. [3] = {\
  1776. name = \"Pippette Mode\",\
  1777. key = \"p\",\
  1778. animonly = false,\
  1779. textonly = false,\
  1780. message = \"Pippette mode allows the user to click the canvas and set the colour clicked to the left or right \"..\
  1781. \"selected colour, for later painting.\",\
  1782. controls = {\
  1783. { \"Left Click\", \"Sets clicked colour to the left selected colour\" },\
  1784. { \"Right Click\", \"Sets clicked colour to the right selected colour\" }\
  1785. }\
  1786. },\
  1787. [4] = {\
  1788. name = \"Move Mode\",\
  1789. key = \"m\",\
  1790. animonly = false,\
  1791. textonly = false,\
  1792. message = \"Mode mode allows the moving of the entire image on the screen. This is especially useful for justifying\"..\
  1793. \" the image to the top-left for animations or game assets.\",\
  1794. controls = {\
  1795. { \"Left/Right Click\", \"Moves top-left corner of image to selected square\" },\
  1796. { \"Arrow keys\", \"Moves image one pixel in any direction\" }\
  1797. }\
  1798. },\
  1799. [5] = {\
  1800. name = \"Flood Mode\",\
  1801. key = \"f\",\
  1802. animonly = false,\
  1803. textonly = false,\
  1804. message = \"Flood mode allows the changing of an area of a given colour to that of the selected colour. \"..\
  1805. \"The tool uses a flood4 algorithm and will not fill diagonally. Transparency cannot be flood filled.\",\
  1806. controls = {\
  1807. { \"Left Click\", \"Flood fills selected area to left colour\" },\
  1808. { \"Right Click\", \"Flood fills selected area to right colour\" }\
  1809. }\
  1810. },\
  1811. [6] = {\
  1812. name = \"Select Mode\",\
  1813. key = \"s\",\
  1814. animonly = false,\
  1815. textonly = false,\
  1816. message = \"Select mode allows the creation and use of the selection rectangle, to highlight specific areas on \"..\
  1817. \"the screen and perform operations on the selected area of the image. The selection rectangle can contain an \"..\
  1818. \"image on the clipboard- if it does, the image will flash inside the rectangle, and the rectangle edges will \"..\
  1819. \"be light grey instead of dark grey.\",\
  1820. controls = {\
  1821. { \"C Key\", \"Copy: Moves selection into the clipboard\" },\
  1822. { \"X Key\", \"Cut: Clears canvas under the rectangle, and moves it into the clipboard\" },\
  1823. { \"V Key\", \"Paste: Copys clipboard to the canvas\" },\
  1824. { \"Z Key\", \"Clears clipboard\" },\
  1825. { \"Left Click\", \"Moves top-left corner of rectangle to selected pixel\" },\
  1826. { \"Right Click\", \"Opens selection menu\" },\
  1827. { \"Arrow Keys\", \"Moves rectangle one pixel in any direction\" }\
  1828. }\
  1829. },\
  1830. [7] = {\
  1831. name = \"Corner Select Mode\",\
  1832. key = nil,\
  1833. animonly = false,\
  1834. textonly = false,\
  1835. message = \"If a selection rectangle isn't visible, this mode is selected automatically. It allows the \"..\
  1836. \"defining of the corners of the rectangle- one the top-left and bottom-right corners have been defined, \"..\
  1837. \"NPaintPro switches to selection mode. Note rectangle must be at least 2 pixels wide and high.\",\
  1838. controls = {\
  1839. { \"Left/Right Click\", \"Defines a corner of the selection rectangle\" }\
  1840. }\
  1841. },\
  1842. [8] = {\
  1843. name = \"Play Mode\",\
  1844. key = \"space\",\
  1845. animonly = true,\
  1846. textonly = false,\
  1847. message = \"Play mode will loop through each frame in your animation at a constant rate. Editing tools are \"..\
  1848. \"locked in this mode, and the coordinate display will turn green to indicate it is on.\",\
  1849. controls = {\
  1850. { \"</> Keys\", \"Increases/Decreases speed of the animation\" },\
  1851. { \"Space Bar\", \"Returns to paint mode\" }\
  1852. }\
  1853. },\
  1854. [9] = {\
  1855. name = \"Record Mode\",\
  1856. key = \"\\\\\",\
  1857. animonly = true,\
  1858. textonly = false,\
  1859. message = \"Record mode is not a true mode, but influences how other modes work. Changes made that modify the \"..\
  1860. \"canvas in record mode will affect ALL frames in the animation. The coordinates will turn red to indicate that \"..\
  1861. \"record mode is on.\",\
  1862. controls = {\
  1863. { \"\", \"Affects:\" },\
  1864. { \"- Paint Mode\", \"\" },\
  1865. { \"- Brush Mode\", \"\" },\
  1866. { \"- Cut and Paste in Select Mode\", \"\"},\
  1867. { \"- Move Mode\", \"\"}\
  1868. }\
  1869. },\
  1870. \009\009[10] = {\
  1871. \009\009\009\009name = \"Hide Interface\",\
  1872. \009\009\009\009key = \"~\",\
  1873. \009\009\009\009animonly = false,\
  1874. \009\009\009\009textonly = false,\
  1875. \009\009\009\009message = \"Hides the sidebar and colour picker so only the image is visible.\"..\
  1876. \009\009\009\009\" The program can be started with the interface hidden using the -d command line option.\"..\
  1877. \009\009\009\009\" When hidden, if a file is animated it will automatically go to play mode.\\n\"..\
  1878. \009\009\009\009\"Note that all other input is locked until the display is revealed again in this\"..\
  1879. \009\009\009\009\" mode.\",\
  1880. \009\009\009\009controls = {\
  1881. { \"</> Keys\", \"Increases/Decreases speed of the animation\" },\
  1882. \009\009\009\009\009{ \"~ Key\", \"Shows interface\"}\
  1883. \009\009\009\009}\
  1884. \009\009},\
  1885. [11] = {\
  1886. name = \"Help Mode\",\
  1887. key = \"h\",\
  1888. animonly = false,\
  1889. textonly = false,\
  1890. message = \"Displays this help screen. Clicking on options will display help on that topic. Clicking out of the screen\"..\
  1891. \" will leave this mode.\",\
  1892. controls = {\
  1893. { \"Left/Right Click\", \"Displays a topic/Leaves the mode\" }\
  1894. }\
  1895. },\
  1896. [12] = {\
  1897. name = \"File Mode\",\
  1898. key = nil,\
  1899. animonly = false,\
  1900. textonly = false,\
  1901. message = \"Clicking on the mode display at the bottom of the screen will open the options menu. Here you can\"..\
  1902. \" activate all of the modes in the program with a simple mouse click. Pressing left control will open up the\"..\
  1903. \" file menu automatically.\",\
  1904. controls = {\
  1905. { \"leftCtrl\", \"Opens the file menu\" },\
  1906. { \"leftAlt\", \"Opens the paint menu\" }\
  1907. }\
  1908. },\
  1909. [13] = {\
  1910. name = \"Text Mode\",\
  1911. key = \"t\",\
  1912. animonly = false,\
  1913. textonly = true,\
  1914. message = \"In this mode, the user is able to type letters onto the document for display. The left colour \"..\
  1915. \"pallette value determines what colour the text will be, and the right determines what colour the background \"..\
  1916. \"will be (set either to nil to keep the same colours as already there).\",\
  1917. controls = {\
  1918. { \"Backspace\", \"Deletes the character on the previous line\" },\
  1919. { \"Arrow Keys\", \"Moves the cursor in any direction\" },\
  1920. { \"Left Click\", \"Moves the cursor to beneath the mouse cursor\" }\
  1921. }\
  1922. },\
  1923. [14] = {\
  1924. name = \"Textpaint Mode\",\
  1925. key = \"y\",\
  1926. animonly = false,\
  1927. textonly = true,\
  1928. message = \"Allows the user to paint any text on screen to the desired colour with the mouse. If affects the text colour\"..\
  1929. \" values rather than the background values, but operates identically to paint mode in all other regards.\",\
  1930. controls = {\
  1931. { \"Left Click\", \"Paints the text with the left colour\" },\
  1932. { \"Right Click\", \"Paints the text with the right colour\" }\
  1933. }\
  1934. },\
  1935. [15] = {\
  1936. name = \"About NPaintPro\",\
  1937. keys = nil,\
  1938. animonly = false,\
  1939. textonly = false,\
  1940. message = \"NPaintPro: The feature-bloated paint program for ComputerCraft by Nitrogen Fingers.\",\
  1941. controls = {\
  1942. { \"Testers:\", \" \"},\
  1943. { \" \", \"Faubiguy\"},\
  1944. { \" \", \"TheOriginalBIT\"}\
  1945. }\
  1946. }\
  1947. }\
  1948. --The \"bounds\" of the image- the first/last point on both axes where a pixel appears\
  1949. local toplim,botlim,leflim,riglim = nil,nil,nil,nil\
  1950. --The selected path\
  1951. local sPath = nil\
  1952. \
  1953. \
  1954. --Screen Size Parameters- decided dynamically further down the program\
  1955. --Whether or not the help screen is available\
  1956. local helpAvailable = true\
  1957. --Whether or not the main menu is available\
  1958. local mainAvailable = true\
  1959. --Whether or not selection box dropdowns are available\
  1960. local boxdropAvailable = true\
  1961. --Whether or not a manual file descriptor option is available (part of the title)\
  1962. local filemakerAvailable = true\
  1963. \
  1964. --[[ \
  1965. Section: Helpers \
  1966. ]]--\
  1967. \
  1968. --[[Converts a colour parameter into a single-digit hex coordinate for the colour\
  1969. Params: colour:int = The colour to be converted\
  1970. Returns:string A string conversion of the colour\
  1971. ]]--\
  1972. local function getHexOf(colour)\
  1973. if not colour or not tonumber(colour) then\
  1974. return \" \"\
  1975. end\
  1976. local value = math.log(colour)/math.log(2)\
  1977. if value > 9 then\
  1978. value = hexnums[value]\
  1979. end\
  1980. return value\
  1981. end\
  1982. \
  1983. --[[Converts a hex digit into a colour value\
  1984. Params: hex:?string = the hex digit to be converted\
  1985. Returns:string A colour value corresponding to the hex, or nil if the character is invalid\
  1986. ]]--\
  1987. local function getColourOf(hex)\
  1988. local value = tonumber(hex, 16)\
  1989. if not value then return nil end\
  1990. value = math.pow(2,value)\
  1991. return value\
  1992. end\
  1993. \
  1994. --[[Finds the largest width and height of the text in a given menu. Should conform to the format\
  1995. \009of all standard menus (number indexed values and a 'name' field).\
  1996. \009This is done recursively. It's just easier that way.\
  1997. \009Params: menu:table = the table being tested for the max width and height\
  1998. \009Returns:number,number = the max width and height of the text or names of any menu or submenu.\
  1999. ]]--\
  2000. local function findMaxWH(menu)\
  2001. \009local wmax,hmax = #menu.name, #menu\
  2002. \009for _,entry in pairs(menu) do\
  2003. \009\009if type(entry) == \"table\" then\
  2004. \009\009\009local nw,nh = findMaxWH(entry)\
  2005. \009\009\009wmax = math.max(wmax,nw)\
  2006. \009\009\009hmax = math.max(hmax,nh)\
  2007. \009\009else\
  2008. \009\009\009wmax = math.max(wmax,#entry)\
  2009. \009\009end\
  2010. \009end\
  2011. \009return wmax,hmax\
  2012. end\
  2013. \
  2014. --[[Determines what services are available depending on the size of the screen. Certain features\
  2015. \009may be disabled with screen real estate does not allow for it.\
  2016. \009Params: none\
  2017. \009Returns:nil\
  2018. ]]--\
  2019. local function determineAvailableServices()\
  2020. \009--Help files were designed to fit a 'standard' CC screen, of 51 x 19. The height of the screen\
  2021. \009--needs to match the number of available options plus white space, but for consistency with\
  2022. \009--the files themselves, a natural size of 51 is required for the screen width as well.\
  2023. \009if w < 51 or h < #helpTopics+3 then helpAvailable = false end\
  2024. \009if not helpAvailable then table.remove(ddModes,3) end\
  2025. \009--These hard-coded values mirror the drawLogo values, with extra consideration for the \
  2026. \009--additional menu options\
  2027. \009if h < 14 or w < 24 then filemakerAvailable = false end\
  2028. \009\
  2029. \009--Menus can't cover the picker and need 2 spaces for branches. 4 whitespace on X total.\
  2030. \009--Menus need a title and can't eclipse the footer. 2 whitespace on Y total.\
  2031. \009local wmin,hmin = findMaxWH(ddModes)\
  2032. \009if w < wmin+4 or h < hmin+2 then mainAvailable = false end\
  2033. \009wmin,hmin = findMaxWH(srModes)\
  2034. \009if w < wmin+4 or h < hmin+2 then boxdropAvailable = false end\
  2035. end\
  2036. \
  2037. --[[Finds the biggest and smallest bounds of the image- the outside points beyond which pixels do not appear\
  2038. These values are assigned to the \"lim\" parameters for access by other methods\
  2039. Params: forAllFrames:bool = True if all frames should be used to find bounds, otherwise false or nil\
  2040. Returns:nil\
  2041. ]]--\
  2042. local function updateImageLims(forAllFrames)\
  2043. local f,l = sFrame,sFrame\
  2044. if forAllFrames == true then f,l = 1,framecount end\
  2045. \
  2046. toplim,botlim,leflim,riglim = nil,nil,nil,nil\
  2047. for locf = f,l do\
  2048. for y,_ in pairs(frames[locf]) do\
  2049. if type(y) == \"number\" then\
  2050. for x,_ in pairs(frames[locf][y]) do\
  2051. if frames[locf][y][x] ~= nil then\
  2052. if leflim == nil or x < leflim then leflim = x end\
  2053. if toplim == nil or y < toplim then toplim = y end\
  2054. if riglim == nil or x > riglim then riglim = x end\
  2055. if botlim == nil or y > botlim then botlim = y end\
  2056. end\
  2057. end\
  2058. end\
  2059. end\
  2060. end\
  2061. \
  2062. --There is just... no easier way to do this. It's horrible, but necessary\
  2063. if textEnabled then\
  2064. for locf = f,l do\
  2065. for y,_ in pairs(frames[locf].text) do\
  2066. for x,_ in pairs(frames[locf].text[y]) do\
  2067. if frames[locf].text[y][x] ~= nil then\
  2068. if leflim == nil or x < leflim then leflim = x end\
  2069. if toplim == nil or y < toplim then toplim = y end\
  2070. if riglim == nil or x > riglim then riglim = x end\
  2071. if botlim == nil or y > botlim then botlim = y end\
  2072. end\
  2073. end\
  2074. end\
  2075. for y,_ in pairs(frames[locf].textcol) do\
  2076. for x,_ in pairs(frames[locf].textcol[y]) do\
  2077. if frames[locf].textcol[y][x] ~= nil then\
  2078. if leflim == nil or x < leflim then leflim = x end\
  2079. if toplim == nil or y < toplim then toplim = y end\
  2080. if riglim == nil or x > riglim then riglim = x end\
  2081. if botlim == nil or y > botlim then botlim = y end\
  2082. end\
  2083. end\
  2084. end\
  2085. end\
  2086. end\
  2087. end\
  2088. \
  2089. --[[Determines how much of each material is required for a print. Done each time printing is called.\
  2090. Params: none\
  2091. Returns:table A complete list of how much of each material is required.\
  2092. ]]--\
  2093. function calculateMaterials()\
  2094. updateImageLims(animated)\
  2095. requiredMaterials = {}\
  2096. for i=1,16 do\
  2097. requiredMaterials[i] = 0\
  2098. end\
  2099. \
  2100. if not toplim then return end\
  2101. \
  2102. for i=1,#frames do\
  2103. for y = toplim, botlim do\
  2104. for x = leflim, riglim do\
  2105. if type(frames[i][y][x]) == \"number\" then\
  2106. requiredMaterials[math.log10(frames[i][y][x])/math.log10(2) + 1] =\
  2107. requiredMaterials[math.log10(frames[i][y][x])/math.log10(2) + 1] + 1\
  2108. end \
  2109. end\
  2110. end\
  2111. end\
  2112. end\
  2113. \
  2114. \
  2115. --[[Updates the rectangle blink timer. Should be called anywhere events are captured, along with a timer capture.\
  2116. Params: nil\
  2117. Returns:nil\
  2118. ]]--\
  2119. local function updateTimer(id)\
  2120. if id == recttimer then\
  2121. recttimer = os.startTimer(0.5)\
  2122. rectblink = (rectblink % 2) + 1\
  2123. end\
  2124. end\
  2125. \
  2126. --[[Constructs a message based on the state currently selected\
  2127. Params: nil\
  2128. Returns:string A message regarding the state of the application\
  2129. ]]--\
  2130. local function getStateMessage()\
  2131. local msg = \" \"..string.upper(string.sub(state, 1, 1))..string.sub(state, 2, #state)..\" mode\"\
  2132. if state == \"brush\" then msg = msg..\", size=\"..brushsize end\
  2133. return msg\
  2134. end\
  2135. \
  2136. --[[Calls the rednet_message event, but also looks for timer events to keep then\
  2137. system timer ticking.\
  2138. Params: timeout:number how long before the event times out\
  2139. Returns:number the id of the sender\
  2140. :number the message send\
  2141. ]]--\
  2142. local function rsTimeReceive(timeout)\
  2143. local timerID\
  2144. if timeout then timerID = os.startTimer(timeout) end\
  2145. \
  2146. local id,key,msg = nil,nil\
  2147. while true do\
  2148. id,key,msg = os.pullEvent()\
  2149. \
  2150. if id == \"timer\" then\
  2151. if key == timerID then return\
  2152. else updateTimer(key) end\
  2153. end\
  2154. if id == \"rednet_message\" then\
  2155. return key,msg\
  2156. end\
  2157. end\
  2158. end\
  2159. \
  2160. --[[Draws a picture, in paint table format on the screen\
  2161. Params: image:table = the image to display\
  2162. xinit:number = the x position of the top-left corner of the image\
  2163. yinit:number = the y position of the top-left corner of the image\
  2164. alpha:number = the color to display for the alpha channel. Default is white.\
  2165. Returns:nil\
  2166. ]]--\
  2167. local function drawPictureTable(image, xinit, yinit, alpha)\
  2168. if not alpha then alpha = 1 end\
  2169. for y=1,#image do\
  2170. for x=1,#image[y] do\
  2171. term.setCursorPos(xinit + x-1, yinit + y-1)\
  2172. local col = getColourOf(string.sub(image[y], x, x))\
  2173. if not col then col = alpha end\
  2174. term.setBackgroundColour(col)\
  2175. term.write(\" \")\
  2176. end\
  2177. end\
  2178. end\
  2179. \
  2180. --[[ \
  2181. Section: Loading \
  2182. ]]--\
  2183. \
  2184. --[[Loads a non-animted paint file into the program\
  2185. Params: path:string = The path in which the file is located\
  2186. Returns:nil\
  2187. ]]--\
  2188. local function loadNFP(path)\
  2189. sFrame = 1\
  2190. frames[sFrame] = { }\
  2191. if fs.exists(path) then\
  2192. local file = io.open(path, \"r\" )\
  2193. local sLine = file:read()\
  2194. local num = 1\
  2195. while sLine do\
  2196. table.insert(frames[sFrame], num, {})\
  2197. for i=1,#sLine do\
  2198. frames[sFrame][num][i] = getColourOf(string.sub(sLine,i,i))\
  2199. end\
  2200. num = num+1\
  2201. sLine = file:read()\
  2202. end\
  2203. file:close()\
  2204. end\
  2205. end\
  2206. \
  2207. --[[Loads a text-paint file into the program\
  2208. Params: path:string = The path in which the file is located\
  2209. Returns:nil\
  2210. ]]--\
  2211. local function loadNFT(path)\
  2212. sFrame = 1\
  2213. frames[sFrame] = { }\
  2214. frames[sFrame].text = { }\
  2215. frames[sFrame].textcol = { }\
  2216. \
  2217. if fs.exists(path) then\
  2218. local file = io.open(path, \"r\")\
  2219. local sLine = file:read()\
  2220. local num = 1\
  2221. while sLine do\
  2222. table.insert(frames[sFrame], num, {})\
  2223. table.insert(frames[sFrame].text, num, {})\
  2224. table.insert(frames[sFrame].textcol, num, {})\
  2225. \
  2226. --As we're no longer 1-1, we keep track of what index to write to\
  2227. local writeIndex = 1\
  2228. --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour\
  2229. local bgNext, fgNext = false, false\
  2230. --The current background and foreground colours\
  2231. local currBG, currFG = nil,nil\
  2232. term.setCursorPos(1,1)\
  2233. for i=1,#sLine do\
  2234. local nextChar = string.sub(sLine, i, i)\
  2235. if nextChar:byte() == 30 then\
  2236. bgNext = true\
  2237. elseif nextChar:byte() == 31 then\
  2238. fgNext = true\
  2239. elseif bgNext then\
  2240. currBG = getColourOf(nextChar)\
  2241. bgNext = false\
  2242. elseif fgNext then\
  2243. currFG = getColourOf(nextChar)\
  2244. fgNext = false\
  2245. else\
  2246. if nextChar ~= \" \" and currFG == nil then\
  2247. currFG = colours.white\
  2248. end\
  2249. frames[sFrame][num][writeIndex] = currBG\
  2250. frames[sFrame].textcol[num][writeIndex] = currFG\
  2251. frames[sFrame].text[num][writeIndex] = nextChar\
  2252. writeIndex = writeIndex + 1\
  2253. end\
  2254. end\
  2255. num = num+1\
  2256. sLine = file:read()\
  2257. end\
  2258. file:close()\
  2259. end\
  2260. end\
  2261. \
  2262. --[[Loads an animated paint file into the program\
  2263. Params: path:string = The path in which the file is located\
  2264. Returns:nil\
  2265. ]]--\
  2266. local function loadNFA(path)\
  2267. frames[sFrame] = { }\
  2268. if fs.exists(path) then\
  2269. local file = io.open(path, \"r\" )\
  2270. local sLine = file:read()\
  2271. local num = 1\
  2272. while sLine do\
  2273. table.insert(frames[sFrame], num, {})\
  2274. if sLine == \"~\" then\
  2275. sFrame = sFrame + 1\
  2276. frames[sFrame] = { }\
  2277. num = 1\
  2278. else\
  2279. for i=1,#sLine do\
  2280. frames[sFrame][num][i] = getColourOf(string.sub(sLine,i,i))\
  2281. end\
  2282. num = num+1\
  2283. end\
  2284. sLine = file:read()\
  2285. end\
  2286. file:close()\
  2287. end\
  2288. framecount = sFrame\
  2289. sFrame = 1\
  2290. end\
  2291. \
  2292. --[[Saves a non-animated paint file to the specified path\
  2293. Params: path:string = The path to save the file to\
  2294. Returns:nil\
  2295. ]]--\
  2296. local function saveNFP(path)\
  2297. local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))\
  2298. if not fs.exists(sDir) then\
  2299. fs.makeDir(sDir)\
  2300. end\
  2301. \
  2302. local file = io.open(path, \"w\")\
  2303. updateImageLims(false)\
  2304. if not toplim then\
  2305. file:close()\
  2306. return\
  2307. end\
  2308. for y=1,botlim do\
  2309. local line = \"\"\
  2310. if frames[sFrame][y] then\
  2311. for x=1,riglim do\
  2312. line = line..getHexOf(frames[sFrame][y][x])\
  2313. end\
  2314. end\
  2315. file:write(line..\"\\n\")\
  2316. end\
  2317. file:close()\
  2318. end\
  2319. \
  2320. --[[Saves a text-paint file to the specified path\
  2321. Params: path:string = The path to save the file to\
  2322. Returns:nil\
  2323. ]]--\
  2324. local function saveNFT(path)\
  2325. local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))\
  2326. if not fs.exists(sDir) then\
  2327. fs.makeDir(sDir)\
  2328. end\
  2329. \
  2330. local file = io.open(path, \"w\")\
  2331. updateImageLims(false)\
  2332. if not toplim then\
  2333. file:close()\
  2334. return\
  2335. end\
  2336. for y=1,botlim do\
  2337. local line = \"\"\
  2338. local currBG, currFG = nil,nil\
  2339. for x=1,riglim do\
  2340. if frames[sFrame][y] and frames[sFrame][y][x] ~= currBG then\
  2341. line = line..string.char(30)..getHexOf(frames[sFrame][y][x])\
  2342. currBG = frames[sFrame][y][x]\
  2343. end\
  2344. if frames[sFrame].textcol[y] and frames[sFrame].textcol[y][x] ~= currFG then\
  2345. line = line..string.char(31)..getHexOf(frames[sFrame].textcol[y][x])\
  2346. currFG = frames[sFrame].textcol[y][x]\
  2347. end\
  2348. if frames[sFrame].text[y] then\
  2349. local char = frames[sFrame].text[y][x]\
  2350. if not char then char = \" \" end\
  2351. line = line..char\
  2352. end\
  2353. end\
  2354. file:write(line..\"\\n\")\
  2355. end\
  2356. file:close()\
  2357. end\
  2358. \
  2359. --[[Saves a animated paint file to the specified path\
  2360. Params: path:string = The path to save the file to\
  2361. Returns:nil\
  2362. ]]--\
  2363. local function saveNFA(path)\
  2364. local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))\
  2365. if not fs.exists(sDir) then\
  2366. fs.makeDir(sDir)\
  2367. end\
  2368. \
  2369. local file = io.open(path, \"w\")\
  2370. updateImageLims(true)\
  2371. if not toplim then\
  2372. file:close()\
  2373. return\
  2374. end\
  2375. for i=1,#frames do\
  2376. for y=1,botlim do\
  2377. local line = \"\"\
  2378. if frames[i][y] then\
  2379. for x=1,riglim do\
  2380. line = line..getHexOf(frames[i][y][x])\
  2381. end\
  2382. end\
  2383. file:write(line..\"\\n\")\
  2384. end\
  2385. if i < #frames then file:write(\"~\\n\") end\
  2386. end\
  2387. file:close()\
  2388. end\
  2389. \
  2390. --[[Runs a special pre-program dialogue to determine the filename and filepath. Done if\
  2391. \009there's room, and a file name hasn't been specified\
  2392. \009Params: none\
  2393. \009Returns:bool= true if file is created; false otherwise\
  2394. ]]--\
  2395. local function runFileMaker()\
  2396. \009local newFName = \"\"\
  2397. \009local fileType = 1\
  2398. \009if animated then fileType = 2\
  2399. \009elseif textEnabled then fileType = 3 end\
  2400. \009\
  2401. \009local tlx,tly = math.floor(w/2 - #logo[1]/2), math.floor(h/2 + #logo/2 + 1)\
  2402. \
  2403. \009--This is done on top of the logo, so it backpedals a bit.\
  2404. \009term.setCursorPos(tlx, tly)\
  2405. \009term.clearLine()\
  2406. \009term.write(\"Name: \")\
  2407. \009term.setCursorPos(tlx, tly + 1)\
  2408. \009term.clearLine()\
  2409. \009term.write(\"Filetype: Sprite\")\
  2410. \009term.setCursorPos(tlx + 12, tly + 2)\
  2411. \009term.write(\"Animation\")\
  2412. \009term.setCursorPos(tlx + 12, tly + 3)\
  2413. \009term.write(\"Text\")\
  2414. \009\
  2415. \009while true do\
  2416. \009\009term.setCursorPos(tlx + 6, tly)\
  2417. \009\009term.setBackgroundColour(colours.lightGrey)\
  2418. \009\009term.setTextColour(colours.grey)\
  2419. \009\009term.write(newFName..string.rep(\" \", 15-#newFName))\
  2420. \009\009term.setBackgroundColour(colours.white)\
  2421. \009\009term.setTextColour(colours.black)\
  2422. \009\009local extension = \".nfp\"\
  2423. \009\009if fileType == 2 then extension = \".nfa\"\
  2424. \009\009elseif fileType == 3 then extension = \".nft\" end\
  2425. \009\009term.write(extension)\
  2426. \009\009\
  2427. \009\009term.setBackgroundColour(colours.lightGrey)\
  2428. \009\009term.setTextColour(colours.grey)\
  2429. \009\009for i=1,3 do\
  2430. \009\009\009term.setCursorPos(tlx + 24, tly + i)\
  2431. \009\009\009if i==fileType then term.write(\"X\")\
  2432. \009\009\009else term.write(\" \") end\
  2433. \009\009end\
  2434. \009\009\
  2435. \009\009local fPath = shell.resolve(newFName..extension)\
  2436. \009\009term.setCursorPos(tlx, tly + 3)\
  2437. \009\009local fileValid = true\
  2438. \009\009if (fs.exists(fPath) and fs.isDir(fPath)) or newFName == \"\" then\
  2439. \009\009\009term.setBackgroundColour(colours.white)\
  2440. \009\009\009term.setTextColour(colours.red)\
  2441. \009\009\009term.write(\"Invalid \")\
  2442. \009\009\009fileValid = false\
  2443. \009\009elseif fs.exists(fPath) then\
  2444. \009\009\009term.setBackgroundColour(colours.grey)\
  2445. \009\009\009term.setTextColour(colours.lightGrey)\
  2446. \009\009\009term.write(\" Edit \")\
  2447. \009\009else\
  2448. \009\009\009term.setBackgroundColour(colours.grey)\
  2449. \009\009\009term.setTextColour(colours.lightGrey)\
  2450. \009\009\009term.write(\" Create \")\
  2451. \009\009end\
  2452. \009\009\
  2453. \009\009term.setTextColour(colours.grey)\
  2454. \009\009term.setCursorPos(tlx + 6 + #newFName, tly)\
  2455. \009\009term.setCursorBlink(true)\
  2456. \009\009\
  2457. \009\009local id,p1,p2,p3 = os.pullEvent()\
  2458. \009\009if id == \"key\" then\
  2459. \009\009\009if p1 == keys.backspace and #newFName > 0 then \
  2460. \009\009\009\009newFName = string.sub(newFName, 1, #newFName-1)\
  2461. \009\009\009elseif p1 == keys.enter and fileValid then\
  2462. \009\009\009\009sPath = fPath\
  2463. \009\009\009\009return true\
  2464. \009\009\009end\
  2465. \009\009elseif id == \"char\" and p1 ~= \".\" and p1 ~= \" \" and #newFName < 15 then\
  2466. \009\009\009newFName = newFName..p1\
  2467. \009\009elseif id == \"mouse_click\" then\
  2468. \009\009\009--The option boxes. Man, hardcoding is ugly...\
  2469. \009\009\009if p2 == tlx + 24 then\
  2470. \009\009\009\009for i=1,3 do \
  2471. \009\009\009\009\009if p3 == tly+i then fileType = i end \
  2472. \009\009\009\009end\
  2473. \009\009\009end\
  2474. \009\009\009if p3 == tly + 3 and p2 >= tlx and p2 <= tlx + 8 and fileValid then\
  2475. \009\009\009\009sPath = fPath\
  2476. \009\009\009\009return true\
  2477. \009\009\009end\
  2478. \009\009end\
  2479. \009end\
  2480. end\
  2481. \
  2482. --[[Initializes the program, by loading in the paint file. Called at the start of each program.\
  2483. Params: none\
  2484. Returns:nil\
  2485. ]]--\
  2486. local function init()\
  2487. if textEnabled then\
  2488. loadNFT(sPath)\
  2489. table.insert(ddModes, 2, { \"text\", \"textpaint\", name = \"text\"})\
  2490. elseif animated then\
  2491. loadNFA(sPath)\
  2492. table.insert(ddModes, #ddModes, { \"record\", \"play\", name = \"anim\" })\
  2493. table.insert(ddModes, #ddModes, { \"go to\", \"remove\", name = \"frames\"})\
  2494. table.insert(ddModes[2], #ddModes[2], \"blueprint on\")\
  2495. table.insert(ddModes[2], #ddModes[2], \"layers on\")\
  2496. else\
  2497. loadNFP(sPath)\
  2498. table.insert(ddModes[2], #ddModes[2], \"blueprint on\")\
  2499. end\
  2500. \009\009\
  2501. for i=0,15 do\
  2502. table.insert(column, math.pow(2,i))\
  2503. end\
  2504. end\
  2505. \
  2506. --[[ \
  2507. Section: Drawing \
  2508. ]]--\
  2509. \
  2510. \
  2511. --[[Draws the rather superflous logo. Takes about 1 second, before user is able to move to the\
  2512. actual program.\
  2513. Params: none\
  2514. Returns:bool= true if the file select ran successfully; false otherwise.\
  2515. ]]--\
  2516. local function drawLogo()\
  2517. term.setBackgroundColour(colours.white)\
  2518. term.clear()\
  2519. \009\009if h >= 12 and w >= 24 then\
  2520. \009\009\009drawPictureTable(logo, w/2 - #logo[1]/2, h/2 - #logo/2, colours.white)\
  2521. \009\009\009term.setBackgroundColour(colours.white)\
  2522. \009\009\009term.setTextColour(colours.black)\
  2523. \009\009\009local msg = \"NPaintPro\"\
  2524. \009\009\009term.setCursorPos(w/2 - #msg/2, h/2 + #logo/2 + 1)\
  2525. \009\009\009term.write(msg)\
  2526. \009\009\009msg = \"By NitrogenFingers\"\
  2527. \009\009\009term.setCursorPos(w/2 - #msg/2, h/2 + #logo/2 + 2)\
  2528. \009\009\009term.write(msg)\
  2529. elseif w >= 15 then\
  2530. \009\009\009local msg = \"NPaintPro\"\
  2531. \009\009\009term.setCursorPos(math.ceil(w/2 - #msg/2), h/2)\
  2532. \009\009\009term.setTextColour(colours.cyan)\
  2533. \009\009\009term.write(msg)\
  2534. \009\009\009msg = \"NitrogenFingers\"\
  2535. \009\009\009term.setCursorPos(math.ceil(w/2 - #msg/2), h/2 + 1)\
  2536. \009\009\009term.setTextColour(colours.black)\
  2537. \009\009\009term.write(msg)\
  2538. \009\009else\
  2539. \009\009\009local msg = \"NPP\"\
  2540. \009\009\009term.setCursorPos(math.ceil(w/2 - #msg/2), math.floor(h/2))\
  2541. \009\009\009term.setTextColour(colours.cyan)\
  2542. \009\009\009term.write(msg)\
  2543. \009\009\009msg = \"By NF\"\
  2544. \009\009\009term.setCursorPos(math.ceil(w/2 - #msg/2), math.ceil(h/2))\
  2545. \009\009\009term.setTextColour(colours.black)\
  2546. \009\009\009term.write(msg)\
  2547. \009\009end\
  2548. os.pullEvent()\
  2549. end\
  2550. \
  2551. --[[Clears the display to the alpha channel colour, draws the canvas, the image buffer and the selection\
  2552. rectanlge if any of these things are present.\
  2553. Params: none\
  2554. Returns:nil\
  2555. ]]--\
  2556. local function drawCanvas()\
  2557. --We have to readjust the position of the canvas if we're printing\
  2558. turtlechar = \"@\"\
  2559. if state == \"active print\" then\
  2560. if layering == \"up\" then\
  2561. if py >= 1 and py <= #frames then\
  2562. sFrame = py\
  2563. end\
  2564. if pz < sy then sy = pz\
  2565. elseif pz > sy + h - 1 then sy = pz + h - 1 end\
  2566. if px < sx then sx = px\
  2567. elseif px > sx + w - 2 then sx = px + w - 2 end\
  2568. else\
  2569. if pz >= 1 and pz <= #frames then\
  2570. sFrame = pz\
  2571. end\
  2572. \
  2573. if py < sy then sy = py\
  2574. elseif py > sy + h - 1 then sy = py + h - 1 end\
  2575. if px < sx then sx = px\
  2576. elseif px > sx + w - 2 then sx = px + w - 2 end\
  2577. end\
  2578. \
  2579. if pfx == 1 then turtlechar = \">\"\
  2580. elseif pfx == -1 then turtlechar = \"<\"\
  2581. elseif pfz == 1 then turtlechar = \"V\"\
  2582. elseif pfz == -1 then turtlechar = \"^\"\
  2583. end\
  2584. end\
  2585. \
  2586. --Picture next\
  2587. local topLayer, botLayer\
  2588. if layerDisplay then\
  2589. topLayer = sFrame\
  2590. botLayer = 1\
  2591. else\
  2592. topLayer,botLayer = sFrame,sFrame\
  2593. end\
  2594. \
  2595. \009 --How far the canvas draws. If the interface is visible, it stops short of that.\
  2596. \009 local wlim,hlim = 0,0\
  2597. \009\009if not interfaceHidden then\
  2598. \009\009\009wlim = 2\
  2599. \009\009\009hlim = 1\
  2600. \009\009end\
  2601. \009 \
  2602. for currframe = botLayer,topLayer,1 do\
  2603. for y=sy+1,sy+h-hlim do\
  2604. if frames[currframe][y] then\
  2605. for x=sx+1,sx+w-wlim do\
  2606. term.setCursorPos(x-sx,y-sy)\
  2607. if frames[currframe][y][x] then\
  2608. term.setBackgroundColour(frames[currframe][y][x])\
  2609. if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then\
  2610. term.setTextColour(frames[currframe].textcol[y][x])\
  2611. term.write(frames[currframe].text[y][x])\
  2612. else\
  2613. term.write(\" \")\
  2614. end\
  2615. else\
  2616. tileExists = false\
  2617. for i=currframe-1,botLayer,-1 do\
  2618. if frames[i][y][x] then\
  2619. tileExists = true\
  2620. break\
  2621. end\
  2622. end\
  2623. \
  2624. if not tileExists then\
  2625. if blueprint then\
  2626. term.setBackgroundColour(colours.blue)\
  2627. term.setTextColour(colours.white)\
  2628. if x == sx+1 and y % 4 == 1 then\
  2629. term.write(\"\"..((y/4) % 10))\
  2630. elseif y == sy + 1 and x % 4 == 1 then\
  2631. term.write(\"\"..((x/4) % 10))\
  2632. elseif x % 2 == 1 and y % 2 == 1 then\
  2633. term.write(\"+\")\
  2634. elseif x % 2 == 1 then\
  2635. term.write(\"|\")\
  2636. elseif y % 2 == 1 then\
  2637. term.write(\"-\")\
  2638. else\
  2639. term.write(\" \")\
  2640. end\
  2641. else\
  2642. term.setBackgroundColour(alphaC)\
  2643. if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then\
  2644. term.setTextColour(frames[currframe].textcol[y][x])\
  2645. term.write(frames[currframe].text[y][x])\
  2646. else\
  2647. term.write(\" \")\
  2648. end\
  2649. end\
  2650. end\
  2651. end\
  2652. end\
  2653. else\
  2654. for x=sx+1,sx+w-wlim do\
  2655. term.setCursorPos(x-sx,y-sy)\
  2656. \
  2657. tileExists = false\
  2658. for i=currframe-1,botLayer,-1 do\
  2659. if frames[i][y] and frames[i][y][x] then\
  2660. tileExists = true\
  2661. break\
  2662. end\
  2663. end\
  2664. \
  2665. if not tileExists then\
  2666. if blueprint then\
  2667. term.setBackgroundColour(colours.blue)\
  2668. term.setTextColour(colours.white)\
  2669. if x == sx+1 and y % 4 == 1 then\
  2670. term.write(\"\"..((y/4) % 10))\
  2671. elseif y == sy + 1 and x % 4 == 1 then\
  2672. term.write(\"\"..((x/4) % 10))\
  2673. elseif x % 2 == 1 and y % 2 == 1 then\
  2674. term.write(\"+\")\
  2675. elseif x % 2 == 1 then\
  2676. term.write(\"|\")\
  2677. elseif y % 2 == 1 then\
  2678. term.write(\"-\")\
  2679. else\
  2680. term.write(\" \")\
  2681. end\
  2682. else\
  2683. term.setBackgroundColour(alphaC)\
  2684. term.write(\" \")\
  2685. end\
  2686. end\
  2687. end\
  2688. end\
  2689. end\
  2690. end\
  2691. \
  2692. --Then the printer, if he's on\
  2693. if state == \"active print\" then\
  2694. local bgColour = alphaC\
  2695. if layering == \"up\" then\
  2696. term.setCursorPos(px-sx,pz-sy)\
  2697. if frames[sFrame] and frames[sFrame][pz-sy] and frames[sFrame][pz-sy][px-sx] then\
  2698. bgColour = frames[sFrame][pz-sy][px-sx]\
  2699. elseif blueprint then bgColour = colours.blue end\
  2700. else\
  2701. term.setCursorPos(px-sx,py-sy)\
  2702. if frames[sFrame] and frames[sFrame][py-sy] and frames[sFrame][py-sy][px-sx] then\
  2703. bgColour = frames[sFrame][py-sy][px-sx]\
  2704. elseif blueprint then bgColour = colours.blue end\
  2705. end\
  2706. \
  2707. term.setBackgroundColour(bgColour)\
  2708. if bgColour == colours.black then term.setTextColour(colours.white)\
  2709. else term.setTextColour(colours.black) end\
  2710. \
  2711. term.write(turtlechar)\
  2712. end\
  2713. \
  2714. --Then the buffer\
  2715. if selectrect then\
  2716. if buffer and rectblink == 1 then\
  2717. for y=selectrect.y1, math.min(selectrect.y2, selectrect.y1 + buffer.height-1) do\
  2718. for x=selectrect.x1, math.min(selectrect.x2, selectrect.x1 + buffer.width-1) do\
  2719. if buffer.contents[y-selectrect.y1+1][x-selectrect.x1+1] then\
  2720. term.setCursorPos(x+sx,y+sy)\
  2721. term.setBackgroundColour(buffer.contents[y-selectrect.y1+1][x-selectrect.x1+1])\
  2722. term.write(\" \")\
  2723. end\
  2724. end\
  2725. end\
  2726. end\
  2727. \
  2728. --This draws the \"selection\" box\
  2729. local add = nil\
  2730. if buffer then\
  2731. term.setBackgroundColour(colours.lightGrey)\
  2732. else\
  2733. term.setBackgroundColour(colours.grey)\
  2734. end\
  2735. for i=selectrect.x1, selectrect.x2 do\
  2736. add = (i + selectrect.y1 + rectblink) % 2 == 0\
  2737. term.setCursorPos(i-sx,selectrect.y1-sy)\
  2738. if add then term.write(\" \") end\
  2739. add = (i + selectrect.y2 + rectblink) % 2 == 0\
  2740. term.setCursorPos(i-sx,selectrect.y2-sy)\
  2741. if add then term.write(\" \") end\
  2742. end\
  2743. for i=selectrect.y1 + 1, selectrect.y2 - 1 do\
  2744. add = (i + selectrect.x1 + rectblink) % 2 == 0\
  2745. term.setCursorPos(selectrect.x1-sx,i-sy)\
  2746. if add then term.write(\" \") end\
  2747. add = (i + selectrect.x2 + rectblink) % 2 == 0\
  2748. term.setCursorPos(selectrect.x2-sx,i-sy)\
  2749. if add then term.write(\" \") end\
  2750. end\
  2751. end\
  2752. end\
  2753. \
  2754. --[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any\
  2755. messages currently being displayed\
  2756. Params: none\
  2757. Returns:nil\
  2758. ]]--\
  2759. local function drawInterface()\
  2760. --Picker\
  2761. \009\009local coffset,ioffset = 0,0\
  2762. \009\009local maxcsize = h-2\
  2763. \009\009if h < #column + 2 then\
  2764. \009\009\009maxcsize = h-4\
  2765. \009\009\009coffset = columnoffset\
  2766. \009\009\009ioffset = 1\
  2767. \009\009\009term.setBackgroundColour(colours.lightGrey)\
  2768. \009\009\009term.setTextColour(colours.grey)\
  2769. \009\009\009term.setCursorPos(w-1,1)\
  2770. \009\009\009term.write(\"^^\")\
  2771. \009\009\009term.setCursorPos(w-1,h-2)\
  2772. \009\009\009term.write(\"VV\")\
  2773. \009\009end\
  2774. for i=1,math.min(#column+1,maxcsize) do\
  2775. \009\009\009term.setCursorPos(w-1, i + ioffset)\
  2776. \009\009\009local ci = i+coffset\
  2777. \009\009\009if ci == #column+1 then\
  2778. \009\009\009\009term.setBackgroundColour(colours.black)\
  2779. \009\009\009\009term.setTextColour(colours.red)\
  2780. \009\009\009\009term.write(\"XX\")\
  2781. \009\009\009elseif state == \"print\" then\
  2782. \009\009\009\009term.setBackgroundColour(column[ci])\
  2783. \009\009\009\009if column[ci] == colours.black then\
  2784. \009\009\009\009\009term.setTextColour(colours.white)\
  2785. \009\009\009\009else term.setTextColour(colours.black) end\
  2786. \009\009\009\009\
  2787. \009\009\009\009if requirementsDisplayed then\
  2788. \009\009\009\009\009\009if requiredMaterials[i] < 10 then term.write(\" \") end\
  2789. \009\009\009\009\009\009term.setCursorPos(w-#tostring(requiredMaterials[i])+1, i)\
  2790. \009\009\009\009\009\009term.write(requiredMaterials[i])\
  2791. \009\009\009\009else\
  2792. \009\009\009\009\009\009if i+coffset < 10 then term.write(\" \") end\
  2793. \009\009\009\009\009\009term.write(i+coffset)\
  2794. \009\009\009\009end\
  2795. \009\009\009else\
  2796. \009\009\009\009term.setBackgroundColour(column[ci])\
  2797. \009\009\009\009term.write(\" \")\
  2798. \009\009\009end\
  2799. end\
  2800. \009\009--Filling the whitespace with... 'greyspace' *shudder*\
  2801. \009\009if h > #column+3 then\
  2802. \009\009\009term.setTextColour(colours.grey)\
  2803. \009\009\009term.setBackgroundColour(colours.lightGrey)\
  2804. \009\009\009for y=#column+2,h-2 do\
  2805. \009\009\009\009term.setCursorPos(w-1,y)\
  2806. \009\009\009\009term.write(\"| \")\
  2807. \009\009\009end\
  2808. \009\009end\
  2809. --Pallette\
  2810. term.setCursorPos(w-1,h-1)\
  2811. if not lSel then\
  2812. term.setBackgroundColour(colours.black)\
  2813. term.setTextColour(colours.red)\
  2814. term.write(\"X\")\
  2815. else\
  2816. term.setBackgroundColour(lSel)\
  2817. term.setTextColour(lSel)\
  2818. term.write(\" \")\
  2819. end\
  2820. if not rSel then\
  2821. term.setBackgroundColour(colours.black)\
  2822. term.setTextColour(colours.red)\
  2823. term.write(\"X\")\
  2824. else\
  2825. term.setBackgroundColour(rSel)\
  2826. term.setTextColour(rSel)\
  2827. term.write(\" \")\
  2828. end\
  2829. --Footer\
  2830. if inMenu then return end\
  2831. \
  2832. term.setCursorPos(1, h)\
  2833. term.setBackgroundColour(colours.lightGrey)\
  2834. term.setTextColour(colours.grey)\
  2835. term.clearLine()\
  2836. \009\009if mainAvailable then\
  2837. \009\009\009if inDropDown then\
  2838. \009\009\009\009\009term.write(string.rep(\" \", #ddModes.name + 2))\
  2839. \009\009\009else\
  2840. \009\009\009\009\009term.setBackgroundColour(colours.grey)\
  2841. \009\009\009\009\009term.setTextColour(colours.lightGrey)\
  2842. \009\009\009\009\009term.write(ddModes.name..\" \")\
  2843. \009\009\009end\
  2844. \009\009end\
  2845. term.setBackgroundColour(colours.lightGrey)\
  2846. term.setTextColour(colours.grey)\
  2847. term.write(getStateMessage())\
  2848. \
  2849. local coords=\"X:\"..sx..\" Y:\"..sy\
  2850. if animated then coords = coords..\" Frame:\"..sFrame..\"/\"..framecount..\" \" end\
  2851. term.setCursorPos(w-#coords+1,h)\
  2852. if state == \"play\" then term.setBackgroundColour(colours.lime)\
  2853. elseif record then term.setBackgroundColour(colours.red) end\
  2854. term.write(coords)\
  2855. \
  2856. if animated then\
  2857. term.setCursorPos(w-1,h)\
  2858. term.setBackgroundColour(colours.grey)\
  2859. term.setTextColour(colours.lightGrey)\
  2860. term.write(\"<>\")\
  2861. end\
  2862. end\
  2863. \
  2864. --[[Runs an interface where users can select topics of help. Will return once the user quits the help screen.\
  2865. Params: none\
  2866. Returns:nil\
  2867. ]]--\
  2868. local function drawHelpScreen()\
  2869. local selectedHelp = nil\
  2870. while true do\
  2871. term.setBackgroundColour(colours.lightGrey)\
  2872. term.clear()\
  2873. if not selectedHelp then\
  2874. term.setCursorPos(4, 1)\
  2875. term.setTextColour(colours.brown)\
  2876. term.write(\"Available modes (click for info):\")\
  2877. for i=1,#helpTopics do\
  2878. term.setCursorPos(2, 2 + i)\
  2879. term.setTextColour(colours.black)\
  2880. term.write(helpTopics[i].name)\
  2881. if helpTopics[i].key then\
  2882. term.setTextColour(colours.red)\
  2883. term.write(\" (\"..helpTopics[i].key..\")\")\
  2884. end\
  2885. end\
  2886. term.setCursorPos(4,h)\
  2887. term.setTextColour(colours.black)\
  2888. term.write(\"Press any key to exit\")\
  2889. else\
  2890. term.setCursorPos(4,1)\
  2891. term.setTextColour(colours.brown)\
  2892. term.write(helpTopics[selectedHelp].name)\
  2893. if helpTopics[selectedHelp].key then\
  2894. term.setTextColour(colours.red)\
  2895. term.write(\" (\"..helpTopics[selectedHelp].key..\")\")\
  2896. end\
  2897. term.setCursorPos(1,3)\
  2898. term.setTextColour(colours.black)\
  2899. print(helpTopics[selectedHelp].message..\"\\n\")\
  2900. for i=1,#helpTopics[selectedHelp].controls do\
  2901. term.setTextColour(colours.brown)\
  2902. term.write(helpTopics[selectedHelp].controls[i][1]..\" \")\
  2903. term.setTextColour(colours.black)\
  2904. print(helpTopics[selectedHelp].controls[i][2])\
  2905. end\
  2906. end\
  2907. \
  2908. local id,p1,p2,p3 = os.pullEvent()\
  2909. \
  2910. if id == \"timer\" then updateTimer(p1)\
  2911. elseif id == \"key\" then\
  2912. if selectedHelp then selectedHelp = nil\
  2913. else break end\
  2914. elseif id == \"mouse_click\" then\
  2915. if not selectedHelp then\
  2916. if p3 >=3 and p3 <= 2+#helpTopics then\
  2917. selectedHelp = p3-2\
  2918. else break end\
  2919. else\
  2920. selectedHelp = nil\
  2921. end\
  2922. end\
  2923. end\
  2924. end\
  2925. \
  2926. --[[Draws a message in the footer bar. A helper for DrawInterface, but can be called for custom messages, if the\
  2927. inMenu paramter is set to true while this is being done (remember to set it back when done!)\
  2928. Params: message:string = The message to be drawn\
  2929. Returns:nil\
  2930. ]]--\
  2931. local function drawMessage(message)\
  2932. term.setCursorPos(1,h)\
  2933. term.setBackgroundColour(colours.lightGrey)\
  2934. term.setTextColour(colours.grey)\
  2935. term.clearLine()\
  2936. term.write(message)\
  2937. end\
  2938. \
  2939. --[[\
  2940. Section: Generic Interfaces\
  2941. ]]--\
  2942. \
  2943. \
  2944. --[[One of my generic text printing methods, printing a message at a specified position with width and offset.\
  2945. No colour materials included.\
  2946. Params: msg:string = The message to print off-center\
  2947. height:number = The starting height of the message\
  2948. width:number = The limit as to how many characters long each line may be\
  2949. offset:number = The starting width offset of the message\
  2950. Returns:number the number of lines used in printing the message\
  2951. ]]--\
  2952. local function wprintOffCenter(msg, height, width, offset)\
  2953. local inc = 0\
  2954. local ops = 1\
  2955. while #msg - ops > width do\
  2956. local nextspace = 0\
  2957. while string.find(msg, \" \", ops + nextspace) and\
  2958. string.find(msg, \" \", ops + nextspace) - ops < width do\
  2959. nextspace = string.find(msg, \" \", nextspace + ops) + 1 - ops\
  2960. end\
  2961. local ox,oy = term.getCursorPos()\
  2962. term.setCursorPos(width/2 - (nextspace)/2 + offset, height + inc)\
  2963. inc = inc + 1\
  2964. term.write(string.sub(msg, ops, nextspace + ops - 1))\
  2965. ops = ops + nextspace\
  2966. end\
  2967. term.setCursorPos(width/2 - #string.sub(msg, ops)/2 + offset, height + inc)\
  2968. term.write(string.sub(msg, ops))\
  2969. \
  2970. return inc + 1\
  2971. end\
  2972. \
  2973. --[[Draws a message that must be clicked on or a key struck to be cleared. No options, so used for displaying\
  2974. generic information.\
  2975. Params: ctitle:string = The title of the confirm dialogue\
  2976. msg:string = The message displayed in the dialogue\
  2977. Returns:nil\
  2978. ]]--\
  2979. local function displayConfirmDialogue(ctitle, msg)\
  2980. local dialogoffset = 8\
  2981. --We actually print twice- once to get the lines, second time to print proper. Easier this way.\
  2982. local lines = wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2)\
  2983. \
  2984. term.setCursorPos(dialogoffset, 3)\
  2985. term.setBackgroundColour(colours.grey)\
  2986. term.setTextColour(colours.lightGrey)\
  2987. term.write(string.rep(\" \", w - dialogoffset * 2))\
  2988. term.setCursorPos(dialogoffset + (w - dialogoffset * 2)/2 - #ctitle/2, 3)\
  2989. term.write(ctitle)\
  2990. term.setTextColour(colours.grey)\
  2991. term.setBackgroundColour(colours.lightGrey)\
  2992. term.setCursorPos(dialogoffset, 4)\
  2993. term.write(string.rep(\" \", w - dialogoffset * 2))\
  2994. for i=5,5+lines do\
  2995. term.setCursorPos(dialogoffset, i)\
  2996. term.write(\" \"..string.rep(\" \", w - (dialogoffset) * 2 - 2)..\" \")\
  2997. end\
  2998. wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2)\
  2999. \
  3000. --In the event of a message, the player hits anything to continue\
  3001. while true do\
  3002. local id,key = os.pullEvent()\
  3003. if id == \"timer\" then updateTimer(key);\
  3004. elseif id == \"key\" or id == \"mouse_click\" or id == \"mouse_drag\" then break end\
  3005. end\
  3006. end\
  3007. \
  3008. --[[Produces a nice dropdown menu based on a table of strings. Depending on the position, this will auto-adjust the position\
  3009. of the menu drawn, and allows nesting of menus and sub menus. Clicking anywhere outside the menu will cancel and return nothing\
  3010. Params: x:int = the x position the menu should be displayed at\
  3011. y:int = the y position the menu should be displayed at\
  3012. options:table = the list of options available to the user, as strings or submenus (tables of strings, with a name parameter)\
  3013. Returns:string the selected menu option.\
  3014. ]]--\
  3015. local function displayDropDown(x, y, options)\
  3016. inDropDown = true\
  3017. --Figures out the dimensions of our thing\
  3018. local longestX = #options.name\
  3019. for i=1,#options do\
  3020. local currVal = options[i]\
  3021. if type(currVal) == \"table\" then currVal = currVal.name end\
  3022. \
  3023. longestX = math.max(longestX, #currVal)\
  3024. end\
  3025. local xOffset = math.max(0, longestX - ((w-2) - x) + 1)\
  3026. local yOffset = math.max(0, #options - ((h-1) - y))\
  3027. \
  3028. local clickTimes = 0\
  3029. local tid = nil\
  3030. local selection = nil\
  3031. while clickTimes < 2 do\
  3032. drawCanvas()\
  3033. drawInterface()\
  3034. \
  3035. term.setCursorPos(x-xOffset,y-yOffset)\
  3036. term.setBackgroundColour(colours.grey)\
  3037. term.setTextColour(colours.lightGrey)\
  3038. term.write(options.name..string.rep(\" \", longestX-#options.name + 2))\
  3039. \
  3040. for i=1,#options do\
  3041. term.setCursorPos(x-xOffset, y-yOffset+i)\
  3042. if i==selection and clickTimes % 2 == 0 then\
  3043. term.setBackgroundColour(colours.grey)\
  3044. term.setTextColour(colours.lightGrey)\
  3045. else\
  3046. term.setBackgroundColour(colours.lightGrey)\
  3047. term.setTextColour(colours.grey)\
  3048. end\
  3049. local currVal = options[i]\
  3050. if type(currVal) == \"table\" then\
  3051. term.write(currVal.name..string.rep(\" \", longestX-#currVal.name + 1))\
  3052. term.setBackgroundColour(colours.grey)\
  3053. term.setTextColour(colours.lightGrey)\
  3054. term.write(\">\")\
  3055. else\
  3056. term.write(currVal..string.rep(\" \", longestX-#currVal + 2))\
  3057. end\
  3058. end\
  3059. \
  3060. local id, p1, p2, p3 = os.pullEvent()\
  3061. if id == \"timer\" then\
  3062. if p1 == tid then\
  3063. clickTimes = clickTimes + 1\
  3064. if clickTimes > 2 then\
  3065. break\
  3066. else\
  3067. tid = os.startTimer(0.1)\
  3068. end\
  3069. else\
  3070. updateTimer(p1)\
  3071. drawCanvas()\
  3072. drawInterface()\
  3073. end\
  3074. elseif id == \"mouse_click\" then\
  3075. if p2 >=x-xOffset and p2 <= x-xOffset + longestX + 1 and p3 >= y-yOffset+1 and p3 <= y-yOffset+#options then\
  3076. selection = p3-(y-yOffset)\
  3077. tid = os.startTimer(0.1)\
  3078. else\
  3079. selection = \"\"\
  3080. break\
  3081. end\
  3082. end\
  3083. end\
  3084. \
  3085. if type(selection) == \"number\" then\
  3086. selection = options[selection]\
  3087. end\
  3088. \
  3089. if type(selection) == \"string\" then\
  3090. inDropDown = false\
  3091. return selection\
  3092. elseif type(selection) == \"table\" then\
  3093. return displayDropDown(x, y, selection)\
  3094. end\
  3095. end\
  3096. \
  3097. --[[A custom io.read() function with a few differences- it limits the number of characters being printed,\
  3098. waits a 1/100th of a second so any keys still in the event library are removed before input is read and\
  3099. the timer for the selectionrectangle is continuously updated during the process.\
  3100. Params: lim:int = the number of characters input is allowed\
  3101. Returns:string the inputted string, trimmed of leading and tailing whitespace\
  3102. ]]--\
  3103. local function readInput(lim)\
  3104. term.setCursorBlink(true)\
  3105. \
  3106. local inputString = \"\"\
  3107. if not lim or type(lim) ~= \"number\" or lim < 1 then lim = w - ox end\
  3108. local ox,oy = term.getCursorPos()\
  3109. --We only get input from the footer, so this is safe. Change if recycling\
  3110. term.setBackgroundColour(colours.lightGrey)\
  3111. term.setTextColour(colours.grey)\
  3112. term.write(string.rep(\" \", lim))\
  3113. term.setCursorPos(ox, oy)\
  3114. --As events queue immediately, we may get an unwanted key... this will solve that problem\
  3115. local inputTimer = os.startTimer(0.01)\
  3116. local keysAllowed = false\
  3117. \
  3118. while true do\
  3119. local id,key = os.pullEvent()\
  3120. \
  3121. if keysAllowed then\
  3122. if id == \"key\" and key == 14 and #inputString > 0 then\
  3123. inputString = string.sub(inputString, 1, #inputString-1)\
  3124. term.setCursorPos(ox + #inputString,oy)\
  3125. term.write(\" \")\
  3126. elseif id == \"key\" and key == 28 and inputString ~= string.rep(\" \", #inputString) then\
  3127. break\
  3128. elseif id == \"key\" and key == keys.leftCtrl then\
  3129. return \"\"\
  3130. elseif id == \"char\" and #inputString < lim then\
  3131. inputString = inputString..key\
  3132. end\
  3133. end\
  3134. \
  3135. if id == \"timer\" then\
  3136. if key == inputTimer then\
  3137. keysAllowed = true\
  3138. else\
  3139. updateTimer(key)\
  3140. drawCanvas()\
  3141. drawInterface()\
  3142. term.setBackgroundColour(colours.lightGrey)\
  3143. term.setTextColour(colours.grey)\
  3144. end\
  3145. end\
  3146. term.setCursorPos(ox,oy)\
  3147. term.write(inputString)\
  3148. term.setCursorPos(ox + #inputString, oy)\
  3149. end\
  3150. \
  3151. while string.sub(inputString, 1, 1) == \" \" do\
  3152. inputString = string.sub(inputString, 2, #inputString)\
  3153. end\
  3154. while string.sub(inputString, #inputString, #inputString) == \" \" do\
  3155. inputString = string.sub(inputString, 1, #inputString-1)\
  3156. end\
  3157. term.setCursorBlink(false)\
  3158. \
  3159. return inputString\
  3160. end\
  3161. \
  3162. --[[ \
  3163. Section: Image tools\
  3164. ]]--\
  3165. \
  3166. \
  3167. --[[Copies all pixels beneath the selection rectangle into the image buffer. Empty buffers are converted to nil.\
  3168. Params: removeImage:bool = true if the image is to be erased after copying, false otherwise\
  3169. Returns:nil\
  3170. ]]--\
  3171. local function copyToBuffer(removeImage)\
  3172. buffer = { width = selectrect.x2 - selectrect.x1 + 1, height = selectrect.y2 - selectrect.y1 + 1, contents = { } }\
  3173. \
  3174. local containsSomething = false\
  3175. for y=1,buffer.height do\
  3176. buffer.contents[y] = { }\
  3177. local f,l = sFrame,sFrame\
  3178. if record then f,l = 1, framecount end\
  3179. \
  3180. for fra = f,l do\
  3181. if frames[fra][selectrect.y1 + y - 1] then\
  3182. for x=1,buffer.width do\
  3183. buffer.contents[y][x] = frames[sFrame][selectrect.y1 + y - 1][selectrect.x1 + x - 1]\
  3184. if removeImage then frames[fra][selectrect.y1 + y - 1][selectrect.x1 + x - 1] = nil end\
  3185. if buffer.contents[y][x] then containsSomething = true end\
  3186. end\
  3187. end\
  3188. end\
  3189. end\
  3190. --I don't classify an empty buffer as a real buffer- confusing to the user.\
  3191. if not containsSomething then buffer = nil end\
  3192. end\
  3193. \
  3194. --[[Replaces all pixels under the selection rectangle with the image buffer (or what can be seen of it). Record-dependent.\
  3195. Params: removeBuffer:bool = true if the buffer is to be emptied after copying, false otherwise\
  3196. Returns:nil\
  3197. ]]--\
  3198. local function copyFromBuffer(removeBuffer)\
  3199. if not buffer then return end\
  3200. \
  3201. for y = 1, math.min(buffer.height,selectrect.y2-selectrect.y1+1) do\
  3202. local f,l = sFrame, sFrame\
  3203. if record then f,l = 1, framecount end\
  3204. \
  3205. for fra = f,l do\
  3206. if not frames[fra][selectrect.y1+y-1] then frames[fra][selectrect.y1+y-1] = { } end\
  3207. for x = 1, math.min(buffer.width,selectrect.x2-selectrect.x1+1) do\
  3208. frames[fra][selectrect.y1+y-1][selectrect.x1+x-1] = buffer.contents[y][x]\
  3209. end\
  3210. end\
  3211. end\
  3212. \
  3213. if removeBuffer then buffer = nil end\
  3214. end\
  3215. \
  3216. --[[Moves the entire image (or entire animation) to the specified coordinates. Record-dependent.\
  3217. Params: newx:int = the X coordinate to move the image to\
  3218. newy:int = the Y coordinate to move the image to\
  3219. Returns:nil\
  3220. ]]--\
  3221. local function moveImage(newx,newy)\
  3222. if not leflim or not toplim then return end\
  3223. if newx <=0 or newy <=0 then return end\
  3224. local f,l = sFrame,sFrame\
  3225. if record then f,l = 1,framecount end\
  3226. \
  3227. for i=f,l do\
  3228. local newlines = { }\
  3229. for y=toplim,botlim do\
  3230. local line = frames[i][y]\
  3231. if line then\
  3232. newlines[y-toplim+newy] = { }\
  3233. for x,char in pairs(line) do\
  3234. newlines[y-toplim+newy][x-leflim+newx] = char\
  3235. end\
  3236. end\
  3237. end\
  3238. --Exceptions that allow us to move the text as well\
  3239. if textEnabled then\
  3240. newlines.text = { }\
  3241. for y=toplim,botlim do\
  3242. local line = frames[i].text[y]\
  3243. if line then\
  3244. newlines.text[y-toplim+newy] = { }\
  3245. for x,char in pairs(line) do\
  3246. newlines.text[y-toplim+newy][x-leflim+newx] = char\
  3247. end\
  3248. end\
  3249. end\
  3250. \
  3251. newlines.textcol = { }\
  3252. for y=toplim,botlim do\
  3253. local line = frames[i].textcol[y]\
  3254. if line then\
  3255. newlines.textcol[y-toplim+newy] = { }\
  3256. for x,char in pairs(line) do\
  3257. newlines.textcol[y-toplim+newy][x-leflim+newx] = char\
  3258. end\
  3259. end\
  3260. end\
  3261. end\
  3262. \
  3263. frames[i] = newlines\
  3264. end\
  3265. end\
  3266. \
  3267. --[[Prompts the user to clear the current frame or all frames. Record-dependent.,\
  3268. Params: none\
  3269. Returns:nil\
  3270. ]]--\
  3271. local function clearImage()\
  3272. inMenu = true\
  3273. if not animated then\
  3274. drawMessage(\"Clear image? Y/N: \")\
  3275. elseif record then\
  3276. drawMessage(\"Clear ALL frames? Y/N: \")\
  3277. else\
  3278. drawMessage(\"Clear current frame? Y/N :\")\
  3279. end\
  3280. if string.find(string.upper(readInput(1)), \"Y\") then\
  3281. local f,l = sFrame,sFrame\
  3282. if record then f,l = 1,framecount end\
  3283. \
  3284. for i=f,l do\
  3285. frames[i] = { }\
  3286. end\
  3287. end\
  3288. inMenu = false\
  3289. end\
  3290. \
  3291. --[[A recursively called method (watch out for big calls!) in which every pixel of a set colour is\
  3292. changed to another colour. Does not work on the nil colour, for obvious reasons.\
  3293. Params: x:int = The X coordinate of the colour to flood-fill\
  3294. y:int = The Y coordinate of the colour to flood-fill\
  3295. targetColour:colour = the colour that is being flood-filled\
  3296. newColour:colour = the colour with which to replace the target colour\
  3297. Returns:nil\
  3298. ]]--\
  3299. local function floodFill(x, y, targetColour, newColour)\
  3300. if not newColour or not targetColour then return end\
  3301. local nodeList = { }\
  3302. \
  3303. table.insert(nodeList, {x = x, y = y})\
  3304. \
  3305. while #nodeList > 0 do\
  3306. local node = nodeList[1]\
  3307. if frames[sFrame][node.y] and frames[sFrame][node.y][node.x] == targetColour then\
  3308. frames[sFrame][node.y][node.x] = newColour\
  3309. table.insert(nodeList, { x = node.x + 1, y = node.y})\
  3310. table.insert(nodeList, { x = node.x, y = node.y + 1})\
  3311. if x > 1 then table.insert(nodeList, { x = node.x - 1, y = node.y}) end\
  3312. if y > 1 then table.insert(nodeList, { x = node.x, y = node.y - 1}) end\
  3313. end\
  3314. table.remove(nodeList, 1)\
  3315. end\
  3316. end\
  3317. \
  3318. --[[ \
  3319. Section: Animation Tools \
  3320. ]]--\
  3321. \
  3322. --[[Enters play mode, allowing the animation to play through. Interface is restricted to allow this,\
  3323. and method only leaves once the player leaves play mode.\
  3324. Params: none\
  3325. Returns:nil\
  3326. ]]--\
  3327. local function playAnimation()\
  3328. state = \"play\"\
  3329. selectedrect = nil\
  3330. \
  3331. local animt = os.startTimer(animtime)\
  3332. repeat\
  3333. drawCanvas()\
  3334. drawInterface()\
  3335. \
  3336. local id,key,_,y = os.pullEvent()\
  3337. \
  3338. if id==\"timer\" then\
  3339. if key == animt then\
  3340. animt = os.startTimer(animtime)\
  3341. sFrame = (sFrame % framecount) + 1\
  3342. else\
  3343. updateTimer(key)\
  3344. end\
  3345. elseif id==\"key\" then\
  3346. if key == keys.comma and animtime > 0.1 then animtime = animtime - 0.05\
  3347. elseif key == keys.period and animtime < 0.5 then animtime = animtime + 0.05\
  3348. elseif key == keys.space then state = \"paint\" end\
  3349. elseif id==\"mouse_click\" and y == h then\
  3350. state = \"paint\"\
  3351. end\
  3352. until state ~= \"play\"\
  3353. os.startTimer(0.5)\
  3354. end\
  3355. \
  3356. --[[Changes the selected frame (sFrame) to the chosen frame. If this frame is above the framecount,\
  3357. additional frames are created with a copy of the image on the selected frame.\
  3358. Params: newframe:int = the new frame to move to\
  3359. Returns:nil\
  3360. ]]--\
  3361. local function changeFrame(newframe)\
  3362. inMenu = true\
  3363. if not tonumber(newframe) then\
  3364. term.setCursorPos(1,h)\
  3365. term.setBackgroundColour(colours.lightGrey)\
  3366. term.setTextColour(colours.grey)\
  3367. term.clearLine()\
  3368. \
  3369. term.write(\"Go to frame: \")\
  3370. newframe = tonumber(readInput(2))\
  3371. if not newframe or newframe <= 0 then\
  3372. inMenu = false\
  3373. return\
  3374. end\
  3375. elseif newframe <= 0 then return end\
  3376. \
  3377. if newframe > framecount then\
  3378. for i=framecount+1,newframe do\
  3379. frames[i] = {}\
  3380. for y,line in pairs(frames[sFrame]) do\
  3381. frames[i][y] = { }\
  3382. for x,v in pairs(line) do\
  3383. frames[i][y][x] = v\
  3384. end\
  3385. end\
  3386. end\
  3387. framecount = newframe\
  3388. end\
  3389. sFrame = newframe\
  3390. inMenu = false\
  3391. end\
  3392. \
  3393. --[[Removes every frame leading after the frame passed in\
  3394. Params: frame:int the non-inclusive lower bounds of the delete\
  3395. Returns:nil\
  3396. ]]--\
  3397. local function removeFramesAfter(frame)\
  3398. inMenu = true\
  3399. if frame==framecount then return end\
  3400. drawMessage(\"Remove frames \"..(frame+1)..\"/\"..framecount..\"? Y/N :\")\
  3401. local answer = string.upper(readInput(1))\
  3402. \
  3403. if string.find(answer, string.upper(\"Y\")) ~= 1 then\
  3404. inMenu = false\
  3405. return\
  3406. end\
  3407. \
  3408. for i=frame+1, framecount do\
  3409. frames[i] = nil\
  3410. end\
  3411. framecount = frame\
  3412. inMenu = false\
  3413. end\
  3414. \
  3415. --[[\
  3416. Section: Printing Tools\
  3417. ]]--\
  3418. \
  3419. --[[Constructs a new facing to the left of the current facing\
  3420. Params: curx:number = The facing on the X axis\
  3421. curz:number = The facing on the Z axis\
  3422. hand:string = The hand of the axis (\"right\" or \"left\")\
  3423. Returns:number,number = the new facing on the X and Z axis after a left turn\
  3424. ]]--\
  3425. local function getLeft(curx, curz)\
  3426. local hand = \"left\"\
  3427. if layering == \"up\" then hand = \"right\" end\
  3428. \
  3429. if hand == \"right\" then\
  3430. if curx == 1 then return 0,-1 end\
  3431. if curx == -1 then return 0,1 end\
  3432. if curz == 1 then return 1,0 end\
  3433. if curz == -1 then return -1,0 end\
  3434. else\
  3435. if curx == 1 then return 0,1 end\
  3436. if curx == -1 then return 0,-1 end\
  3437. if curz == 1 then return -1,0 end\
  3438. if curz == -1 then return 1,0 end\
  3439. end\
  3440. end\
  3441. \
  3442. --[[Constructs a new facing to the right of the current facing\
  3443. Params: curx:number = The facing on the X axis\
  3444. curz:number = The facing on the Z axis\
  3445. hand:string = The hand of the axis (\"right\" or \"left\")\
  3446. Returns:number,number = the new facing on the X and Z axis after a right turn\
  3447. ]]--\
  3448. local function getRight(curx, curz)\
  3449. local hand = \"left\"\
  3450. if layering == \"up\" then hand = \"right\" end\
  3451. \
  3452. if hand == \"right\" then\
  3453. if curx == 1 then return 0,1 end\
  3454. if curx == -1 then return 0,-1 end\
  3455. if curz == 1 then return -1,0 end\
  3456. if curz == -1 then return 1,0 end\
  3457. else\
  3458. if curx == 1 then return 0,-1 end\
  3459. if curx == -1 then return 0,1 end\
  3460. if curz == 1 then return 1,0 end\
  3461. if curz == -1 then return -1,0 end\
  3462. end\
  3463. end\
  3464. \
  3465. \
  3466. --[[Sends out a rednet signal requesting local printers, and will listen for any responses. Printers found are added to the\
  3467. printerList (for ID's) and printerNames (for names)\
  3468. Params: nil\
  3469. Returns:nil\
  3470. ]]--\
  3471. local function locatePrinters()\
  3472. printerList = { }\
  3473. printerNames = { name = \"Printers\" }\
  3474. local oldState = state\
  3475. state = \"Locating printers, please wait... \"\
  3476. drawCanvas()\
  3477. drawInterface()\
  3478. state = oldState\
  3479. \
  3480. local modemOpened = false\
  3481. for k,v in pairs(rs.getSides()) do\
  3482. if peripheral.isPresent(v) and peripheral.getType(v) == \"modem\" then\
  3483. rednet.open(v)\
  3484. modemOpened = true\
  3485. break\
  3486. end\
  3487. end\
  3488. \
  3489. if not modemOpened then\
  3490. displayConfirmDialogue(\"Modem not found!\", \"No modem peripheral. Must have network modem to locate printers.\")\
  3491. return false\
  3492. end\
  3493. \
  3494. rednet.broadcast(\"$3DPRINT IDENTIFY\")\
  3495. \
  3496. while true do\
  3497. local id, msg = rsTimeReceive(1)\
  3498. \
  3499. if not id then break end\
  3500. if string.find(msg, \"$3DPRINT IDACK\") == 1 then\
  3501. msg = string.gsub(msg, \"$3DPRINT IDACK \", \"\")\
  3502. table.insert(printerList, id)\
  3503. table.insert(printerNames, msg)\
  3504. end\
  3505. end\
  3506. \
  3507. if #printerList == 0 then\
  3508. displayConfirmDialogue(\"Printers not found!\", \"No active printers found in proximity of this computer.\")\
  3509. return false\
  3510. else\
  3511. return true\
  3512. end\
  3513. end\
  3514. \
  3515. --[[Sends a request to the printer. Waits on a response and updates the state of the application accordingly.\
  3516. Params: command:string the command to send\
  3517. param:string a parameter to send, if any\
  3518. Returns:nil\
  3519. ]]--\
  3520. local function sendPC(command,param)\
  3521. local msg = \"$PC \"..command\
  3522. if param then msg = msg..\" \"..param end\
  3523. rednet.send(printerList[selectedPrinter], msg)\
  3524. \
  3525. while true do\
  3526. local id,key = rsTimeReceive()\
  3527. if id == printerList[selectedPrinter] then\
  3528. if key == \"$3DPRINT ACK\" then\
  3529. break\
  3530. elseif key == \"$3DPRINT DEP\" then\
  3531. displayConfirmDialogue(\"Printer Empty\", \"The printer has exhasted a material. Please refill slot \"..param..\
  3532. \", and click this message when ready to continue.\")\
  3533. rednet.send(printerList[selectedPrinter], msg)\
  3534. elseif key == \"$3DPRINT OOF\" then\
  3535. displayConfirmDialogue(\"Printer Out of Fuel\", \"The printer has no fuel. Please replace the material \"..\
  3536. \"in slot 1 with a fuel source, then click this message.\")\
  3537. rednet.send(printerList[selectedPrinter], \"$PC SS 1\")\
  3538. id,key = rsTimeReceive()\
  3539. rednet.send(printerList[selectedPrinter], \"$PC RF\")\
  3540. id,key = rsTimeReceive()\
  3541. rednet.send(printerList[selectedPrinter], msg)\
  3542. end\
  3543. end\
  3544. end\
  3545. \
  3546. --Changes to position are handled after the event has been successfully completed\
  3547. if command == \"FW\" then\
  3548. px = px + pfx\
  3549. pz = pz + pfz\
  3550. elseif command == \"BK\" then\
  3551. px = px - pfx\
  3552. pz = pz - pfz\
  3553. elseif command == \"UP\" then\
  3554. if layering == \"up\" then\
  3555. py = py + 1\
  3556. else\
  3557. py = py - 1\
  3558. end\
  3559. elseif command == \"DW\" then\
  3560. if layering == \"up\" then\
  3561. py = py - 1\
  3562. else \
  3563. py = py + 1\
  3564. end\
  3565. elseif command == \"TL\" then\
  3566. pfx,pfz = getLeft(pfx,pfz)\
  3567. elseif command == \"TR\" then\
  3568. pfx,pfz = getRight(pfx,pfz)\
  3569. elseif command == \"TU\" then\
  3570. pfx = -pfx\
  3571. pfz = -pfz\
  3572. end\
  3573. \
  3574. drawCanvas()\
  3575. drawInterface()\
  3576. end\
  3577. \
  3578. --[[A printing function that commands the printer to turn to face the desired direction, if it is not already doing so\
  3579. Params: desx:number = the normalized x direction to face\
  3580. desz:number = the normalized z direction to face\
  3581. Returns:nil\
  3582. ]]--\
  3583. local function turnToFace(desx,desz)\
  3584. if desx ~= 0 then\
  3585. if pfx ~= desx then\
  3586. local temppfx,_ = getLeft(pfx,pfz)\
  3587. if temppfx == desx then\
  3588. sendPC(\"TL\")\
  3589. elseif temppfx == -desx then\
  3590. sendPC(\"TR\")\
  3591. else\
  3592. sendPC(\"TU\")\
  3593. end\
  3594. end\
  3595. else\
  3596. print(\"on the z axis\")\
  3597. if pfz ~= desz then\
  3598. local _,temppfz = getLeft(pfx,pfz)\
  3599. if temppfz == desz then\
  3600. sendPC(\"TL\")\
  3601. elseif temppfz == -desz then\
  3602. sendPC(\"TR\")\
  3603. else\
  3604. sendPC(\"TU\")\
  3605. end\
  3606. end\
  3607. end\
  3608. end\
  3609. \
  3610. --[[Performs the print\
  3611. Params: nil\
  3612. Returns:nil\
  3613. ]]--\
  3614. local function performPrint()\
  3615. state = \"active print\"\
  3616. if layering == \"up\" then\
  3617. --An up layering starts our builder bot on the bottom left corner of our build\
  3618. px,py,pz = leflim, 0, botlim + 1\
  3619. pfx,pfz = 0,-1\
  3620. \
  3621. --We move him forward and up a bit from his original position.\
  3622. sendPC(\"FW\")\
  3623. sendPC(\"UP\")\
  3624. --For each layer that needs to be completed, we go up by one each time\
  3625. for layers=1,#frames do\
  3626. --We first decide if we're going forwards or back, depending on what side we're on\
  3627. local rowbot,rowtop,rowinc = nil,nil,nil\
  3628. if pz == botlim then\
  3629. rowbot,rowtop,rowinc = botlim,toplim,-1\
  3630. else\
  3631. rowbot,rowtop,rowinc = toplim,botlim,1\
  3632. end\
  3633. \
  3634. for rows = rowbot,rowtop,rowinc do\
  3635. --Then we decide if we're going left or right, depending on what side we're on\
  3636. local linebot,linetop,lineinc = nil,nil,nil\
  3637. if px == leflim then\
  3638. --Facing from the left side has to be easterly- it's changed here\
  3639. turnToFace(1,0)\
  3640. linebot,linetop,lineinc = leflim,riglim,1\
  3641. else\
  3642. --Facing from the right side has to be westerly- it's changed here\
  3643. turnToFace(-1,0)\
  3644. linebot,linetop,lineinc = riglim,leflim,-1\
  3645. end\
  3646. \
  3647. for lines = linebot,linetop,lineinc do\
  3648. --We move our turtle forward, placing the right material at each step\
  3649. local material = frames[py][pz][px]\
  3650. if material then\
  3651. material = math.log10(frames[py][pz][px])/math.log10(2) + 1\
  3652. sendPC(\"SS\", material)\
  3653. sendPC(\"PD\")\
  3654. end\
  3655. if lines ~= linetop then\
  3656. sendPC(\"FW\")\
  3657. end\
  3658. end\
  3659. \
  3660. --The printer then has to do a U-turn, depending on which way he's facing and\
  3661. --which way he needs to go\
  3662. local temppfx,temppfz = getLeft(pfx,pfz)\
  3663. if temppfz == rowinc and rows ~= rowtop then\
  3664. sendPC(\"TL\")\
  3665. sendPC(\"FW\")\
  3666. sendPC(\"TL\")\
  3667. elseif temppfz == -rowinc and rows ~= rowtop then\
  3668. sendPC(\"TR\")\
  3669. sendPC(\"FW\")\
  3670. sendPC(\"TR\")\
  3671. end\
  3672. end\
  3673. --Now at the end of a run he does a 180 and moves up to begin the next part of the print\
  3674. sendPC(\"TU\")\
  3675. if layers ~= #frames then\
  3676. sendPC(\"UP\")\
  3677. end\
  3678. end\
  3679. --All done- now we head back to where we started.\
  3680. if px ~= leflim then\
  3681. turnToFace(-1,0)\
  3682. while px ~= leflim do\
  3683. sendPC(\"FW\")\
  3684. end\
  3685. end\
  3686. if pz ~= botlim then\
  3687. turnToFace(0,-1)\
  3688. while pz ~= botlim do\
  3689. sendPC(\"BK\")\
  3690. end\
  3691. end\
  3692. turnToFace(0,-1)\
  3693. sendPC(\"BK\")\
  3694. while py > 0 do\
  3695. sendPC(\"DW\")\
  3696. end\
  3697. else\
  3698. --The front facing is at the top-left corner, facing south not north\
  3699. px,py,pz = leflim, botlim, 1\
  3700. pfx,pfz = 0,1\
  3701. --We move the printer to the last layer- he prints from the back forwards\
  3702. while pz < #frames do\
  3703. sendPC(\"FW\")\
  3704. end\
  3705. \
  3706. --For each layer in the frame we build our wall, the move back\
  3707. for layers = 1,#frames do\
  3708. --We first decide if we're going left or right based on our position\
  3709. local rowbot,rowtop,rowinc = nil,nil,nil\
  3710. if px == leflim then\
  3711. rowbot,rowtop,rowinc = leflim,riglim,1\
  3712. else\
  3713. rowbot,rowtop,rowinc = riglim,leflim,-1\
  3714. end\
  3715. \
  3716. for rows = rowbot,rowtop,rowinc do\
  3717. --Then we decide if we're going up or down, depending on our given altitude\
  3718. local linebot,linetop,lineinc = nil,nil,nil\
  3719. if py == botlim then\
  3720. linebot,linetop,lineinc = botlim,toplim,-1\
  3721. else\
  3722. linebot,linetop,lineinc = toplim,botlim,1\
  3723. end\
  3724. \
  3725. for lines = linebot,linetop,lineinc do\
  3726. --We move our turtle up/down, placing the right material at each step\
  3727. local material = frames[pz][py][px]\
  3728. if material then\
  3729. material = math.log10(frames[pz][py][px])/math.log10(2) + 1\
  3730. sendPC(\"SS\", material)\
  3731. sendPC(\"PF\")\
  3732. end\
  3733. if lines ~= linetop then\
  3734. if lineinc == 1 then sendPC(\"DW\")\
  3735. else sendPC(\"UP\") end\
  3736. end\
  3737. end\
  3738. \
  3739. if rows ~= rowtop then\
  3740. turnToFace(rowinc,0)\
  3741. sendPC(\"FW\")\
  3742. turnToFace(0,1)\
  3743. end\
  3744. end\
  3745. \
  3746. if layers ~= #frames then\
  3747. sendPC(\"TU\")\
  3748. sendPC(\"FW\")\
  3749. sendPC(\"TU\")\
  3750. end\
  3751. end\
  3752. --He's easy to reset\
  3753. while px ~= leflim do\
  3754. turnToFace(-1,0)\
  3755. sendPC(\"FW\")\
  3756. end\
  3757. turnToFace(0,1)\
  3758. end\
  3759. \
  3760. sendPC(\"DE\")\
  3761. \
  3762. displayConfirmDialogue(\"Print complete\", \"The 3D print was successful.\")\
  3763. end\
  3764. \
  3765. --[[ \
  3766. Section: Interface \
  3767. ]]--\
  3768. \
  3769. --[[Runs the printing interface. Allows users to find/select a printer, the style of printing to perform and to begin the operation\
  3770. Params: none\
  3771. Returns:boolean true if printing was started, false otherwse\
  3772. ]]--\
  3773. local function runPrintInterface()\
  3774. calculateMaterials()\
  3775. --There's nothing on canvas yet!\
  3776. if not botlim then\
  3777. displayConfirmDialogue(\"Cannot Print Empty Canvas\", \"There is nothing on canvas that \"..\
  3778. \"can be printed, and the operation cannot be completed.\")\
  3779. return false\
  3780. end\
  3781. --No printers nearby\
  3782. if not locatePrinters() then\
  3783. return false\
  3784. end\
  3785. \
  3786. layering = \"up\"\
  3787. requirementsDisplayed = false\
  3788. selectedPrinter = 1\
  3789. while true do\
  3790. drawCanvas()\
  3791. term.setBackgroundColour(colours.lightGrey)\
  3792. for i=1,10 do\
  3793. term.setCursorPos(1,i)\
  3794. term.clearLine()\
  3795. end\
  3796. drawInterface()\
  3797. term.setBackgroundColour(colours.lightGrey)\
  3798. term.setTextColour(colours.black)\
  3799. \
  3800. local msg = \"3D Printing\"\
  3801. term.setCursorPos(w/2-#msg/2 - 2, 1)\
  3802. term.write(msg)\
  3803. term.setBackgroundColour(colours.grey)\
  3804. term.setTextColour(colours.lightGrey)\
  3805. if(requirementsDisplayed) then\
  3806. msg = \"Count:\"\
  3807. else\
  3808. msg = \" Slot:\"\
  3809. end\
  3810. term.setCursorPos(w-3-#msg, 1)\
  3811. term.write(msg)\
  3812. term.setBackgroundColour(colours.lightGrey)\
  3813. term.setTextColour(colours.black)\
  3814. \
  3815. term.setCursorPos(7, 2)\
  3816. term.write(\"Layering\")\
  3817. drawPictureTable(layerUpIcon, 3, 3, colours.white)\
  3818. drawPictureTable(layerForwardIcon, 12, 3, colours.white)\
  3819. if layering == \"up\" then\
  3820. term.setBackgroundColour(colours.red)\
  3821. else\
  3822. term.setBackgroundColour(colours.lightGrey)\
  3823. end\
  3824. term.setCursorPos(3, 9)\
  3825. term.write(\"Upwards\")\
  3826. if layering == \"forward\" then\
  3827. term.setBackgroundColour(colours.red)\
  3828. else\
  3829. term.setBackgroundColour(colours.lightGrey)\
  3830. end\
  3831. term.setCursorPos(12, 9)\
  3832. term.write(\"Forward\")\
  3833. \
  3834. term.setBackgroundColour(colours.lightGrey)\
  3835. term.setTextColour(colours.black)\
  3836. term.setCursorPos(31, 2)\
  3837. term.write(\"Printer ID\")\
  3838. term.setCursorPos(33, 3)\
  3839. if #printerList > 1 then\
  3840. term.setBackgroundColour(colours.grey)\
  3841. term.setTextColour(colours.lightGrey)\
  3842. else\
  3843. term.setTextColour(colours.red)\
  3844. end\
  3845. term.write(\" \"..printerNames[selectedPrinter]..\" \")\
  3846. \
  3847. term.setBackgroundColour(colours.grey)\
  3848. term.setTextColour(colours.lightGrey)\
  3849. term.setCursorPos(25, 10)\
  3850. term.write(\" Cancel \")\
  3851. term.setCursorPos(40, 10)\
  3852. term.write(\" Print \")\
  3853. \
  3854. local id, p1, p2, p3 = os.pullEvent()\
  3855. \
  3856. if id == \"timer\" then\
  3857. updateTimer(p1)\
  3858. elseif id == \"mouse_click\" then\
  3859. --Layering Buttons\
  3860. if p2 >= 3 and p2 <= 9 and p3 >= 3 and p3 <= 9 then\
  3861. layering = \"up\"\
  3862. elseif p2 >= 12 and p2 <= 18 and p3 >= 3 and p3 <= 9 then\
  3863. layering = \"forward\"\
  3864. --Count/Slot\
  3865. elseif p2 >= w - #msg - 3 and p2 <= w - 3 and p3 == 1 then\
  3866. requirementsDisplayed = not requirementsDisplayed\
  3867. --Printer ID\
  3868. elseif p2 >= 33 and p2 <= 33 + #printerNames[selectedPrinter] and p3 == 3 and #printerList > 1 then\
  3869. local chosenName = displayDropDown(33, 3, printerNames)\
  3870. for i=1,#printerNames do\
  3871. if printerNames[i] == chosenName then\
  3872. selectedPrinter = i\
  3873. break;\
  3874. end\
  3875. end\
  3876. --Print and Cancel\
  3877. elseif p2 >= 25 and p2 <= 32 and p3 == 10 then\
  3878. break\
  3879. elseif p2 >= 40 and p2 <= 46 and p3 == 10 then\
  3880. rednet.send(printerList[selectedPrinter], \"$3DPRINT ACTIVATE\")\
  3881. ready = false\
  3882. while true do\
  3883. local id,msg = rsTimeReceive(10)\
  3884. \
  3885. if id == printerList[selectedPrinter] and msg == \"$3DPRINT ACTACK\" then\
  3886. ready = true\
  3887. break\
  3888. end\
  3889. end\
  3890. if ready then\
  3891. performPrint()\
  3892. break\
  3893. else\
  3894. displayConfirmDialogue(\"Printer Didn't Respond\", \"The printer didn't respond to the activation command. Check to see if it's online\")\
  3895. end\
  3896. end\
  3897. end\
  3898. end\
  3899. state = \"paint\"\
  3900. end\
  3901. \
  3902. --[[Performs a legacy save. When the dropdown menu is unavailable, it requests the user to save\
  3903. \009or exit using keyboard shortcuts rather than selecting a menu option from the dropdown.\
  3904. \009Pressing the control key again will cancel the save operation.\
  3905. \009Params: none\
  3906. \009Returns:string = the selection made\
  3907. ]]--\
  3908. local function performLegacySaveExit()\
  3909. \009local saveMsg = \"(S)ave/(E)xit?\"\
  3910. \009if w < #saveMsg then saveMsg = \"S/E?\" end\
  3911. \009\
  3912. \009term.setCursorPos(1,h)\
  3913. \009term.setBackgroundColour(colours.lightGrey)\
  3914. \009term.setTextColour(colours.grey)\
  3915. \009term.clearLine()\
  3916. \009term.write(saveMsg)\
  3917. \009\
  3918. \009while true do\
  3919. \009\009local id,val = os.pullEvent()\
  3920. \009\009if id == \"timer\" then updateTimer(val)\
  3921. \009\009elseif id == \"key\" then\
  3922. \009\009\009if val == keys.s then return \"save\" \
  3923. \009\009\009elseif val == keys.e then\
  3924. \009\009\009\009--Get rid of the extra event\
  3925. \009\009\009\009os.pullEvent(\"char\")\
  3926. \009\009\009\009return \"exit\"\
  3927. \009\009\009elseif val == keys.leftCtrl then return nil\
  3928. \009\009\009end\
  3929. \009\009end\
  3930. \009end\
  3931. end\
  3932. \
  3933. --[[This function changes the current paint program to another tool or mode, depending on user input. Handles\
  3934. any necessary changes in logic involved in that.\
  3935. Params: mode:string = the name of the mode to change to\
  3936. Returns:nil\
  3937. ]]--\
  3938. local function performSelection(mode)\
  3939. if not mode or mode == \"\" then return\
  3940. \
  3941. elseif mode == \"help\" and helpAvailable then\
  3942. drawHelpScreen()\
  3943. \
  3944. elseif mode == \"blueprint on\" then\
  3945. blueprint = true\
  3946. \009\009\009\009for i=1,#ddModes[2] do if ddModes[2][i] == \"blueprint on\" then\
  3947. \009\009\009\009\009ddModes[2][i] = \"blueprint off\"\
  3948. \009\009\009\009end end\
  3949. \
  3950. elseif mode == \"blueprint off\" then\
  3951. blueprint = false\
  3952. \009\009\009\009for i=1,#ddModes[2] do if ddModes[2][i] == \"blueprint off\" then\
  3953. \009\009\009\009\009ddModes[2][i] = \"blueprint on\"\
  3954. \009\009\009\009end end\
  3955. \
  3956. elseif mode == \"layers on\" then\
  3957. layerDisplay = true\
  3958. \009\009\009\009for i=1,#ddModes[2] do if ddModes[2][i] == \"layers on\" then\
  3959. \009\009\009\009\009ddModes[2][i] = \"layers off\"\
  3960. \009\009\009\009end end\
  3961. \
  3962. elseif mode == \"layers off\" then\
  3963. layerDisplay = false\
  3964. \009\009\009\009for i=1,#ddModes[2] do if ddModes[2][i] == \"layers off\" then\
  3965. \009\009\009\009\009ddModes[2][i] = \"layers on\"\
  3966. \009\009\009\009end end\
  3967. \
  3968. elseif mode == \"direction on\" then\
  3969. printDirection = true\
  3970. \009\009\009\009for i=1,#ddModes[2] do if ddModes[2][i] == \"direction on\" then\
  3971. \009\009\009\009\009ddModes[2][i] = \"direction off\"\
  3972. \009\009\009\009end end\
  3973. \
  3974. elseif mode == \"direction off\" then\
  3975. printDirection = false\
  3976. \009\009\009\009for i=1,#ddModes[2] do if ddModes[2][i] == \"direction off\" then\
  3977. \009\009\009\009\009ddModes[2][i] = \"direction on\"\
  3978. \009\009\009\009end end\
  3979. \009\009\
  3980. \009\009elseif mode == \"hide interface\" then\
  3981. \009\009\009\009interfaceHidden = true\
  3982. \009\009\009\
  3983. \009\009elseif mode == \"show interface\" then\
  3984. \009\009\009\009interfaceHidden = false\
  3985. \
  3986. elseif mode == \"go to\" then\
  3987. changeFrame()\
  3988. \
  3989. elseif mode == \"remove\" then\
  3990. removeFramesAfter(sFrame)\
  3991. \
  3992. elseif mode == \"play\" then\
  3993. playAnimation()\
  3994. \
  3995. elseif mode == \"copy\" then\
  3996. if selectrect and selectrect.x1 ~= selectrect.x2 then\
  3997. copyToBuffer(false)\
  3998. end\
  3999. \
  4000. elseif mode == \"cut\" then\
  4001. if selectrect and selectrect.x1 ~= selectrect.x2 then\
  4002. copyToBuffer(true)\
  4003. end\
  4004. \
  4005. elseif mode == \"paste\" then\
  4006. if selectrect and selectrect.x1 ~= selectrect.x2 then\
  4007. copyFromBuffer(false)\
  4008. end\
  4009. \
  4010. elseif mode == \"hide\" then\
  4011. selectrect = nil\
  4012. if state == \"select\" then state = \"corner select\" end\
  4013. \009\009\009 \
  4014. elseif mode == \"alpha to left\" then\
  4015. if lSel then alphaC = lSel end\
  4016. \
  4017. elseif mode == \"alpha to right\" then\
  4018. if rSel then alphaC = rSel end\
  4019. \
  4020. elseif mode == \"record\" then\
  4021. record = not record\
  4022. \
  4023. elseif mode == \"clear\" then\
  4024. if state==\"select\" then buffer = nil\
  4025. else clearImage() end\
  4026. \
  4027. elseif mode == \"select\" then\
  4028. if state==\"corner select\" or state==\"select\" then\
  4029. state = \"paint\"\
  4030. elseif selectrect and selectrect.x1 ~= selectrect.x2 then\
  4031. state = \"select\"\
  4032. else\
  4033. state = \"corner select\"\
  4034. end\
  4035. \
  4036. elseif mode == \"print\" then\
  4037. state = \"print\"\
  4038. runPrintInterface()\
  4039. state = \"paint\"\
  4040. \
  4041. elseif mode == \"save\" then\
  4042. if animated then saveNFA(sPath)\
  4043. elseif textEnabled then saveNFT(sPath)\
  4044. else saveNFP(sPath) end\
  4045. \
  4046. elseif mode == \"exit\" then\
  4047. isRunning = false\
  4048. \
  4049. elseif mode ~= state then state = mode\
  4050. else state = \"paint\"\
  4051. end\
  4052. end\
  4053. \
  4054. --[[The main function of the program, reads and handles all events and updates them accordingly. Mode changes,\
  4055. painting to the canvas and general selections are done here.\
  4056. Params: none\
  4057. Returns:nil\
  4058. ]]--\
  4059. local function handleEvents()\
  4060. recttimer = os.startTimer(0.5)\
  4061. while isRunning do\
  4062. drawCanvas()\
  4063. if not interfaceHidden then drawInterface() end\
  4064. \
  4065. if state == \"text\" then\
  4066. term.setCursorPos(textCurX - sx, textCurY - sy)\
  4067. term.setCursorBlink(true)\
  4068. end\
  4069. \
  4070. local id,p1,p2,p3 = os.pullEvent()\
  4071. term.setCursorBlink(false)\
  4072. if id==\"timer\" then\
  4073. updateTimer(p1)\
  4074. elseif (id==\"mouse_click\" or id==\"mouse_drag\") and not interfaceHidden then\
  4075. if p2 >=w-1 and p3 < #column+1 then\
  4076. \009\009\009\009\009\009\009\009local off = 0\
  4077. \009\009\009\009\009\009\009\009local cansel = true\
  4078. \009\009\009\009\009\009\009\009if h < #column + 2 then\
  4079. \009\009\009\009\009\009\009\009\009if p3 == 1 then \
  4080. \009\009\009\009\009\009\009\009\009\009if columnoffset > 0 then columnoffset = columnoffset-1 end\
  4081. \009\009\009\009\009\009\009\009\009\009cansel = false\
  4082. \009\009\009\009\009\009\009\009\009elseif p3 == h-2 then\
  4083. \009\009\009\009\009\009\009\009\009\009if columnoffset < #column-(h-4)+1 then columnoffset = columnoffset+1 end\
  4084. \009\009\009\009\009\009\009\009\009\009cansel = false\
  4085. \009\009\009\009\009\009\009\009\009else\
  4086. \009\009\009\009\009\009\009\009\009\009off = columnoffset - 1\
  4087. \009\009\009\009\009\009\009\009\009end\
  4088. \009\009\009\009\009\009\009\009end\
  4089. \009\009\009\009\009\009\009\009--This rather handily accounts for the nil case (p3+off=#column+1)\
  4090. \009\009\009\009\009\009\009\009if p1==1 and cansel then lSel = column[p3+off]\
  4091. elseif p1==2 and cansel then rSel = column[p3+off] end\
  4092. elseif p2 >=w-1 and p3==#column+1 then\
  4093. if p1==1 then lSel = nil\
  4094. else rSel = nil end\
  4095. elseif p2==w-1 and p3==h and animated then\
  4096. changeFrame(sFrame-1)\
  4097. elseif p2==w and p3==h and animated then\
  4098. changeFrame(sFrame+1)\
  4099. elseif p2 <= #ddModes.name + 2 and p3==h and mainAvailable then\
  4100. local sel = displayDropDown(1, h-1, ddModes)\
  4101. performSelection(sel)\
  4102. elseif p2 < w-1 and p3 <= h-1 then\
  4103. if state==\"pippette\" then\
  4104. if p1==1 then\
  4105. if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then\
  4106. lSel = frames[sFrame][p3+sy][p2+sx]\
  4107. end\
  4108. elseif p1==2 then\
  4109. if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then\
  4110. rSel = frames[sFrame][p3+sy][p2+sx]\
  4111. end\
  4112. end\
  4113. elseif state==\"move\" then\
  4114. updateImageLims(record)\
  4115. moveImage(p2,p3)\
  4116. elseif state==\"flood\" then\
  4117. if p1 == 1 and lSel and frames[sFrame][p3+sy] then\
  4118. floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],lSel)\
  4119. elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then\
  4120. floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],rSel)\
  4121. end\
  4122. elseif state==\"corner select\" then\
  4123. if not selectrect then\
  4124. selectrect = { x1=p2+sx, x2=p2+sx, y1=p3+sy, y2=p3+sy }\
  4125. elseif selectrect.x1 ~= p2+sx and selectrect.y1 ~= p3+sy then\
  4126. if p2+sx<selectrect.x1 then selectrect.x1 = p2+sx\
  4127. else selectrect.x2 = p2+sx end\
  4128. \
  4129. if p3+sy<selectrect.y1 then selectrect.y1 = p3+sy\
  4130. else selectrect.y2 = p3+sy end\
  4131. \
  4132. state = \"select\"\
  4133. end\
  4134. elseif state==\"textpaint\" then\
  4135. local paintCol = lSel\
  4136. if p1 == 2 then paintCol = rSel end\
  4137. if frames[sFrame].textcol[p3+sy] then\
  4138. frames[sFrame].textcol[p3+sy][p2+sx] = paintCol\
  4139. end\
  4140. elseif state==\"text\" then\
  4141. textCurX = p2 + sx\
  4142. textCurY = p3 + sy\
  4143. elseif state==\"select\" then\
  4144. if p1 == 1 then\
  4145. local swidth = selectrect.x2 - selectrect.x1\
  4146. local sheight = selectrect.y2 - selectrect.y1\
  4147. \
  4148. selectrect.x1 = p2 + sx\
  4149. selectrect.y1 = p3 + sy\
  4150. selectrect.x2 = p2 + swidth + sx\
  4151. selectrect.y2 = p3 + sheight + sy\
  4152. elseif p1 == 2 and p2 < w-2 and p3 < h-1 and boxdropAvailable then\
  4153. inMenu = true\
  4154. local sel = displayDropDown(p2, p3, srModes)\
  4155. inMenu = false\
  4156. performSelection(sel)\
  4157. end\
  4158. else\
  4159. local f,l = sFrame,sFrame\
  4160. if record then f,l = 1,framecount end\
  4161. local bwidth = 0\
  4162. if state == \"brush\" then bwidth = brushsize-1 end\
  4163. \
  4164. for i=f,l do\
  4165. for x = math.max(1,p2+sx-bwidth),p2+sx+bwidth do\
  4166. for y = math.max(1,p3+sy-bwidth), p3+sy+bwidth do\
  4167. if math.abs(x - (p2+sx)) + math.abs(y - (p3+sy)) <= bwidth then\
  4168. if not frames[i][y] then frames[i][y] = {} end\
  4169. if p1==1 then frames[i][y][x] = lSel\
  4170. else frames[i][y][x] = rSel end\
  4171. \
  4172. if textEnabled then\
  4173. if not frames[i].text[y] then frames[i].text[y] = { } end\
  4174. if not frames[i].textcol[y] then frames[i].textcol[y] = { } end\
  4175. end\
  4176. end\
  4177. end\
  4178. end\
  4179. end\
  4180. end\
  4181. end\
  4182. elseif id==\"char\" then\
  4183. if state==\"text\" then\
  4184. if not frames[sFrame][textCurY] then frames[sFrame][textCurY] = { } end\
  4185. if not frames[sFrame].text[textCurY] then frames[sFrame].text[textCurY] = { } end\
  4186. if not frames[sFrame].textcol[textCurY] then frames[sFrame].textcol[textCurY] = { } end\
  4187. \
  4188. if rSel then frames[sFrame][textCurY][textCurX] = rSel end\
  4189. if lSel then\
  4190. frames[sFrame].text[textCurY][textCurX] = p1\
  4191. frames[sFrame].textcol[textCurY][textCurX] = lSel\
  4192. else\
  4193. frames[sFrame].text[textCurY][textCurX] = \" \"\
  4194. frames[sFrame].textcol[textCurY][textCurX] = rSel\
  4195. end\
  4196. \
  4197. textCurX = textCurX+1\
  4198. if textCurX > w + sx - 2 then sx = textCurX - w + 2 end\
  4199. elseif tonumber(p1) then\
  4200. if state==\"brush\" and tonumber(p1) > 1 then\
  4201. brushsize = tonumber(p1)\
  4202. elseif animated and tonumber(p1) > 0 then\
  4203. changeFrame(tonumber(p1))\
  4204. end\
  4205. end\
  4206. elseif id==\"key\" then\
  4207. \009\009\009\009\009\009--All standard interface methods are locked when the interface is hidden\
  4208. \009\009\009\009\009\009if interfaceHidden then\
  4209. \009\009\009\009\009\009\009if p1==keys.grave then\
  4210. \009\009\009\009\009\009\009\009performSelection(\"show interface\") \
  4211. \009\009\009\009\009\009\009end\
  4212. --Text needs special handlers (all other keyboard shortcuts are of course reserved for typing)\
  4213. elseif state==\"text\" then\
  4214. if p1==keys.backspace and textCurX > 1 then\
  4215. textCurX = textCurX-1\
  4216. if frames[sFrame].text[textCurY] then\
  4217. frames[sFrame].text[textCurY][textCurX] = nil\
  4218. frames[sFrame].textcol[textCurY][textCurX] = nil\
  4219. end\
  4220. if textCurX < sx then sx = textCurX end\
  4221. elseif p1==keys.left and textCurX > 1 then\
  4222. textCurX = textCurX-1\
  4223. if textCurX-1 < sx then sx = textCurX-1 end\
  4224. elseif p1==keys.right then\
  4225. textCurX = textCurX+1\
  4226. if textCurX > w + sx - 2 then sx = textCurX - w + 2 end\
  4227. elseif p1==keys.up and textCurY > 1 then\
  4228. textCurY = textCurY-1\
  4229. if textCurY-1 < sy then sy = textCurY-1 end\
  4230. elseif p1==keys.down then\
  4231. textCurY = textCurY+1\
  4232. if textCurY > h + sy - 1 then sy = textCurY - h + 1 end\
  4233. end\
  4234. \
  4235. elseif p1==keys.leftCtrl then\
  4236. local sel = nil\
  4237. \009\009\009\009\009\009\009\009if mainAvailable then \
  4238. \009\009\009\009\009\009\009\009\009sel = displayDropDown(1, h-1, ddModes[#ddModes])\
  4239. \009\009\009\009\009\009\009\009else sel = performLegacySaveExit() end\
  4240. performSelection(sel)\
  4241. elseif p1==keys.leftAlt then\
  4242. local sel = displayDropDown(1, h-1, ddModes[1])\
  4243. performSelection(sel)\
  4244. elseif p1==keys.h then\
  4245. performSelection(\"help\")\
  4246. elseif p1==keys.x then\
  4247. performSelection(\"cut\")\
  4248. elseif p1==keys.c then\
  4249. performSelection(\"copy\")\
  4250. elseif p1==keys.v then\
  4251. performSelection(\"paste\")\
  4252. elseif p1==keys.z then\
  4253. performSelection(\"clear\")\
  4254. elseif p1==keys.s then\
  4255. performSelection(\"select\")\
  4256. elseif p1==keys.tab then\
  4257. performSelection(\"hide\")\
  4258. elseif p1==keys.q then\
  4259. performSelection(\"alpha to left\")\
  4260. elseif p1==keys.w then\
  4261. performSelection(\"alpha to right\")\
  4262. elseif p1==keys.f then\
  4263. performSelection(\"flood\")\
  4264. elseif p1==keys.b then\
  4265. performSelection(\"brush\")\
  4266. elseif p1==keys.m then\
  4267. performSelection(\"move\")\
  4268. elseif p1==keys.backslash and animated then\
  4269. performSelection(\"record\")\
  4270. elseif p1==keys.p then\
  4271. performSelection(\"pippette\")\
  4272. elseif p1==keys.g and animated then\
  4273. performSelection(\"go to\")\
  4274. \009\009\009\009\009\009elseif p1==keys.grave then \
  4275. \009\009\009\009\009\009\009\009performSelection(\"hide interface\")\
  4276. elseif p1==keys.period and animated then\
  4277. changeFrame(sFrame+1)\
  4278. elseif p1==keys.comma and animated then\
  4279. changeFrame(sFrame-1)\
  4280. elseif p1==keys.r and animated then\
  4281. performSelection(\"remove\")\
  4282. elseif p1==keys.space and animated then\
  4283. performSelection(\"play\")\
  4284. elseif p1==keys.t and textEnabled then\
  4285. performSelection(\"text\")\
  4286. sleep(0.01)\
  4287. elseif p1==keys.y and textEnabled then\
  4288. performSelection(\"textpaint\")\
  4289. elseif p1==keys.left then\
  4290. if state == \"move\" and toplim then\
  4291. updateImageLims(record)\
  4292. if toplim and leflim then\
  4293. moveImage(leflim-1,toplim)\
  4294. end\
  4295. elseif state==\"select\" and selectrect.x1 > 1 then\
  4296. selectrect.x1 = selectrect.x1-1\
  4297. selectrect.x2 = selectrect.x2-1\
  4298. elseif sx > 0 then sx=sx-1 end\
  4299. elseif p1==keys.right then\
  4300. if state == \"move\" then\
  4301. updateImageLims(record)\
  4302. if toplim and leflim then\
  4303. moveImage(leflim+1,toplim)\
  4304. end\
  4305. elseif state==\"select\" then\
  4306. selectrect.x1 = selectrect.x1+1\
  4307. selectrect.x2 = selectrect.x2+1\
  4308. else sx=sx+1 end\
  4309. elseif p1==keys.up then\
  4310. if state == \"move\" then\
  4311. updateImageLims(record)\
  4312. if toplim and leflim then\
  4313. moveImage(leflim,toplim-1)\
  4314. end\
  4315. elseif state==\"select\" and selectrect.y1 > 1 then\
  4316. selectrect.y1 = selectrect.y1-1\
  4317. selectrect.y2 = selectrect.y2-1\
  4318. elseif sy > 0 then sy=sy-1 end\
  4319. elseif p1==keys.down then\
  4320. if state == \"move\" then\
  4321. updateImageLims(record)\
  4322. if toplim and leflim then\
  4323. moveImage(leflim,toplim+1)\
  4324. end\
  4325. elseif state==\"select\" then\
  4326. selectrect.y1 = selectrect.y1+1\
  4327. selectrect.y2 = selectrect.y2+1\
  4328. else sy=sy+1 end\
  4329. end\
  4330. end\
  4331. end\
  4332. end\
  4333. \
  4334. --[[\
  4335. Section: Main \
  4336. ]]--\
  4337. \
  4338. --The first thing done is deciding what features we actually have, given the screen size\
  4339. if w < 7 or h < 4 then\
  4340. \009--NPaintPro simply doesn't work at certain configurations\
  4341. \009shell.run(\"clear\")\
  4342. \009print(\"Screen too small\")\
  4343. \009os.pullEvent(\"key\")\
  4344. \009return\
  4345. end\
  4346. --And reduces the number of features in others.\
  4347. determineAvailableServices()\
  4348. \
  4349. --There is no b&w support for NPP.\
  4350. if not term.isColour() then\
  4351. \009shell.run(\"clear\")\
  4352. \009print(\"NPaintPro\\nBy NitrogenFingers\\n\\nNPaintPro can only be run on advanced \"..\
  4353. \009\"computers. Please reinstall on an advanced computer.\")\
  4354. return\
  4355. end\
  4356. \
  4357. --Taken almost directly from edit (for consistency)\
  4358. local tArgs = {...}\
  4359. \
  4360. --Command line options can appear before the file path to specify the file format\
  4361. local ca = 1\
  4362. while ca <= #tArgs do\
  4363. \009if tArgs[ca] == \"-a\" then animated = true\
  4364. \009elseif tArgs[ca] == \"-t\" then textEnabled = true\
  4365. \009elseif tArgs[ca] == \"-d\" then interfaceHidden = true\
  4366. \009elseif string.sub(tArgs[ca], 1, 1) == \"-\" then\
  4367. \009\009print(\"Unrecognized option: \"..tArgs[ca])\
  4368. \009\009return\
  4369. \009else break end\
  4370. \009ca = ca + 1\
  4371. end\
  4372. \
  4373. --Presently, animations and text files are not supported\
  4374. if animated and textEnabled then\
  4375. print(\"No support for animated text files- cannot have both -a and -t\")\
  4376. \009return\
  4377. end\
  4378. \
  4379. --Filepaths must be added if the screen is too small\
  4380. if #tArgs < ca then\
  4381. \009if not filemakerAvailable then\
  4382. \009\009print(\"Usage: npaintpro [-a,-t,-d] <path>\")\
  4383. \009\009return\
  4384. \009else\
  4385. \009\009--Otherwise do the logo draw early, to determine the file.\
  4386. \009\009drawLogo()\
  4387. \009\009if not runFileMaker() then return end\
  4388. \009end\
  4389. else\
  4390. \009if not interfaceHidden then drawLogo() end\
  4391. \009sPath = shell.resolve(tArgs[ca])\
  4392. end\
  4393. \
  4394. if fs.exists(sPath) then\
  4395. if fs.isDir(sPath) then\
  4396. print(\"Cannot edit a directory.\")\
  4397. return\
  4398. elseif string.find(sPath, \".nfp\") ~= #sPath-3 and string.find(sPath, \".nfa\") ~= #sPath-3 and\
  4399. string.find(sPath, \".nft\") ~= #sPath-3 then\
  4400. print(\"Can only edit .nfp, .nft and .nfa files:\",string.find(sPath, \".nfp\"),#sPath-3)\
  4401. return\
  4402. end\
  4403. \
  4404. if string.find(sPath, \".nfa\") == #sPath-3 then\
  4405. animated = true\
  4406. end\
  4407. \
  4408. if string.find(sPath, \".nft\") == #sPath-3 then\
  4409. textEnabled = true\
  4410. end \
  4411. \
  4412. if string.find(sPath, \".nfp\") == #sPath-3 and animated then\
  4413. print(\"Convert to nfa? Y/N\")\
  4414. if string.find(string.lower(io.read()), \"y\") then\
  4415. local nsPath = string.sub(sPath, 1, #sPath-1)..\"a\"\
  4416. fs.move(sPath, nsPath)\
  4417. sPath = nsPath\
  4418. else\
  4419. animated = false\
  4420. end\
  4421. end\
  4422. \
  4423. --Again this is possible, I just haven't done it. Maybe I will?\
  4424. if textEnabled and (string.find(sPath, \".nfp\") == #sPath-3 or string.find(sPath, \".nfa\") == #sPath-3) then\
  4425. print(\"Cannot convert to nft\")\
  4426. end\
  4427. else\
  4428. if not animated and not textEnabled and string.find(sPath, \".nfp\") ~= #sPath-3 then\
  4429. sPath = sPath..\".nfp\"\
  4430. elseif animated and string.find(sPath, \".nfa\") ~= #sPath-3 then\
  4431. sPath = sPath..\".nfa\"\
  4432. elseif textEnabled and string.find(sPath, \".nft\") ~= #sPath-3 then\
  4433. sPath = sPath..\".nft\"\
  4434. end\
  4435. end\
  4436. \
  4437. init()\
  4438. handleEvents()\
  4439. \
  4440. term.setBackgroundColour(colours.black)\
  4441. shell.run(\"clear\")",
  4442. "7777777777777777777777777\
  4443. 7ccccccccccccccccccccccc7\
  4444. 7ccccccccccccccccccccccc7\
  4445. 7ccccccccccccccccccccccc7\
  4446. 7ccccccccccccccccccccccc7\
  4447. 7ccccccccccccccccccccccc7\
  4448. 7ccccccccccccccccccccccc7\
  4449. 7ccccccccccccccccccccccc7\
  4450. 7777777777777777777777777",
  4451. "{\
  4452. blocksY = {\
  4453. 9,\
  4454. 9,\
  4455. 9,\
  4456. 9,\
  4457. 9,\
  4458. 9,\
  4459. 9,\
  4460. 9,\
  4461. 9,\
  4462. 8,\
  4463. 7,\
  4464. 5,\
  4465. 6,\
  4466. 4,\
  4467. 3,\
  4468. 2,\
  4469. 1,\
  4470. 1,\
  4471. 1,\
  4472. 1,\
  4473. 1,\
  4474. 1,\
  4475. 1,\
  4476. 1,\
  4477. 1,\
  4478. 1,\
  4479. 1,\
  4480. 1,\
  4481. 1,\
  4482. 9,\
  4483. 9,\
  4484. 9,\
  4485. 9,\
  4486. 9,\
  4487. 9,\
  4488. 9,\
  4489. 9,\
  4490. 9,\
  4491. 9,\
  4492. 9,\
  4493. 9,\
  4494. 9,\
  4495. 9,\
  4496. 9,\
  4497. 9,\
  4498. 9,\
  4499. 8,\
  4500. 7,\
  4501. 6,\
  4502. 5,\
  4503. 3,\
  4504. 4,\
  4505. 2,\
  4506. 1,\
  4507. 1,\
  4508. 1,\
  4509. 1,\
  4510. 1,\
  4511. 1,\
  4512. 1,\
  4513. 1,\
  4514. 1,\
  4515. 1,\
  4516. 1,\
  4517. 1,\
  4518. },\
  4519. blocksX = {\
  4520. 1,\
  4521. 2,\
  4522. 3,\
  4523. 4,\
  4524. 6,\
  4525. 5,\
  4526. 7,\
  4527. 9,\
  4528. 8,\
  4529. 1,\
  4530. 1,\
  4531. 1,\
  4532. 1,\
  4533. 1,\
  4534. 1,\
  4535. 1,\
  4536. 1,\
  4537. 2,\
  4538. 3,\
  4539. 4,\
  4540. 6,\
  4541. 7,\
  4542. 5,\
  4543. 8,\
  4544. 9,\
  4545. 11,\
  4546. 12,\
  4547. 10,\
  4548. 13,\
  4549. 10,\
  4550. 11,\
  4551. 13,\
  4552. 12,\
  4553. 14,\
  4554. 16,\
  4555. 15,\
  4556. 17,\
  4557. 18,\
  4558. 20,\
  4559. 21,\
  4560. 19,\
  4561. 22,\
  4562. 24,\
  4563. 25,\
  4564. 22,\
  4565. 23,\
  4566. 25,\
  4567. 25,\
  4568. 25,\
  4569. 25,\
  4570. 25,\
  4571. 25,\
  4572. 25,\
  4573. 25,\
  4574. 24,\
  4575. 23,\
  4576. 22,\
  4577. 21,\
  4578. 20,\
  4579. 19,\
  4580. 18,\
  4581. 17,\
  4582. 16,\
  4583. 15,\
  4584. 14,\
  4585. },\
  4586. doorsX = {},\
  4587. spawnY = 1,\
  4588. spawnX = 1,\
  4589. laddersX = {\
  4590. 7,\
  4591. },\
  4592. doorsY = {},\
  4593. laddersY = {\
  4594. 8,\
  4595. },\
  4596. ladderDestination = {\
  4597. \"house2\",\
  4598. },\
  4599. }",
  4600. "--Editor (yaay make your own levels based on this \"engine\")\
  4601. --Again, written by me c:\
  4602. --(I know, I'm shit at programming but hey why not C:)\
  4603. \
  4604. --Variablen\
  4605. _ver = 0.1\
  4606. _verstr = \"0.1\"\
  4607. pfad = \"\"\
  4608. \
  4609. lvlData = {\
  4610. \009spawnPosX=\"1\",\
  4611. \009spawnPosY=\"1\",\
  4612. \009blocksX = {\
  4613. \
  4614. \009},\
  4615. \009blocksY = {\
  4616. \
  4617. \009}\
  4618. }\
  4619. \
  4620. --Funktionen\
  4621. function clear(bg, fg)\
  4622. \009term.setCursorPos(1,1)\
  4623. \009term.setBackgroundColor(bg)\
  4624. \009term.setTextColor(fg)\
  4625. \009term.clear()\
  4626. end\
  4627. \
  4628. function menu()\
  4629. \009clear(colors.black, colors.white)\
  4630. \009term.setBackgroundColor(colors.lime)\
  4631. \009term.setCursorPos(25, 6)\
  4632. \009term.write(\"NEW\")\
  4633. \009term.setCursorPos(24, 8)\
  4634. \009term.write(\"LOAD\")\
  4635. \009term.setCursorPos(24, 10)\
  4636. \009term.write(\"EXIT\")\
  4637. \009menu = true\
  4638. \009while menu do\
  4639. \009\009local event, button, x, y = os.pullEventRaw(\"mouse_click\")\
  4640. \009\009if button == 1 and x >= 25 and x <= 27 and y == 6 then\
  4641. \009\009\009menu = false\
  4642. \009\009\009menu2()\
  4643. \009\009end\
  4644. \009end\
  4645. end\
  4646. \
  4647. function menu2()\
  4648. \009clear(colors.black, colors.white)\
  4649. \009oldTerm = term.native()\
  4650. \009local graywindow = window.create(oldTerm, 15, 5, 20, 5)\
  4651. \009term.redirect(graywindow)\
  4652. \009term.setBackgroundColor(colors.lightGray)\
  4653. \009term.setCursorPos(1,1)\
  4654. \009term.clear()\
  4655. \009local textBox = window.create(term.current(), 2, 2, 18, 1)\
  4656. \009textBox.setBackgroundColor(colors.gray)\
  4657. \009textBox.setTextColor(colors.lime)\
  4658. \009textBox.clear()\
  4659. \009textBox.write(\"Enter Name/Desti..\")\
  4660. \009term.setBackgroundColor(colors.gray)\
  4661. \009term.setTextColor(colors.white)\
  4662. \009term.setCursorPos(2, 4)\
  4663. \009term.write(\"New\")\
  4664. \009term.setCursorPos(16, 4)\
  4665. \009term.write(\"Load\")\
  4666. \009menu = true\
  4667. \009while menu do\
  4668. \009\009local event, button, x, y = os.pullEvent(\"mouse_click\")\
  4669. \009\009if button == 1 and x >= 16 and x <= 34 and y == 6 then\
  4670. \009\009\009term.redirect(textBox)\
  4671. \009\009\009term.clear()\
  4672. \009\009\009term.setCursorPos(1,1)\
  4673. \009\009\009local eingabe = read()\
  4674. \009\009\009pfad = eingabe\
  4675. \009\009\009term.setCursorPos(1,1)\
  4676. \009\009\009term.clear()\
  4677. \009\009\009term.write(eingabe)\
  4678. \009\009\009term.redirect(graywindow)\
  4679. \009\009elseif button == 1 and x >= 16 and x <= 18 and y == 8 then\
  4680. \009\009\009if fs.exists(pfad..\".lvl\") then\
  4681. \009\009\009\009textBox.setCursorPos(1,1)\
  4682. \009\009\009\009textBox.clear()\
  4683. \009\009\009\009textBox.setTextColor(colors.red)\
  4684. \009\009\009\009textBox.write(\"Already exists.\")\
  4685. \009\009\009\009textBox.setTextColor(colors.lime)\
  4686. \009\009\009elseif pfad == \"\" or pfad == nil then\
  4687. \009\009\009\009textBox.setCursorPos(1,1)\
  4688. \009\009\009\009textBox.clear()\
  4689. \009\009\009\009textBox.setTextColor(colors.red)\
  4690. \009\009\009\009textBox.write(\"Please fill in.\")\
  4691. \009\009\009\009textBox.setTextColor(colors.lime)\
  4692. \009\009\009else\
  4693. \009\009\009\009term.redirect(oldTerm)\
  4694. \009\009\009\009term.setCursorPos(1,1)\
  4695. \009\009\009\009clear(colors.black, colors.white)\
  4696. \009\009\009\009menu = false\
  4697. \009\009\009\009print(\"Please draw your LevelDESIGN.\")\
  4698. \009\009\009\009print(\"This will be that, what you see when playing the level.\")\
  4699. \009\009\009\009sleep(3)\
  4700. \009\009\009\009shell.run(\"paint \"..pfad..\".lvl\")\
  4701. \009\009\009\009\
  4702. \009\009\009\009editor()\
  4703. \009\009\009end\
  4704. \009\009elseif button == 1 and x >= 30 and x <= 34 and y == 8 then\
  4705. \009\009\009if fs.exists(pfad..\".lvl\") and fs.exists(pfad..\".lvlDat\") then\
  4706. \009\009\009\009term.redirect(oldTerm)\
  4707. \009\009\009\009menu = false\
  4708. \009\009\009\009editor(\"true\")\
  4709. \009\009\009elseif fs.exists(pfad..\".lvl\") then\
  4710. \009\009\009\009term.redirect(oldTerm)\
  4711. \009\009\009\009menu = false\
  4712. \009\009\009\009editor(\"false\")\
  4713. \009\009\009else\
  4714. \009\009\009\009textBox.setCursorPos(1,1)\
  4715. \009\009\009\009textBox.clear()\
  4716. \009\009\009\009textBox.setTextColor(colors.red)\
  4717. \009\009\009\009textBox.write(\"Doesn't exist.\")\
  4718. \009\009\009\009textBox.setTextColor(colors.lime)\
  4719. \009\009\009end\
  4720. \009\009end\
  4721. \009end\
  4722. \
  4723. end\
  4724. \
  4725. function loadDat()\
  4726. \009local file = fs.open(pfad..\".lvlDat\",\"r\")\
  4727. \009local inhalt = file.readAll()\
  4728. \009lvlData = textutils.unserialize(inhalt)\
  4729. \009file.close()\
  4730. end\
  4731. \
  4732. function editor(loadData)\
  4733. \009clear(colors.black, colors.white)\
  4734. \009lvl = paintutils.loadImage(pfad..\".lvl\")\
  4735. \009paintutils.drawImage(lvl, 1, 1)\
  4736. \009if loadData == \"true\" then\
  4737. \009\009loadDat()\
  4738. \009\009reloadMap()\
  4739. \009end\
  4740. \009term.setCursorPos(1,19)\
  4741. \009term.setBackgroundColor(colors.lightGray)\
  4742. \009term.clearLine()\
  4743. \009term.setBackgroundColor(colors.lime)\
  4744. \009term.write(\" Block \")\
  4745. \009term.setBackgroundColor(colors.lightGray)\
  4746. \009term.write(\" \")\
  4747. \009term.setBackgroundColor(colors.lime)\
  4748. \009term.write(\" Spawn \")\
  4749. \009term.setBackgroundColor(colors.lightGray)\
  4750. \009term.write(\" \")\
  4751. \009term.setBackgroundColor(colors.lime)\
  4752. \009term.write(\" Remove \")\
  4753. \009editing = true\
  4754. \009while editing do\
  4755. \009\009local event, button, x, y = os.pullEventRaw()\
  4756. \009\009if event == \"mouse_click\" and button == 1 and x >= 1 and x <= 7 and y == 19 then\
  4757. \009\009\009currentBlock = \"block\"\
  4758. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 9 and x <= 15 and y == 19 then\
  4759. \009\009\009currentBlock = \"spawn\"\
  4760. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 17 and x <= 24 and y == 19 then\
  4761. \009\009\009currentBlock = \"remove\"\
  4762. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 1 and x <= 51 and y >= 1 and y <= 18 then\
  4763. \009\009\009if currentBlock == \"block\" then\
  4764. \009\009\009\009term.setCursorPos(x, y)\
  4765. \009\009\009\009term.setBackgroundColor(colors.brown)\
  4766. \009\009\009\009term.setTextColor(colors.white)\
  4767. \009\009\009\009term.write(\"B\")\
  4768. \009\009\009\009local x = tostring(x)\
  4769. \009\009\009\009local y = tostring(y)\
  4770. \009\009\009\009table.insert(lvlData.blocksX, x)\
  4771. \009\009\009\009table.insert(lvlData.blocksY, y)\
  4772. \009\009\009\009reloadMap()\
  4773. \009\009\009elseif currentBlock == \"spawn\" then\
  4774. \009\009\009\009term.setCursorPos(x, y)\
  4775. \009\009\009\009term.setBackgroundColor(colors.blue)\
  4776. \009\009\009\009term.setTextColor(colors.white)\
  4777. \009\009\009\009term.write(\"S\")\
  4778. \009\009\009\009local x = tostring(x)\
  4779. \009\009\009\009local y = tostring(y)\
  4780. \009\009\009\009lvlData.spawnPosX = x\
  4781. \009\009\009\009lvlData.spawnPosY = y\
  4782. \009\009\009\009reloadMap()\
  4783. \009\009\009elseif currentBlock == \"remove\" then\
  4784. \009\009\009\009for _, block in ipairs(lvlData.blocksX) do\
  4785. \009\009\009\009\009local blockY = tonumber(lvlData.blocksY[_])\
  4786. \009\009\009\009\009local block = tonumber(block)\
  4787. \009\009\009\009\009if x == block and y == blockY then\
  4788. \009\009\009\009\009\009lvlData.blocksX[_] = nil\
  4789. \009\009\009\009\009\009lvlData.blocksY[_] = nil\
  4790. \009\009\009\009\009end\
  4791. \009\009\009\009end\
  4792. \009\009\009\009if x == lvlData.spawnPosX and y == lvlData.spawnPosY then\
  4793. \009\009\009\009\009lvlData.spawnPosX = \"1\"\
  4794. \009\009\009\009\009lvlData.spawnPosY = \"1\"\
  4795. \009\009\009\009end\
  4796. \009\009\009\009reloadMap()\
  4797. \009\009\009end\
  4798. \009\009elseif event == \"key\" and button == keys.s then\
  4799. \009\009\009local file = fs.open(pfad..\".lvlDat\",\"w\")\
  4800. \009\009\009local lvlData = textutils.serialize(lvlData)\
  4801. \009\009\009file.write(lvlData)\
  4802. \009\009\009file.close()\
  4803. \009\009\009clear(colors.black, colors.white)\
  4804. \
  4805. \009\009\009editing = false\
  4806. \009\009\009break\
  4807. \009\009end\
  4808. \
  4809. \009end\
  4810. end\
  4811. \
  4812. function reloadMap()\
  4813. \009clear(colors.black, colors.white)\
  4814. \009term.setCursorPos(1,19)\
  4815. \009term.setBackgroundColor(colors.lightGray)\
  4816. \009term.clearLine()\
  4817. \009term.setBackgroundColor(colors.lime)\
  4818. \009term.write(\" Block \")\
  4819. \009term.setBackgroundColor(colors.lightGray)\
  4820. \009term.write(\" \")\
  4821. \009term.setBackgroundColor(colors.lime)\
  4822. \009term.write(\" Spawn \")\
  4823. \009term.setBackgroundColor(colors.lightGray)\
  4824. \009term.write(\" \")\
  4825. \009term.setBackgroundColor(colors.lime)\
  4826. \009term.write(\" Remove \")\
  4827. \009term.setCursorPos(1,1)\
  4828. \009paintutils.drawImage(lvl, 1, 1)\
  4829. \009for _, block in ipairs(lvlData.blocksX) do\
  4830. \009\009local blockY = tonumber(lvlData.blocksY[_])\
  4831. \009\009local block = tonumber(block)\
  4832. \009\009term.setCursorPos(block, blockY)\
  4833. \009\009term.setBackgroundColor(colors.brown)\
  4834. \009\009term.setTextColor(colors.white)\
  4835. \009\009term.write(\"B\")\
  4836. \009end\
  4837. \009local sX = tonumber(lvlData.spawnPosX)\
  4838. \009local sY = tonumber(lvlData.spawnPosY)\
  4839. \009term.setCursorPos(sX, sY)\
  4840. \009term.setBackgroundColor(colors.blue)\
  4841. \009term.setTextColor(colors.white)\
  4842. \009term.write(\"S\")\
  4843. end\
  4844. \
  4845. \
  4846. \
  4847. --Code\
  4848. menu2()",
  4849. "7777777777777777777777777\
  4850. 7ccccccccccccccccccccccc7\
  4851. 7ccccccccccccccccccccccc7\
  4852. 7ccccccccccccccccccccccc7\
  4853. 7ccccccccccccccccccccccc7\
  4854. 7ccccccccccccccccccccccc7\
  4855. 7ccccccccccccccccccccccc7\
  4856. 7ccccccccccccccccccccccc7\
  4857. 7777777777777777777777777",
  4858. "{\
  4859. blocksY = {\
  4860. 9,\
  4861. 9,\
  4862. 9,\
  4863. 9,\
  4864. 9,\
  4865. 9,\
  4866. 9,\
  4867. 9,\
  4868. 9,\
  4869. 9,\
  4870. 9,\
  4871. 9,\
  4872. 9,\
  4873. 9,\
  4874. 9,\
  4875. 9,\
  4876. 9,\
  4877. 9,\
  4878. 9,\
  4879. 9,\
  4880. 9,\
  4881. 9,\
  4882. 9,\
  4883. 9,\
  4884. 9,\
  4885. 8,\
  4886. 7,\
  4887. 6,\
  4888. 5,\
  4889. 4,\
  4890. 3,\
  4891. 2,\
  4892. 1,\
  4893. 1,\
  4894. 1,\
  4895. 1,\
  4896. 1,\
  4897. 1,\
  4898. 1,\
  4899. 1,\
  4900. 1,\
  4901. 1,\
  4902. 1,\
  4903. 1,\
  4904. 1,\
  4905. 1,\
  4906. 1,\
  4907. 1,\
  4908. 1,\
  4909. 1,\
  4910. 1,\
  4911. 1,\
  4912. 1,\
  4913. 1,\
  4914. 1,\
  4915. 1,\
  4916. 1,\
  4917. 2,\
  4918. 3,\
  4919. 4,\
  4920. 5,\
  4921. 6,\
  4922. 8,\
  4923. 7,\
  4924. },\
  4925. blocksX = {\
  4926. 1,\
  4927. 2,\
  4928. 3,\
  4929. 4,\
  4930. 5,\
  4931. 6,\
  4932. 7,\
  4933. 8,\
  4934. 9,\
  4935. 10,\
  4936. 11,\
  4937. 12,\
  4938. 13,\
  4939. 14,\
  4940. 15,\
  4941. 16,\
  4942. 17,\
  4943. 18,\
  4944. 19,\
  4945. 20,\
  4946. 21,\
  4947. 22,\
  4948. 24,\
  4949. 25,\
  4950. 23,\
  4951. 25,\
  4952. 25,\
  4953. 25,\
  4954. 25,\
  4955. 25,\
  4956. 25,\
  4957. 25,\
  4958. 25,\
  4959. 24,\
  4960. 23,\
  4961. 22,\
  4962. 21,\
  4963. 20,\
  4964. 19,\
  4965. 18,\
  4966. 17,\
  4967. 16,\
  4968. 15,\
  4969. 14,\
  4970. 13,\
  4971. 12,\
  4972. 11,\
  4973. 10,\
  4974. 9,\
  4975. 8,\
  4976. 7,\
  4977. 1,\
  4978. 2,\
  4979. 3,\
  4980. 4,\
  4981. 5,\
  4982. 6,\
  4983. 1,\
  4984. 1,\
  4985. 1,\
  4986. 1,\
  4987. 1,\
  4988. 1,\
  4989. 1,\
  4990. },\
  4991. doorsX = {},\
  4992. spawnY = 1,\
  4993. spawnX = 1,\
  4994. laddersX = {\
  4995. 9,\
  4996. },\
  4997. doorsY = {},\
  4998. laddersY = {\
  4999. 2,\
  5000. },\
  5001. ladderDestination = {\
  5002. \"house1\",\
  5003. },\
  5004. }",
  5005. "--Editor (yaay make your own levels based on this \"engine\")\
  5006. --Again, written by me c:\
  5007. --(I know, I'm shit at programming but hey why not C:)\
  5008. \
  5009. --Variablen\
  5010. _ver = 0.1\
  5011. _verstr = \"0.1\"\
  5012. pfad = \"\"\
  5013. \
  5014. lvlData = {\
  5015. \009spawnPosX=\"1\",\
  5016. \009spawnPosY=\"1\",\
  5017. \009blocksX = {\
  5018. \
  5019. \009},\
  5020. \009blocksY = {\
  5021. \
  5022. \009}\
  5023. }\
  5024. \
  5025. --Funktionen\
  5026. function clear(bg, fg)\
  5027. \009term.setCursorPos(1,1)\
  5028. \009term.setBackgroundColor(bg)\
  5029. \009term.setTextColor(fg)\
  5030. \009term.clear()\
  5031. end\
  5032. \
  5033. function menu()\
  5034. \009clear(colors.black, colors.white)\
  5035. \009term.setBackgroundColor(colors.lime)\
  5036. \009term.setCursorPos(25, 6)\
  5037. \009term.write(\"NEW\")\
  5038. \009term.setCursorPos(24, 8)\
  5039. \009term.write(\"LOAD\")\
  5040. \009term.setCursorPos(24, 10)\
  5041. \009term.write(\"EXIT\")\
  5042. \009menu = true\
  5043. \009while menu do\
  5044. \009\009local event, button, x, y = os.pullEventRaw(\"mouse_click\")\
  5045. \009\009if button == 1 and x >= 25 and x <= 27 and y == 6 then\
  5046. \009\009\009menu = false\
  5047. \009\009\009menu2()\
  5048. \009\009end\
  5049. \009end\
  5050. end\
  5051. \
  5052. function menu2()\
  5053. \009clear(colors.black, colors.white)\
  5054. \009oldTerm = term.native()\
  5055. \009local graywindow = window.create(oldTerm, 15, 5, 20, 5)\
  5056. \009term.redirect(graywindow)\
  5057. \009term.setBackgroundColor(colors.lightGray)\
  5058. \009term.setCursorPos(1,1)\
  5059. \009term.clear()\
  5060. \009local textBox = window.create(term.current(), 2, 2, 18, 1)\
  5061. \009textBox.setBackgroundColor(colors.gray)\
  5062. \009textBox.setTextColor(colors.lime)\
  5063. \009textBox.clear()\
  5064. \009textBox.write(\"Enter Name/Desti..\")\
  5065. \009term.setBackgroundColor(colors.gray)\
  5066. \009term.setTextColor(colors.white)\
  5067. \009term.setCursorPos(2, 4)\
  5068. \009term.write(\"New\")\
  5069. \009term.setCursorPos(16, 4)\
  5070. \009term.write(\"Load\")\
  5071. \009menu = true\
  5072. \009while menu do\
  5073. \009\009local event, button, x, y = os.pullEvent(\"mouse_click\")\
  5074. \009\009if button == 1 and x >= 16 and x <= 34 and y == 6 then\
  5075. \009\009\009term.redirect(textBox)\
  5076. \009\009\009term.clear()\
  5077. \009\009\009term.setCursorPos(1,1)\
  5078. \009\009\009local eingabe = read()\
  5079. \009\009\009pfad = eingabe\
  5080. \009\009\009term.setCursorPos(1,1)\
  5081. \009\009\009term.clear()\
  5082. \009\009\009term.write(eingabe)\
  5083. \009\009\009term.redirect(graywindow)\
  5084. \009\009elseif button == 1 and x >= 16 and x <= 18 and y == 8 then\
  5085. \009\009\009if fs.exists(pfad..\".lvl\") then\
  5086. \009\009\009\009textBox.setCursorPos(1,1)\
  5087. \009\009\009\009textBox.clear()\
  5088. \009\009\009\009textBox.setTextColor(colors.red)\
  5089. \009\009\009\009textBox.write(\"Already exists.\")\
  5090. \009\009\009\009textBox.setTextColor(colors.lime)\
  5091. \009\009\009elseif pfad == \"\" or pfad == nil then\
  5092. \009\009\009\009textBox.setCursorPos(1,1)\
  5093. \009\009\009\009textBox.clear()\
  5094. \009\009\009\009textBox.setTextColor(colors.red)\
  5095. \009\009\009\009textBox.write(\"Please fill in.\")\
  5096. \009\009\009\009textBox.setTextColor(colors.lime)\
  5097. \009\009\009else\
  5098. \009\009\009\009term.redirect(oldTerm)\
  5099. \009\009\009\009term.setCursorPos(1,1)\
  5100. \009\009\009\009clear(colors.black, colors.white)\
  5101. \009\009\009\009menu = false\
  5102. \009\009\009\009print(\"Please draw your LevelDESIGN.\")\
  5103. \009\009\009\009print(\"This will be that, what you see when playing the level.\")\
  5104. \009\009\009\009sleep(3)\
  5105. \009\009\009\009shell.run(\"paint \"..pfad..\".lvl\")\
  5106. \009\009\009\009\
  5107. \009\009\009\009editor()\
  5108. \009\009\009end\
  5109. \009\009elseif button == 1 and x >= 30 and x <= 34 and y == 8 then\
  5110. \009\009\009if fs.exists(pfad..\".lvl\") and fs.exists(pfad..\".lvlDat\") then\
  5111. \009\009\009\009term.redirect(oldTerm)\
  5112. \009\009\009\009menu = false\
  5113. \009\009\009\009editor(\"true\")\
  5114. \009\009\009elseif fs.exists(pfad..\".lvl\") then\
  5115. \009\009\009\009term.redirect(oldTerm)\
  5116. \009\009\009\009menu = false\
  5117. \009\009\009\009editor(\"false\")\
  5118. \009\009\009else\
  5119. \009\009\009\009textBox.setCursorPos(1,1)\
  5120. \009\009\009\009textBox.clear()\
  5121. \009\009\009\009textBox.setTextColor(colors.red)\
  5122. \009\009\009\009textBox.write(\"Doesn't exist.\")\
  5123. \009\009\009\009textBox.setTextColor(colors.lime)\
  5124. \009\009\009end\
  5125. \009\009end\
  5126. \009end\
  5127. \
  5128. end\
  5129. \
  5130. function loadDat()\
  5131. \009local file = fs.open(pfad..\".lvlDat\",\"r\")\
  5132. \009local inhalt = file.readAll()\
  5133. \009lvlData = textutils.unserialize(inhalt)\
  5134. \009file.close()\
  5135. end\
  5136. \
  5137. function editor(loadData)\
  5138. \009clear(colors.black, colors.white)\
  5139. \009lvl = paintutils.loadImage(pfad..\".lvl\")\
  5140. \009paintutils.drawImage(lvl, 1, 1)\
  5141. \009if loadData == \"true\" then\
  5142. \009\009loadDat()\
  5143. \009\009reloadMap()\
  5144. \009end\
  5145. \009term.setCursorPos(1,19)\
  5146. \009term.setBackgroundColor(colors.lightGray)\
  5147. \009term.clearLine()\
  5148. \009term.setBackgroundColor(colors.lime)\
  5149. \009term.write(\" Block \")\
  5150. \009term.setBackgroundColor(colors.lightGray)\
  5151. \009term.write(\" \")\
  5152. \009term.setBackgroundColor(colors.lime)\
  5153. \009term.write(\" Spawn \")\
  5154. \009term.setBackgroundColor(colors.lightGray)\
  5155. \009term.write(\" \")\
  5156. \009term.setBackgroundColor(colors.lime)\
  5157. \009term.write(\" Remove \")\
  5158. \009editing = true\
  5159. \009while editing do\
  5160. \009\009local event, button, x, y = os.pullEventRaw()\
  5161. \009\009if event == \"mouse_click\" and button == 1 and x >= 1 and x <= 7 and y == 19 then\
  5162. \009\009\009currentBlock = \"block\"\
  5163. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 9 and x <= 15 and y == 19 then\
  5164. \009\009\009currentBlock = \"spawn\"\
  5165. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 17 and x <= 24 and y == 19 then\
  5166. \009\009\009currentBlock = \"remove\"\
  5167. \009\009elseif event == \"mouse_click\" and button == 1 and x >= 1 and x <= 51 and y >= 1 and y <= 18 then\
  5168. \009\009\009if currentBlock == \"block\" then\
  5169. \009\009\009\009term.setCursorPos(x, y)\
  5170. \009\009\009\009term.setBackgroundColor(colors.brown)\
  5171. \009\009\009\009term.setTextColor(colors.white)\
  5172. \009\009\009\009term.write(\"B\")\
  5173. \009\009\009\009local x = tostring(x)\
  5174. \009\009\009\009local y = tostring(y)\
  5175. \009\009\009\009table.insert(lvlData.blocksX, x)\
  5176. \009\009\009\009table.insert(lvlData.blocksY, y)\
  5177. \009\009\009\009reloadMap()\
  5178. \009\009\009elseif currentBlock == \"spawn\" then\
  5179. \009\009\009\009term.setCursorPos(x, y)\
  5180. \009\009\009\009term.setBackgroundColor(colors.blue)\
  5181. \009\009\009\009term.setTextColor(colors.white)\
  5182. \009\009\009\009term.write(\"S\")\
  5183. \009\009\009\009local x = tostring(x)\
  5184. \009\009\009\009local y = tostring(y)\
  5185. \009\009\009\009lvlData.spawnPosX = x\
  5186. \009\009\009\009lvlData.spawnPosY = y\
  5187. \009\009\009\009reloadMap()\
  5188. \009\009\009elseif currentBlock == \"remove\" then\
  5189. \009\009\009\009for _, block in ipairs(lvlData.blocksX) do\
  5190. \009\009\009\009\009local blockY = tonumber(lvlData.blocksY[_])\
  5191. \009\009\009\009\009local block = tonumber(block)\
  5192. \009\009\009\009\009if x == block and y == blockY then\
  5193. \009\009\009\009\009\009lvlData.blocksX[_] = nil\
  5194. \009\009\009\009\009\009lvlData.blocksY[_] = nil\
  5195. \009\009\009\009\009end\
  5196. \009\009\009\009end\
  5197. \009\009\009\009if x == lvlData.spawnPosX and y == lvlData.spawnPosY then\
  5198. \009\009\009\009\009lvlData.spawnPosX = \"1\"\
  5199. \009\009\009\009\009lvlData.spawnPosY = \"1\"\
  5200. \009\009\009\009end\
  5201. \009\009\009\009reloadMap()\
  5202. \009\009\009end\
  5203. \009\009elseif event == \"key\" and button == keys.s then\
  5204. \009\009\009local file = fs.open(pfad..\".lvlDat\",\"w\")\
  5205. \009\009\009local lvlData = textutils.serialize(lvlData)\
  5206. \009\009\009file.write(lvlData)\
  5207. \009\009\009file.close()\
  5208. \009\009\009clear(colors.black, colors.white)\
  5209. \
  5210. \009\009\009editing = false\
  5211. \009\009\009break\
  5212. \009\009end\
  5213. \
  5214. \009end\
  5215. end\
  5216. \
  5217. function reloadMap()\
  5218. \009clear(colors.black, colors.white)\
  5219. \009term.setCursorPos(1,19)\
  5220. \009term.setBackgroundColor(colors.lightGray)\
  5221. \009term.clearLine()\
  5222. \009term.setBackgroundColor(colors.lime)\
  5223. \009term.write(\" Block \")\
  5224. \009term.setBackgroundColor(colors.lightGray)\
  5225. \009term.write(\" \")\
  5226. \009term.setBackgroundColor(colors.lime)\
  5227. \009term.write(\" Spawn \")\
  5228. \009term.setBackgroundColor(colors.lightGray)\
  5229. \009term.write(\" \")\
  5230. \009term.setBackgroundColor(colors.lime)\
  5231. \009term.write(\" Remove \")\
  5232. \009term.setCursorPos(1,1)\
  5233. \009paintutils.drawImage(lvl, 1, 1)\
  5234. \009for _, block in ipairs(lvlData.blocksX) do\
  5235. \009\009local blockY = tonumber(lvlData.blocksY[_])\
  5236. \009\009local block = tonumber(block)\
  5237. \009\009term.setCursorPos(block, blockY)\
  5238. \009\009term.setBackgroundColor(colors.brown)\
  5239. \009\009term.setTextColor(colors.white)\
  5240. \009\009term.write(\"B\")\
  5241. \009end\
  5242. \009local sX = tonumber(lvlData.spawnPosX)\
  5243. \009local sY = tonumber(lvlData.spawnPosY)\
  5244. \009term.setCursorPos(sX, sY)\
  5245. \009term.setBackgroundColor(colors.blue)\
  5246. \009term.setTextColor(colors.white)\
  5247. \009term.write(\"S\")\
  5248. end\
  5249. \
  5250. \
  5251. \
  5252. --Code\
  5253. menu2()",
  5254. }
  5255. folders = {
  5256. "Project",
  5257. "Project/API",
  5258. "Project/game",
  5259. "Project/maps",
  5260. "Project/maps/house1",
  5261. "Project/maps/house2",
  5262. }
  5263. local args = {...}
  5264. if #args < 1 then
  5265. print('Usage: <file> <destination>')
  5266. else
  5267. args[1] = args[1]..'/' for _, folder in ipairs(folders) do
  5268. fs.makeDir(args[1]..folder)
  5269. end
  5270. for _, file in ipairs(files) do
  5271. local file = fs.open(args[1]..file, 'w')
  5272. file.write(fileData[_])
  5273. file.close()
  5274. end
  5275. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement