main.lua 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883
  1. local class = require 'lib/middleclass'
  2. local stalker = require 'lib/STALKER-X'
  3. local animate = require 'lib/love-animation'
  4. local i18n = require 'lib/i18n'
  5. local sti = require 'lib/Simple-Tiled-Implementation/sti'
  6. -- Button values
  7. LEFT = -4; RIGHT = -3; UP = -2; DOWN = -1
  8. YES = -5; NO = -6; NUCLEAR = -7
  9. currentRoom = nil -- Just in case. Gets overriden, but juuust in case.
  10. states = {}
  11. function love.load()
  12. love.graphics.setDefaultFilter("nearest", "nearest")
  13. P_ttf = love.graphics.newFont("art/font/PressStart2P.ttf", nil, "none")
  14. p_ttf = love.graphics.newFont("art/font/puntillas.ttf", nil, "none")
  15. new camera()
  16. game init()
  17. end
  18. -- Main loop
  19. -- t – Time since last update.
  20. function love.update(t)
  21. camera:update(t)
  22. state function("update", t)
  23. end
  24. function love.draw()
  25. camera:attach()
  26. state function("draw")
  27. camera:detach()
  28. camera:draw()
  29. end
  30. function love.keypressed(key)
  31. state function("keypressed", key)
  32. end
  33. function love.keyreleased(key)
  34. state function("keyreleased", key)
  35. end
  36. function love.resize()
  37. local width,height = love.window.getMode()
  38. new camera()
  39. currentRoom:camera bound()
  40. end
  41. function new camera()
  42. camera = stalker()
  43. camera:setFollowStyle('TIGHT_FOLLOW')
  44. camera:setFollowLerp(1)
  45. end
  46. -- STATES :: SUFOKIĜU :: ℋ𝒜𝒮𝒦ℰℒℒ 𝒞ℛℰ𝒲
  47. --------------------------------------------------------------------------------
  48. -- GAME
  49. ----------------------------------------
  50. --[[
  51. function·call U+00B7 MIDDLE DOT
  52. function’call
  53. function🦆call,<<<
  54. function🕴call
  55. blessed†function†invocation
  56. function⁂call
  57. function‣call
  58. function⁝call
  59. newUpdate, newDraw, newPress, newRelease,
  60. ]]--
  61. function game init()
  62. local domo = Domo:new()
  63. domo:install()
  64. local functions = {
  65. ["update"] = { ["func"] = game update, ["combine"] = false },
  66. ["draw"] = { ["func"] = game draw, ["combine"] = false },
  67. ["keypressed"] = { ["func"] = game keypressed, ["combine"] = false },
  68. ["keyreleased"] = { ["func"] = game keyreleased, ["combine"] = false }
  69. }
  70. local game mode = { ["functions"] = functions, ["name"] = "game" }
  71. add state(game mode)
  72. testmenuo = ĉefmenuo()
  73. testmenuo:install()
  74. end
  75. function game update(t)
  76. currentRoom:update(t)
  77. end
  78. function game draw()
  79. currentRoom:draw()
  80. end
  81. function game keypressed(key)
  82. currentRoom:keypressed(key)
  83. end
  84. function game keyreleased(key)
  85. currentRoom:keyreleased(key)
  86. end
  87. --
  88. ----------------------------------------
  89. -- ^CLASSES <<<< ~~~ ** ""< <<<<<<<< TIE <<< ĜI SUPERAS, ĈU VI RIMARKIS AŬ NE??? BONVOLE RESPONDU
  90. --------------------------------------------------------------------------------
  91. -- CHARACTER
  92. ----------------------------------------
  93. Character = class("Character")
  94. function Character:initialize(sprite file, name)
  95. self.name = name
  96. if (sprite file ~= nil) then
  97. self.animation = LoveAnimation.new(sprite file)
  98. end
  99. self.loc = { ["x"] = 0, ["y"] = 0, ["z"] = nil } --[[Oseble]]--
  100. self.width = 32
  101. self.height = 16
  102. self.dead = false
  103. self.direction = RIGHT
  104. -- Right or left― which way the character is facing.
  105. self.directionals = { RIGHT = 0, LEFT = 0, UP = 0, DOWN = 0 }
  106. -- Directionals show the ascending order of currently pressed buttons.
  107. self.walking = false
  108. self.walkspeed = 100
  109. self.move order = nil
  110. self.has plunger = false
  111. end
  112. function Character:draw()
  113. if (self.animation ~= nil) then
  114. self.animation:draw(2, 2)
  115. end
  116. end
  117. function Character:update(t)
  118. self:movement(t)
  119. self:move to update()
  120. self:directionals update()
  121. self:animation update(t)
  122. end
  123. function Character:interact(interacter)
  124. end
  125. function Character:directionals update()
  126. local dirs = self.directionals
  127. if (dirs[LEFT] == 2 and dirs[RIGHT] == 0) then dirs[LEFT] = 1; end
  128. if (dirs[RIGHT] == 2 and dirs[LEFT] == 0) then dirs[RIGHT] = 1; end
  129. if (dirs[UP] == 2 and dirs[DOWN] == 0) then dirs[UP] = 1; end
  130. if (dirs[DOWN] == 2 and dirs[UP] == 0) then dirs[DOWN] = 1; end
  131. self.walking = false
  132. for direction,queue pos in pairs(dirs) do
  133. if (queue pos == 1) then
  134. self.walking = true
  135. end
  136. end
  137. end
  138. function Character:animation update(t)
  139. if (self.animation == nil) then
  140. return
  141. end
  142. self.animation:setPosition(self.loc.x, self.loc.y)
  143. self.animation:update(t)
  144. if (self.dead == true) then
  145. return
  146. end
  147. if (self.walking == true) then
  148. if (self.direction == LEFT) and (self.animation:getCurrentState() ~= "walkleft") then
  149. self.animation:setState("walkleft")
  150. elseif (self.direction == RIGHT) and (self.animation:getCurrentState() ~= "walkright") then
  151. self.animation:setState("walkright")
  152. end
  153. else
  154. if (self.direction == LEFT) and (self.animation:getCurrentState() ~= "inactiveleft") then
  155. self.animation:setState("inactiveleft")
  156. elseif (self.direction == RIGHT) and (self.animation:getCurrentState() ~= "inactiveright") then
  157. self.animation:setState("inactiveright")
  158. end
  159. end
  160. end
  161. function Character:touched thing()
  162. -- NOTO POR ĴADO: Ĉu ne tro precizas? (K.a. mi korektis.)
  163. -- La problemo estas, ke la ludata koordinatoj malpli grandas ol atendite― do ni aldonu 32, ne forgu
  164. -- Hooo, ial mi mispensis, ke self.loc.x monrus al la aĵo…
  165. return currentRoom:get thing at("Aĵoj", self.loc.x + 32, self.loc.y + 32)
  166. end
  167. function Character:touched character()
  168. for k,char in pairs(currentRoom.characters) do
  169. if (char.name ~= self.name) then
  170. if (are colliding(self:bounding box(), char:bounding box()) == true) then
  171. return char
  172. end
  173. end
  174. end
  175. end
  176. function Character:bounding box()
  177. local x diff = self.width / 2
  178. local y diff = self.height / 2
  179. local x1 = self.loc.x - x diff - 16
  180. local x2 = self.loc.x + x diff - 16
  181. local y1 = self.loc.y - y diff - 16
  182. local y2 = self.loc.y + y diff - 16
  183. return { ["x1"] = x1, ["x2"] = x2, ["y1"] = y1, ["y2"] = y2 }
  184. end
  185. function Character:touching wall at(direction)
  186. local x = self.loc.x
  187. local y = self.loc.y
  188. if (direction == UP) then y = y - self.height
  189. elseif (direction == DOWN) then y = y + self.height
  190. elseif (direction == RIGHT) then x = x + self.width / 2
  191. elseif (direction == LEFT) then x = x - self.width / 2
  192. end
  193. return currentRoom:has tile at("Interfrapeco", x, y)
  194. end
  195. function Character:take(character)
  196. self.has plunger = true
  197. for k,char in pairs(currentRoom.characters) do
  198. if (char.name == "malŝtopilo") then
  199. char:remove()
  200. end
  201. end
  202. end
  203. function Character:has plunger()
  204. return self.has plunger
  205. end
  206. function Character:movement(t)
  207. if (self.dead == true) then
  208. return
  209. end
  210. local walkspeed = self.walkspeed * t
  211. local dirs = self.directionals
  212. if (self.walking == true) then
  213. -- actually moving -- ←←←←←←←←←←←←←←
  214. if (dirs[RIGHT] == 1) and (self:touching wall at(RIGHT) == false) then
  215. self.loc.x = self.loc.x + walkspeed
  216. elseif (dirs[LEFT] == 1) and (self:touching wall at(LEFT) == false) then
  217. self.loc.x = self.loc.x - walkspeed
  218. end
  219. if (dirs[UP] == 1) and (self:touching wall at(UP) == false) then
  220. self.loc.y = self.loc.y - walkspeed
  221. elseif (dirs[DOWN] == 1) and (self:touching wall at(DOWN) == false) then
  222. self.loc.y = self.loc.y + walkspeed
  223. end
  224. end
  225. end
  226. function Character:move to(x, y)
  227. self.move order = { ["x"] = x, ["y"] = y }
  228. end
  229. function Character:move to update(t)
  230. dirs = self.directionals
  231. if (self.move order == nil) then
  232. return
  233. end
  234. self.walking = true
  235. if (self.loc.x < self.move order.x) then
  236. self.direction = RIGHT
  237. dirs[RIGHT] = 1; dirs[LEFT] = 0
  238. elseif (self.loc.x > self.move order.x) then
  239. self.direction = LEFT
  240. dirs[LEFT] = 1; dirs[RIGHT] = 0
  241. elseif (self.loc.y < self.move order.y) then
  242. dirs[DOWN] = 1; dirs[UP] = 0
  243. elseif (self.loc.y > self.move order.y) then
  244. dirs[UP] = 1; dirs[DOWN] = 0
  245. else
  246. dirs[DOWN] = 0; dirs[UP] = 0
  247. dirs[RIGHT] = 0; dirs[LEFT] = 0
  248. self.move order = nil
  249. self.walking = false
  250. end
  251. end
  252. function Character:remove()
  253. for k,character in pairs(currentRoom.characters) do
  254. if (character.name == self.name) then
  255. table.remove(currentRoom.characters, k)
  256. end
  257. end
  258. end
  259. function Character:kill()
  260. print("HELPPP IM BEING MURDEREDDD")
  261. if (self.direction == LEFT) then
  262. self.animation:setState("ripleft")
  263. else
  264. self.animation:setState("ripright")
  265. end
  266. self.dead = true
  267. end
  268. function Character:keypressed(key)
  269. end
  270. function Character:keyreleased(key)
  271. end
  272. -- PLAYER
  273. ----------------------------------------
  274. Player = class("Player", Character)
  275. function Player:initialize(sprite file)
  276. Character.initialize(self, sprite file, "ludato")
  277. self.height = 16
  278. self.keymap = {
  279. ["left"] = LEFT, ["right"] = RIGHT, ["up"] = UP, ["down"] = DOWN,
  280. ["kp4"] = LEFT, ["kp6"] = RIGHT, ["kp8"] = UP, ["kp2"] = DOWN,
  281. ["a"] = LEFT, ["d"] = RIGHT, ["w"] = UP, ["s"] = DOWN,
  282. ["a"] = LEFT, ["e"] = RIGHT, [","] = UP, ["o"] = DOWN,
  283. ["q"] = YES, ["z"] = YES, ["space"] = YES, ["return"] = YES,
  284. ["j"] = NO, ["x"] = NO, ["backspace"] = NO, ["lctrl"] = NO,
  285. ["escape"] = NUCLEAR, ["capslock"] = NUCLEAR,
  286. }
  287. end
  288. function Player:bounding box()
  289. local x diff = self.width / 2
  290. local y diff = self.height / 2
  291. local x1 = self.loc.x - x diff
  292. local x2 = self.loc.x + x diff
  293. local y1 = self.loc.y - y diff
  294. local y2 = self.loc.y + y diff
  295. return { ["x1"] = x1, ["x2"] = x2, ["y1"] = y1, ["y2"] = y2 }
  296. end
  297. function Player:update(t)
  298. Character.update(self, t)
  299. camera:follow(self.loc.x, self.loc.y)
  300. end
  301. function Player:keypressed(key)
  302. local dirs = self.directionals
  303. local dir = self.keymap[key]
  304. if (dir == RIGHT) or (dir == LEFT) then
  305. self.direction = dir
  306. end
  307. if (dir == YES) then -- trying to interact
  308. local char = self:touched character()
  309. local obj = self:touched thing()
  310. if (char ~= nil) then
  311. char:interact(self)
  312. elseif (obj ~= nil) then
  313. obj:interact(self)
  314. end
  315. return
  316. end
  317. if (dir == NUCLEAR) then -- you wanna yeet out
  318. -- menuo ĉi tie :w:
  319. end
  320. if (dir == RIGHT) then -- you’re going in the right direction
  321. dirs[RIGHT] = 1; if (dirs[LEFT] == 1) then dirs[LEFT] = 2; end
  322. elseif (dir == LEFT) then
  323. dirs[LEFT] = 1; if (dirs[RIGHT] == 1) then dirs[RIGHT] = 2; end
  324. elseif (dir == UP) then
  325. dirs[UP] = 1; if (dirs[DOWN] == 1) then dirs[DOWN] = 2; end
  326. elseif (dir == DOWN) then -- you’re going DOWN >:-)
  327. dirs[DOWN] = 1; if (dirs[UP] == 1) then dirs[UP] = 2; end
  328. end
  329. end
  330. function Player:keyreleased(key)
  331. local dirs = self.directionals
  332. local dir = self.keymap[key]
  333. if (dirs[dir] ~= nil) then
  334. dirs[dir] = 0
  335. end
  336. end
  337. -- ROOM
  338. ----------------------------------------
  339. Room = class("Room")
  340. function Room:initialize(map file, door id)
  341. self:load map(map file)
  342. local ludato = Player:new("art/adventurer.lua")
  343. self:install character(ludato, door id)
  344. self.things = { }
  345. end
  346. function Room:draw()
  347. for k,layer in pairs(self.bottom layers) do
  348. self.map:drawLayer(layer)
  349. end
  350. for k,layer in pairs(self.middle layers) do
  351. self.map:drawLayer(layer)
  352. end
  353. for k,character in pairs(self.characters) do
  354. character:draw()
  355. end
  356. for k,layer in pairs(self.top layers) do
  357. self.map:drawLayer(layer)
  358. end
  359. end
  360. function Room:update(t)
  361. self.map:update()
  362. for k,character in pairs(self.characters) do
  363. character:update(t)
  364. end
  365. end
  366. function Room:keypressed(key)
  367. for k,character in pairs(self.characters) do
  368. character:keypressed(key)
  369. end
  370. end
  371. function Room:keyreleased(key)
  372. for k,character in pairs(self.characters) do
  373. character:keyreleased(key)
  374. end
  375. end
  376. function Room:install()
  377. currentRoom = self
  378. self:camera bound()
  379. end
  380. function Room:camera bound()
  381. camera:setBounds(-30, -30, self.width + 30, self.height + 30)
  382. end
  383. function Room:load map(map file)
  384. self.map = sti(map file)
  385. self:reload tiles()
  386. end
  387. function Room:reload tiles()
  388. self.top layers = {}
  389. self.middle layers = {}
  390. self.bottom layers = {}
  391. for k,layer in pairs(self.map.layers) do
  392. -- if (layer.name == "Interfrapeco") then
  393. -- table.insert(self.top layers, layer)
  394. -- end
  395. if (layer.width ~=nil) then
  396. self.width,self.height = self.map:convertTileToPixel(layer.width + 1, layer.height + 2)
  397. end
  398. if (type(k) == "number") then
  399. local ordo = layer.properties.ordo
  400. if (ordo == nil) then
  401. -- nenio
  402. elseif (ordo == "top") then
  403. table.insert(self.top layers, layer)
  404. elseif (ordo == "bottom") then
  405. table.insert(self.bottom layers, layer)
  406. end
  407. end
  408. end
  409. end
  410. function Room:install character(character, doorid)
  411. if (self.characters == nil) then self.characters = {} end
  412. table.insert(self.characters, character)
  413. if (doorid ~= nil) then
  414. local door = self:get object("Pordoj", "id", doorid)
  415. if (door ~= nil) then
  416. character.loc.x = door.x
  417. character.loc.y = door.y
  418. return
  419. end
  420. end
  421. local spawn = self:get object("Roluloj", "rolulo", character.name)
  422. if (spawn == nil) then
  423. return
  424. end
  425. character.loc.x = spawn.x
  426. character.loc.y = spawn.y
  427. end
  428. function Room:install thing(thing)
  429. if (self.things == nil) then self.things = {} end
  430. table.insert(self.things, thing)
  431. end
  432. function Room:on enter()
  433. end
  434. function Room:on exit()
  435. end
  436. -- Find object in the given layer by a property/value pair
  437. function Room:get object(layer, property, value)
  438. local layer = self.map.layers[layer]
  439. for k,object in pairs(layer.objects) do
  440. if (object.properties ~= nil) and (object.properties[property] ~=nil) then
  441. if (object.properties[property] == value) then
  442. return object
  443. end
  444. end
  445. end
  446. end
  447. -- Find object in the given layer by location
  448. function Room:get object at(layer name, x, y)
  449. local layer = self.map.layers[layer name]
  450. local closest = nil
  451. local closeness = nil
  452. --[[ -- Tiriftaĵo; ne zorgu!
  453. self.map:setObjectCoordinates(layer)
  454. for k,v in pairs(layer["objects"][1]) do
  455. print(k, v)
  456. end
  457. print("-----------------------------------")
  458. ]]
  459. print(x .. "x" .. y)
  460. for k,object in pairs(layer.objects) do
  461. local distanco = distance(x, y, object.x, object.y)
  462. print ("Objekto: " .. object.x .. "x" .. object.y .. " at " .. distanco)
  463. if (closeness == nil) or (closeness > distanco) then
  464. closeness = distanco
  465. closest = object
  466. end
  467. end
  468. if (closeness ~= nil) and (closeness < 30) then
  469. return closest
  470. end
  471. end
  472. function Room:get thing at(layer name, x, y)
  473. local object = self:get object at(layer name, x, y)
  474. if (object ~= nil) then
  475. for k,thing in pairs(self.things) do
  476. if (thing.name == object.properties["aĵo"]) then
  477. return thing
  478. end
  479. end
  480. end
  481. end
  482. function distance(x1, y1, x2, y2)
  483. return math.sqrt((x2-x1)^2 + (y2-y1)^2)
  484. end
  485. function Room:get tile at(layer, x, y)
  486. local layer = self.map.layers[layer].data
  487. tileX,tileY = self.map:convertPixelToTile(x , y)
  488. tileX = math.floor(tileX) + 2
  489. tileY = math.floor(tileY) + 2
  490. if (layer[tileY] == nil) or (layer[tileY][tileX] == nil) then
  491. return nil
  492. end
  493. return layer[tileY][tileX]
  494. end
  495. function Room:has tile at(layer, x, y)
  496. if (self:get tile at(layer, x, y) == nil) then
  497. return false
  498. end
  499. return true
  500. end
  501. -- tileX – your one-wipe step to tiles clear as mirrors
  502. -- MENU
  503. ---------------------------------------
  504. Menu = class("Menu")
  505. function Menu:initialize(x, y, offset_x, offset_y, scale, menuItems)
  506. -- x, kie komenciĝas la menuo horizontale
  507. -- y, kie komenciĝas la menuo vertikale
  508. self.x,self.y = x,y
  509. -- offset_x, horizontal distance between option and ">>"
  510. -- offset_y, vertical distance between options
  511. self.offset_x,self.offset_y = offset_x,offset_y
  512. self.options = menuItems
  513. self.selected = 1
  514. self.scale = scale
  515. self.keys = {}
  516. self.keys['up'] = false
  517. self.keys['down'] = false
  518. self.keys['enter'] = false
  519. self.ttf = p_ttf
  520. end
  521. function Menu:install(update, draw, press, release)
  522. local functions = {
  523. ["update"] = { ["func"] = function (t) self:update(dt) end, ["combine"] = false },
  524. ["draw"] = { ["func"] = function () self:draw() end, ["combine"] = true },
  525. ["keypressed"] = { ["func"] = function(key) self:keypressed(key) end, ["combine"] = false },
  526. ["keyreleased"] = { ["func"] = function(key) self:keyreleased(key) end, ["combine"] = false }
  527. }
  528. add state({ ["functions"] = functions, ["name"] = "menuo" })
  529. end
  530. function Menu:uninstall()
  531. remove state("menuo")
  532. end
  533. function Menu:update()
  534. end
  535. function Menu:draw()
  536. for i=1,table.maxn(self.options) do
  537. local this_y = self.y + (self.offset_y * i)
  538. love.graphics.draw(
  539. love.graphics.newText(p_ttf, self.options[i][1]),
  540. self.x, this_y, 0, self.scale, self.scale)
  541. if (i == self.selected) then
  542. love.graphics.draw(love.graphics.newText(p_ttf, ">>"),
  543. self.x - self.offset_x, this_y, 0, self.scale, self.scale)
  544. end
  545. end
  546. end
  547. function Menu:keypressed(key)
  548. maxn = table.maxn(self.options)
  549. if (key == "return" or key == "space") then
  550. self.keys['enter'] = true
  551. if(self.options[self.selected][2]) then
  552. self.options[self.selected][2]()
  553. end
  554. elseif (key == "up" and self.selected > 1
  555. and self.keys['up'] == false) then
  556. self.keys['up'] = true
  557. self.selected = self.selected - 1
  558. elseif (key == "up" and self.keys['up'] == false) then
  559. self.keys['up'] = true
  560. self.selected = maxn
  561. elseif (key == "down" and self.selected < maxn
  562. and self.keys['down'] == false) then
  563. self.keys['down'] = true
  564. self.selected = self.selected + 1
  565. elseif (key == "down" and self.keys['down'] == false) then
  566. self.keys['down'] = true
  567. self.selected = 1
  568. end
  569. end
  570. function Menu:keyreleased(key)
  571. if (key == "return" or key == "space") then
  572. self.keys['enter'] = false
  573. elseif (key == "up") then
  574. self.keys['up'] = false
  575. elseif (key == "down") then
  576. self.keys['down'] = false
  577. end
  578. end
  579. -- MAIN MENU
  580. -------------------
  581. Main Menu = class("Main Menu", Menu)
  582. function Main Menu:initialize(menuItems)
  583. self:update() -- Gives us self.x and self.y
  584. Menu.initialize(self, self.x, self.y, 50, 50, 3, menuItems)
  585. end
  586. function Main Menu:update() -- Must set self.x and self.y
  587. window width, window height = love.graphics.getDimensions()
  588. self.x, self.y = (window width - 300) / 2, (window height - 300) / 2
  589. end
  590. function Main Menu:draw()
  591. -- Darken screen
  592. window width, window height = love.graphics.getDimensions()
  593. love.graphics.setColor(0.4, 0.1, 0.1)
  594. love.graphics.rectangle("fill",
  595. 0, 0,
  596. window width, window height)
  597. love.graphics.setColor(1, 1, 1)
  598. Menu.draw(self)
  599. end
  600. -- GOURMET MENU
  601. -------------------
  602. Gourmet Menu = class("Gourmet Menu", Menu) -- It’s really a “choice menu”…
  603. function Gourmet Menu:initialize(menuItems)
  604. self.width = 400
  605. self.height = (6 * 4--[[frame line]]) + (64 * #menuItems)
  606. self:update() -- Gives us self.x and self.y
  607. Menu.initialize(self, self.x, self.y, 50, 50, 2, menuItems)
  608. end
  609. function Gourmet Menu:update() -- Must set self.x and self.y
  610. window width, window height = love.graphics.getDimensions()
  611. self.x = 64 + (camera.x - window width / 2)
  612. self.y = (window height - self.height) / 2 + (camera.y - window height / 2)
  613. self.width = window width - 128
  614. end
  615. function Gourmet Menu:draw()
  616. draw frame(self.x - (frame line * 3),
  617. self.y - (frame line * 2),
  618. self.width + (frame line * 6),
  619. self.height + (frame line * 4))
  620. Menu.draw(self)
  621. end
  622. function Gourmet Menu:keypressed(key)
  623. if (key == "return" or key == "space") then
  624. self:uninstall()
  625. end
  626. Menu.keypressed(self, key)
  627. end
  628. -- DIALOGUE
  629. ----------------------------------------
  630. Dialogue = class("Dialogue")
  631. function Dialogue:initialize(message list)
  632. self.messages = message list -- Number-indexed table
  633. self.progress = 1
  634. end
  635. function Dialogue:advance()
  636. if (self.progress >= table.maxn(self.messages)) then
  637. self.progress = 1
  638. self:uninstall()
  639. else
  640. self.progress = self.progress + 1
  641. -- ASSUMING “DO” WILL BE ALONE EVER ONLY
  642. if (self.messages[self.progress].act ~= nil) then
  643. self.messages[self.progress].act()
  644. self:advance()
  645. end
  646. end
  647. end
  648. function Dialogue:install()
  649. local functions = {
  650. ["update"] = { ["func"] = function (t) self:update(t) end,
  651. ["combine"] = false },
  652. ["draw"] = { ["func"] = function () self:draw() end,
  653. ["combine"] = true },
  654. ["keypressed"] = { ["func"] = function (key) self:keypressed(key) end,
  655. ["combine"] = false },
  656. ["keyreleased"] = { ["func"] = function (key) self:keyreleased(key) end,
  657. ["combine"] = false }
  658. }
  659. add state({ ["functions"] = functions, ["name"] = "interparolo" })
  660. end
  661. function Dialogue:uninstall()
  662. remove state("interparolo")
  663. end
  664. function Dialogue:update(t)
  665. return nil
  666. end
  667. function Dialogue:draw()
  668. window width, window height = love.graphics.getDimensions()
  669. -- wife = getRandomWife()
  670. -- wife.husband:die()
  671. -- widow width, widow height = wife.graphics.getDimensions()
  672. -- oh noooooo xD
  673. msg frame width = window width - 32
  674. msg frame height = window height / 2 - 32
  675. msg frame x = 16 + camera.x - window width / 2
  676. msg frame y = (window height / 2 + 16) + camera.y - window height / 2
  677. msg width = (msg frame width - (frame line * 3)) / 2
  678. -- Ni duonigas, ĉar ni duobligos grandecon de teksto (kaj ties skatolo).
  679. name frame width = 306
  680. name frame height = 64
  681. name frame x = msg frame x + 48
  682. name frame y = msg frame y - name frame height + frame line -- to merge borders.
  683. name width = (name frame width - (frame line * 3)) / 2
  684. -- Ni duonigas, ĉar ni duobligos grandecon de teksto (kaj ties skatolo).
  685. draw frame(msg frame x, msg frame y,
  686. msg frame width, msg frame height)
  687. draw frame(name frame x, name frame y,
  688. name frame width, name frame height)
  689. love.graphics.printf(self.messages[self.progress].msg, p_ttf,
  690. msg frame x + (frame line * 3),
  691. msg frame y + (frame line * 2),
  692. msg width, "left", 0, 2, 2)
  693. love.graphics.setColor(1, 1, 0.5)
  694. love.graphics.printf(self.messages[self.progress].name, p_ttf,
  695. name frame x + (frame line * 3),
  696. name frame y + (frame line * 2),
  697. name width, "left", 0, 2, 2)
  698. love.graphics.setColor(1, 1, 1)
  699. end
  700. function Dialogue:keypressed(key)
  701. if (key == "return" or key == "space") then
  702. self:advance()
  703. end
  704. end
  705. function Dialogue:keyreleased(key)
  706. return nil
  707. end
  708. -- You’re the keeper of the seven keys
  709. -- THING
  710. ----------------------------------------
  711. Thing = class("Thing")
  712. function Thing:initialize(name)
  713. self.name = name
  714. end
  715. function Thing:kill()
  716. for k,thing in pairs(currentRoom.things) do
  717. if (thing.name == self.name) then
  718. print("MORTINTA")
  719. table.remove(currentRoom.things, k)
  720. end
  721. end
  722. local objlayer = currentRoom.map.layers["Aĵoj"]
  723. for k,obj in pairs(objlayer.objects) do
  724. if (obj.properties["aĵo"] == self.name) then
  725. table.remove(objlayer.objects, k)
  726. currentRoom.map:setObjectData(objlayer)
  727. currentRoom:reload tiles()
  728. print("MURDITA")
  729. end
  730. end
  731. end
  732. function Thing:interact(interacter)
  733. print("owo")
  734. end
  735. -- Install the important 'hook' functions (draw, update, keypressed/released)
  736. -- If any of the 'old' functions passed are not nil, then both the new and
  737. -- old will be added into the new corresponding hook function
  738. -- This function is too god damn long and it makes me want to cry
  739. -- Could be pretty easily shortened, now that I think about it
  740. -- ne mallongigu, suferu
  741. --[[ Miaj pensoj // Tirifto, 2021 // Lua-pens-eldonejo Snopyta, Berlino
  742. Jes ja, kiel estas nune,
  743. oni povus havi ĉiean funkciaron,
  744. al kiu, laŭ sia bezono,
  745. oni funkciojn novajn donus.
  746. Tamen, por priparoli pli klare,
  747. tion al kio celis originale mia mens’,
  748. mi volus diri kelkajn pliajn vortojn,
  749. … .
  750. Esence oni priskribus atendatan konduton de la ludo
  751. per tiel-nomeblaj »statoj«, kiuj povus esti propraj
  752. objektoj.
  753. Ekzemple, la ordinara ludo de stato prezentus tian
  754. konduton, ke ludato moviĝus je premo kaj klavo, kaj
  755. la mondo ordinare ĝisdatiĝus.
  756. Male, povus ekzisti ankaŭ la menua stato aŭ aliaj statoj,
  757. kiuj kondutigus la tutan ludon alimaniere. Ni ankoraŭ devus
  758. registri tiujn statojn per iu ĉiea tabelo.
  759. Kiam ek-funkcius nova stato, ĝi simple aldoniĝus al la tabelo –
  760. ĝi devus aŭ anstataŭigi la antaŭajn tieajn statojn, aŭ indiki,
  761. ke dum ĝia ĉeesto, la konduto de la aliaj statoj tieaj devas
  762. esti malatentata.
  763. La rezulto devus esti la sama kiel ĉe la nuna uzata/proponata
  764. sistemo, kie oni rekte ŝanĝas funkciojn. La diferenco de ĉi tiu
  765. ideo/propono estas, ke oni ne traktas rekte funkciojn, sed rilataj
  766. funkcioj estas enmetitaj en statoj, kaj oni traktas rekte nur statojn
  767. (kaj nerekte do ankaŭ ties funkciojn).
  768. La motivo de tia sistemo estas, ke okupiĝi nur pri po unu stato ĉiufoje
  769. povus esti pli facile/klare, ol okupiĝi pri pluraj funkcioj. Sed ankaŭ
  770. eblas, ke la aldona tavolo de objekto-volvado pli malsimpligus la logikon
  771. de la kodo.
  772. Reĝimoj:
  773. • Ordinara ludo
  774. • Ĉefmenuo
  775. • Ludmenuo
  776. • Batalo
  777. • Parolado
  778. • Interago
  779. perl -ine 's/stat/reĝim' 'menso de Ĵado.cpp'
  780. --]]
  781. -- GAME OBJCTS
  782. --------------------------------------------------------------------------------
  783. -- INTERPAROLOJ
  784. -------------------
  785. prova interparolo = Dialogue:new({
  786. {name = "La profeta pingveno",
  787. msg = "Brittle are your feathers, vitreous duck, vitreous duck."},
  788. {name = "La profeta pingveno",
  789. msg = "Won’t you try and fly over the vale?"},
  790. {name = "La profeta pingveno",
  791. msg = "Yes, if you walked, you’d be caught and meet your end for sure. "
  792. .. "And if you fall, your fate won’t be of those any better than that."},
  793. {name = "La profeta pingveno",
  794. msg = "But maybe, just maybe your wings can carry you across this valley, "
  795. .. "and perhaps there you can finally be happy, "
  796. .. "vitreous duck, vitreous duck."},
  797. {name = "La profeta pingveno",
  798. msg = "Will you take this flight?"},
  799. {act = function() prova elekto:install() end}
  800. })
  801. --[[--
  802. prova elekto = Gourmet Menu:new({
  803. { "Yes",
  804. function() prova elekto jes:install() end },
  805. { "Who the $%!@ are you?!",
  806. function() prova elekto kiu:install() end },
  807. { "No",
  808. function() prova elekto ne:install() end }
  809. })
  810. prova elekto jes = Dialogue:new({
  811. {name = "Vitreca anaso",
  812. msg = "Yeah, I might as well give it a try. Quack quack."},
  813. {name = "La profeta pingveno",
  814. msg = "May the winds caress you ever so gently, "
  815. .. "vitreous duck, vitreous duck."}
  816. })
  817. prova elekto kiu = Dialogue:new({
  818. {name = "Vitreca anaso",
  819. msg = "Who the $%!@ are you?! Like, even? Quack quack."},
  820. {name = "La profeta pingveno",
  821. msg = "Let’s see…"},
  822. {name = "La profeta pingveno",
  823. msg = "“La profeta pingveno”, apparently."},
  824. {name = "Vitreca anaso",
  825. msg = "What the $%!@ did you just $%!@ing say about me, you little $%!@? "
  826. .. "I’ll have you know I graduated top of my class in the Navy "
  827. .. "Ducks, and I’ve been involved in numerous secret raids on "
  828. .. "Al-Quackeda, and I have over 69 confirmed quacks. Quack quack."}
  829. })
  830. prova elekto ne = Dialogue:new({
  831. {name = "Vitreca anaso",
  832. msg = "Nah, that’s like, way up high, dude. Quack quack."},
  833. {name = "La profeta pingveno",
  834. msg = "git gud lol" },
  835. {name = "La profeta pingveno",
  836. msg = "…vitreous duck, vitreous duck."}
  837. })
  838. -- Kun neceseja seĝo
  839. ---------
  840. elekto s = Gourmet Menu:new({
  841. { "Flush the toilet",
  842. function() elekto fluigi:install() end },
  843. { "Step aside",
  844. function() elekto forpaŝi:install() end },
  845. { "Use plunger for its intended purpose",
  846. function() elekto malŝtopi:install() end },
  847. })
  848. fluigi = Dialogue:new({
  849. {name = "Johan Mojos",
  850. msg = "This ought to fix it!"},
  851. {name = "Toilet",
  852. msg = "Shhhhhhhhhhhhhhhhhhh… glrblgrblrgbl… “help…” shhhhhhhhh."},
  853. {name = "Narrator",
  854. msg = "Having flushed the toilet, Johan saw that all was well once again."},
  855. {name = "Johan Mojos",
  856. msg = "All is well once again!"},
  857. {act = function () end} -- flush dwarf
  858. })
  859. malŝtopi = Dialogue:new({
  860. {name = "Johan Mojos",
  861. msg = "Alright, let’s give this a try!"},
  862. {name = "Johan Mojos",
  863. msg = "Hnnnngh!"},
  864. {name = "Narrator",
  865. msg = "With great effort, Johan plunged the plunger deep into the toilet, "
  866. .. "utilising all of his strength to try and remove whichever of the "
  867. .. "many things that exist in our world and could possibly clog "
  868. .. "a toilet while disturbing the surface has actually gone and done "
  869. .. "just that."},
  870. {name = "Johan Mojos",
  871. msg = "HAAAARGHHH!!!"},
  872. {name = "Toilet",
  873. msg = "AAAAAAAAAAAAAAAHHHHHHHHHHHHH!!!"},
  874. {name = "Narrator",
  875. msg = "It was a fierce battle, a battle of muscle and will, a battle "
  876. .. "between good and evil, human and nature, man and toilet."},
  877. {name = "Narrator",
  878. msg = "But at last, the side on which stood our hero, alone, carrying "
  879. .. "the sentiments of all the good people on this planet on his "
  880. .. "shoulders, has emerged victorious, when with one last mighty pull, "
  881. .. "the bowl has been reclaimed."},
  882. {name = "Johan Mojos",
  883. msg = "Glory to humankind! Vive la ventouse !"},
  884. {act = function () end} -- make dwarf
  885. })
  886. -- Kun gnomo
  887. ---------
  888. -- Kun malŝtopilo
  889. ---------
  890. -- Kun duŝangulo
  891. ---------
  892. --]]--
  893. -- MENUOJ
  894. -------------------
  895. function ĉefmenuo()
  896. return Main Menu:new({
  897. { "New Game",
  898. function () remove state("menuo"); end },
  899. { "Useless Choice",
  900. function () print "It has no use, seriously!" end },
  901. { "Exit",
  902. function () love.event.quit(0) end },
  903. })
  904. end
  905. -- ĈAMBROJ
  906. -------------------
  907. Domo = class("Domo", Room)
  908. function Domo:initialize(door id)
  909. Room.initialize(self, "maps/Domo.lua", door id)
  910. self:install character(Fremdulo:new("art/dwarf.lua", "fremdulo"))
  911. self:install character(Malŝtopilo:new("art/plunger.lua", "malŝtopilo"))
  912. self:install thing(Neceseja seĝo:new("neceseja seĝo"))
  913. self:install thing(Duŝangulo:new("duŝangulo"))
  914. self:install thing(Librobretaro:new("librobretaro"))
  915. self:install thing(Pordo a:new("pord1"))
  916. self:install thing(Pordo b:new("pord2"))
  917. self:install thing(Mia Lito:new("mia lito"))
  918. self:install thing(Lia Lito:new("lia lito"))
  919. end
  920. Fremdulo = class("Fremdulo", Character)
  921. function Fremdulo:interact(interactor)
  922. local fight = Fight:new({interactor}, {self})
  923. fight:install()
  924. end
  925. Dwarf = class("Dwarf", Character)
  926. function Dwarf:initialize(sprite, name)
  927. print("DWARF INITIALIZEDD")
  928. self.thanked = false
  929. Character.initialize(self, sprite, name)
  930. end
  931. function Dwarf:interact(interacter)
  932. self.dialogues = {
  933. start = Dialogue:new({
  934. {name = "Dwarf",
  935. msg = "At last, I have been freed! Thank you, kind stranger, who, judging "
  936. .. "by your adventurous yet somehow casual attire, and your presence "
  937. .. "here, as well as the act of benevolence you have carried out in "
  938. .. "pulling me out, also happens to be the owner of the toilet in "
  939. .. "which, by a stroke of extraordinary misfortune, I have found "
  940. .. "myself."},
  941. {act = function () self.dialogues["react"]:install() end}
  942. }),
  943. react = Gourmet Menu:new({
  944. { "You are very welcome.",
  945. function() self.dialogues["polite"]:install() end },
  946. { "The hell, dude?",
  947. function() self.dialogues["explain"]:install() end },
  948. { "A $%!@ dwarf?! Where’s the elf?!",
  949. function() self.dialogues["fight"]:install() end }
  950. }),
  951. polite = Dialogue:new({
  952. {name = "Dwarf",
  953. msg = "Honestly, sir, I can’t possibly find enough words to express my "
  954. .. "gratitude. I thought for sure that I was a goner. We dwarves "
  955. .. "can hold our breath for a good while , but we can’t do it forever. "
  956. .. "Much less in a toilet, I’ll tell you that!"},
  957. {name = "Johan Mojos",
  958. msg = "Well, alright, but how did you get in there in the first place?"},
  959. {act = function () self.dialogues["explain"]:install() end}
  960. }),
  961. explain = Dialogue:new({
  962. {name = "Dwarf",
  963. msg = "It was a cold but peaceful night, when the one whose name must not "
  964. .. "be spoken set out with his sleigh once again, as he does every "
  965. .. "year."},
  966. {name = "Johan Mojos",
  967. msg = "Who’s the one whose name must not be spoken?"},
  968. {name = "Dwarf",
  969. msg = "Santa Claus."},
  970. {name = "Dwarf",
  971. msg = "…ah, curses. Well, anyway…"},
  972. {name = "Dwarf",
  973. msg = "On that night, he would travel the land and climb into every "
  974. .. "chimney he’d laid his fiery eyes on, in order to collect the "
  975. .. "yearly offerings of milk and cookies. Everyone is told to make them, "
  976. .. "and everyone obeys, save for the few exceptions."},
  977. {name = "Dwarf",
  978. msg = "As it turns out, your humble household has been one such exception "
  979. .. "this year. Santa came here, oh yes he did, and when he saw that "
  980. .. "the milk and the cookies were not, his rage cracked the earth! "
  981. .. "That's how that giant rift outside your house was made, by the way."},
  982. {name = "Johan Mojos",
  983. msg = "There’s a giant rift outside our house?!"},
  984. {name = "Dwarf",
  985. msg = "Yeah! You didn’t know? You should be heading out more often."},
  986. {name = "Johan Mojos",
  987. msg = "In case you’re not aware, we’ve been completely snowed up in here "
  988. .. "for a couple of days. We literally can’t get out."},
  989. {name = "Dwarf",
  990. msg = "Oh right. About that…"},
  991. {name = "Dwarf",
  992. msg = "When Santa got back to the secret floating iceberg base which now "
  993. .. "hovers right outside your house, he—"},
  994. {name = "Johan Mojos",
  995. msg = "There’s a floating iceberg base outside our house?!"},
  996. {name = "Dwarf",
  997. msg = "Yeah, a secret floating iceberg base! You didn’t know? You should—"},
  998. {name = "Johan Mojos",
  999. msg = "Please continue."},
  1000. {name = "Dwarf",
  1001. msg = "Ah, right. So, as soon as he got back, he has decided to punish "
  1002. .. "you. He made a really menacing gesture, like this—"},
  1003. {name = "Narrator",
  1004. msg = "The dwarf has made a gesture so menacing and terrifying that it’s "
  1005. .. "probably better you don’t even imagine it, hence why I won’t "
  1006. .. "be describing it here in great and greatly unsettling detail."},
  1007. {name = "Dwarf",
  1008. msg = "—and then he conjured up a great snowstorm on your house, covering "
  1009. .. "it in snow and trapping you inside! He then sent us—the dwarves—"
  1010. .. "inside through the chimney, so that we would punish you in case "
  1011. .. "you didn’t repent and make the sacrifice of milk and cookies, "
  1012. .. "plus interest."},
  1013. {name = "Johan Mojos",
  1014. msg = "Wait—I thought Santa was working with elves, not dwarves?"},
  1015. {name = "Dwarf",
  1016. msg = "Oh, that’s a common misconception. Us dwarves, we are sturdier and "
  1017. .. "better suited to hard work in a toy factory. Elves wouldn’t be "
  1018. .. "able to last that long, trust me."},
  1019. {name = "Johan Mojos",
  1020. msg = "Not cool, dude. But wait—did you say there were more dwarves "
  1021. .. "around?"},
  1022. {name = "Dwarf",
  1023. msg = "More of us were tossed down here, yes, but I think I was the only "
  1024. .. "one to hit the chimney right. The others probably didn’t make it "
  1025. .. "this far. Rest in peace, Preston, Blackbeard, Arnold, "
  1026. .. "Schwarzenegger…"},
  1027. {name = "Johan Mojos",
  1028. msg = "Fear not, friend! Their deaths shall be avenged!"},
  1029. {name = "Dwarf",
  1030. msg = "Truly? You will take justice into your hands, as if it were "
  1031. .. "a plunger?"},
  1032. {name = "Johan Mojos",
  1033. msg = "I will!"},
  1034. {name = "Johan Mojos",
  1035. msg = "Well, maybe not right now, since there’s only so much you can put "
  1036. .. "in the game in only a week, at least when you’re not all that "
  1037. .. "sure what the heck are you even doing, but one day, one day I hope "
  1038. .. "I will!"},
  1039. {name = "Narrator",
  1040. msg = "And that’s all, folks! Thank you for playing!"},
  1041. {act = function () print("You win! Well, sort of. Congratulations!")
  1042. love.event.quit(0) end}
  1043. }),
  1044. fight = Dialogue:new({
  1045. {name = "Dwarf",
  1046. msg = "What? An elf! I ain’t no elf! That your problem, mate? Well I have "
  1047. .. "just the right tool to solve this problem for you forever right "
  1048. .. "here. Guess what, it’s my axe!"},
  1049. {name = "Johan Mojos",
  1050. msg = "I won’t go down without a fight! If you want to cut me down, you’ll "
  1051. .. "have to cut down my plunger first, the very instrument that is "
  1052. .. "so powerful it has freed you from your toilety confines!"},
  1053. {name = "Dwarf",
  1054. msg = "Enough talking! En garde !"},
  1055. {name = "Johan Mojos",
  1056. msg = "Elf yourself!"},
  1057. {name = "Narrator",
  1058. msg = "And so, the two brave warriors have crossed their weapons of "
  1059. .. "choice, engaging in yet another thrilling clash of arms, wills, "
  1060. .. "but above all, ideas."},
  1061. {name = "Narrator",
  1062. msg = "Is it elves who are meant to find thems-elves stuck in toilets soon "
  1063. .. "after the Christmas festivities, should it so happen that some "
  1064. .. "beings do get stuck in there? Or is this something the dwarves "
  1065. .. "may do as well?"},
  1066. {name = "Narrator",
  1067. msg = "After a long and exhausting battle, a finishing blow is dealt by "
  1068. .. "each one of the two opposing forces, leading to a draw."
  1069. .. "Today, the questions we had remain unanswered, yet two digital lives "
  1070. .. "go to waste."},
  1071. {name = "Narrator",
  1072. msg = "A great tragedy? Perhaps. A great disappointment? Certainly."},
  1073. {name = "Narrator",
  1074. msg = "Rest in peace, brave warriors."},
  1075. {act = function () interacter:kill() ; self:kill() end}
  1076. })
  1077. }
  1078. self.dialogues["start"]:install()
  1079. end
  1080. Malŝtopilo = class("Malŝtopilo", Character)
  1081. function Malŝtopilo:interact(interacter)
  1082. local elekto morti = Dialogue:new({
  1083. {name = "Johan Mojos",
  1084. msg = "I don’t plan on just sitting around in here until we run out of "
  1085. .. "food and starve to death. Desperate times call for desperate "
  1086. .. "actions!"},
  1087. {name = "Johan Mojos",
  1088. msg = "If I’m going down, I may as well go down with all the style and "
  1089. .. "grandeur worthy of both me and this plunger right here."},
  1090. {name = "Johan Mojos",
  1091. msg = "Behold! Let the world marvel at my final stunt!"},
  1092. {name = "Narrator",
  1093. msg = "On saying that, Johan firmly grasped the plunger with both of "
  1094. .. "his hands, and unclogged himself in a manner too graphic "
  1095. .. "to be put into words suited to anyone’s eyes."},
  1096. {name = "Narrator",
  1097. msg = "Please do NOT try this at home. Ever."},
  1098. {act = function () interacter:kill() self:kill() end }
  1099. })
  1100. local elekto = Gourmet Menu:new({
  1101. { "Take the plunger",
  1102. function() interacter:take(self) end },
  1103. { "Don’t take the plunger",
  1104. function() end },
  1105. { "Plunge into death’s embrace",
  1106. function() elekto morti:install() end }
  1107. })
  1108. local main = Dialogue:new({
  1109. {name = "Johan Mojos",
  1110. msg = "This is a plunger we own."},
  1111. {name = "Johan Mojos",
  1112. msg = "It is quite the plunger, honestly! Big and sturdy, I like it. "
  1113. .. "It could probably pull an elf right out of a toilet!"},
  1114. {name = "Johan Mojos",
  1115. msg = "Not like I’m trying to drop any hints here. "
  1116. .. "Just kinda thought it would be good for that sorta thing. "
  1117. .. "Y’know. Hypothetically speaking."},
  1118. {act = function () elekto:install() end}
  1119. })
  1120. main:install()
  1121. end
  1122. Duŝangulo = class("Duŝangulo", Thing)
  1123. function Duŝangulo:initialize(name)
  1124. self.deathcount = 1
  1125. self.should die = false
  1126. self.dialogues = {
  1127. [1] = Dialogue:new({
  1128. {name = "Johan Mojos",
  1129. msg = "This is our shower stall. We take our showers in there."},
  1130. {name = "Johan Mojos",
  1131. msg = "Right now, it looks like there’s a serial killer hiding in there, "
  1132. .. "so I don’t really want to go inside."},
  1133. {act = function () self.deathcount = 2 end}
  1134. }),
  1135. [2] = Dialogue:new({
  1136. {name = "Johan Mojos",
  1137. msg = "No, seriously. I’m not going in there. There’s no way it’s going to "
  1138. .. "end well for me."},
  1139. {act = function () self.deathcount = 3 end}
  1140. }),
  1141. [3] = Dialogue:new({
  1142. {name = "Johan Mojos",
  1143. msg = "What would you do if there was a serial killer hiding in your "
  1144. .. "stall, huh? I bet you wouldn’t want to join per, either."},
  1145. {act = function () self.deathcount = 4 end}
  1146. }),
  1147. [4] = Dialogue:new({
  1148. {name = "Johan Mojos",
  1149. msg = "In case you’re wondering why don’t we run or call the police… "
  1150. .. "well, in case you haven’t noticed, we’re completely snowed up "
  1151. .. "in here!"},
  1152. {act = function () self.deathcount = 5 end}
  1153. }),
  1154. [5] = Dialogue:new({
  1155. {name = "Johan Mojos",
  1156. msg = "I mean, the killer does look pretty harmless like this. As long "
  1157. .. "as we don’t open the stall, we should be perfectly fine!"},
  1158. {act = function () self.deathcount = 6 end}
  1159. }),
  1160. [6] = Dialogue:new({
  1161. {name = "Johan Mojos",
  1162. msg = "You know what? Maybe I will open the stall. It doesn’t seem like "
  1163. .. "such a terrible idea, all things considered."},
  1164. {act = function () self.deathcount = 7 ; self.should die = true end}
  1165. }),
  1166. [7] = Dialogue:new({
  1167. {name = "Johan Mojos",
  1168. msg = "Yeah! What’s the worst that could possibly happen?"},
  1169. {name = "Narrator",
  1170. msg = "The worst that could possibly happen was being murdered in cold "
  1171. .. "blood by the serial killer. That is also exactly what happened."},
  1172. {name = "Narrator",
  1173. msg = "On commiting that atrocious crime, the serial killer went into "
  1174. .. "the kitchen, made perself a cup of tea, and drank it all whilst "
  1175. .. "relishing the newly gained tranquility of the place."},
  1176. {name = "Narrator",
  1177. msg = "The nerve!"}
  1178. })
  1179. }
  1180. Thing.initialize(self, name)
  1181. end
  1182. function Duŝangulo:interact(interacter)
  1183. self.dialogues[self.deathcount]:install()
  1184. if (self.should die == true) then
  1185. interacter:kill()
  1186. end
  1187. end
  1188. Neceseja seĝo = class("Neceseja seĝo", Thing)
  1189. function Neceseja seĝo:initialize(name)
  1190. self.malŝtopita = false
  1191. self.next = "start"
  1192. Thing.initialize(self, name)
  1193. end
  1194. function Neceseja seĝo:interact(interacter)
  1195. self.dialogues = {
  1196. start = Dialogue:new({
  1197. {name = "Johan Mojos",
  1198. msg = "This is our toilet. Nothing to see here. Or at least I hope so."},
  1199. {name = "Toilet",
  1200. msg = "Blgh blrgh blurb blrgh blurb."},
  1201. {name = "Johan Mojos",
  1202. msg = "Actually, hold on. There are… strange sounds coming out of it. "
  1203. .. "The surface looks kinda shaky, too… I don’t like this."},
  1204. {act = function ()
  1205. if (interacter.has plunger == true) then
  1206. self.dialogues["plungep"]:install()
  1207. else
  1208. self.dialogues["flushp"]:install()
  1209. end
  1210. end}
  1211. }),
  1212. flushp = Gourmet Menu:new({
  1213. { "Flush the toilet",
  1214. function() self.dialogues["flush"]:install() end },
  1215. { "Step aside",
  1216. function() return nil end }
  1217. }),
  1218. plungep = Gourmet Menu:new({
  1219. { "Flush the toilet",
  1220. function() self.dialogues["flush"]:install() end },
  1221. { "Step aside",
  1222. function() return nil end },
  1223. { "Use plunger for its intended purpose",
  1224. function() self.dialogues["plunge"]:install() end }
  1225. }),
  1226. flush = Dialogue:new({
  1227. {name = "Johan Mojos",
  1228. msg = "This ought to fix it!"},
  1229. {name = "Toilet",
  1230. msg = "Shhhhhhhhhhhhhhhhhhh… glrblgrblrgbl… “help…” shhhhhhhhh."},
  1231. {name = "Narrator",
  1232. msg = "Having flushed the toilet, Johan saw that all was well once again."},
  1233. {name = "Johan Mojos",
  1234. msg = "All is well once again!"},
  1235. {act = function () self.next = "empty" end} -- flush dwarf
  1236. }),
  1237. empty = Dialogue:new({
  1238. {name = "Johan Mojos",
  1239. msg = "This is our toilet. Nothing to see here. I made sure of that myself!"}
  1240. }),
  1241. plunge = Dialogue:new({
  1242. {name = "Johan Mojos",
  1243. msg = "Alright, let’s give this a try!"},
  1244. {name = "Johan Mojos",
  1245. msg = "Hnnnngh!"},
  1246. {name = "Narrator",
  1247. msg = "With great effort, Johan plunged the plunger deep into the toilet, "
  1248. .. "utilising all of his strength to try and remove whichever of the "
  1249. .. "many things that exist in our world and could possibly clog "
  1250. .. "a toilet while disturbing the surface has actually gone and done "
  1251. .. "just that."},
  1252. {name = "Johan Mojos",
  1253. msg = "HAAAARGHHH!!!"},
  1254. {name = "Toilet",
  1255. msg = "AAAAAAAAAAAAAAAHHHHHHHHHHHHH!!!"},
  1256. {name = "Narrator",
  1257. msg = "It was a fierce battle, a battle of muscle and will, a battle "
  1258. .. "between good and evil, human and nature, man and toilet."},
  1259. {name = "Narrator",
  1260. msg = "But at last, the side on which stood our hero, alone, carrying "
  1261. .. "the sentiments of all the good people on this planet on his "
  1262. .. "shoulders, has emerged victorious, when with one last mighty pull, "
  1263. .. "the bowl has been reclaimed."},
  1264. {name = "Johan Mojos",
  1265. msg = "Glory to humankind! Vive la ventouse !"},
  1266. {act = function ()
  1267. local dwarf = Dwarf:new("art/dwarf.lua", "gnomo")
  1268. currentRoom:install character(dwarf)
  1269. self.next = "saved"
  1270. end} -- make dwarf
  1271. }),
  1272. saved = Dialogue:new({
  1273. {name = "Johan Mojos",
  1274. msg = "This is our toilet. Nothing to see here, save for the occasional dwarf."}
  1275. })
  1276. }
  1277. self.dialogues[self.next]:install()
  1278. end
  1279. Librobretaro = class("Librobretaro", Thing)
  1280. function Librobretaro:initialize(name)
  1281. self.deathcount = 1
  1282. self.should die = false
  1283. self.dialogues = {
  1284. [1] = Dialogue:new({
  1285. {name = "Johan Mojos",
  1286. msg = "This is our bookcase. I don't like reading, I prefer to rub paper all over me. "
  1287. .. "Paper’s super healthy for the skin."},
  1288. {name = "Johan Mojos",
  1289. msg = "But I'm not really in the mood right now." },
  1290. {act = function () self.deathcount = 2 end}
  1291. }),
  1292. [2] = Dialogue:new({
  1293. {name = "Johan Mojos",
  1294. msg = "What? Do you want me to read or something? "},
  1295. {name = "Johan Mojos",
  1296. msg = "No. It's bad for you― look at what it's done to Koĥek."},
  1297. {name = "Johan Mojos",
  1298. msg = "Poor bastard."},
  1299. {act = function () self.deathcount = 3 end}
  1300. }),
  1301. [3] = Dialogue:new({
  1302. {name = "Johan Mojos",
  1303. msg = "Seriously, I'm not doing it. I refuse."},
  1304. {act = function () self.deathcount = 4 end}
  1305. }),
  1306. [4] = Dialogue:new({
  1307. {name = "Johan Mojos",
  1308. msg = "I really don't want to. Please. I'm begging here." },
  1309. {act = function () self.deathcount = 5 end}
  1310. }),
  1311. [5] = Dialogue:new({
  1312. {name = "Johan Mojos",
  1313. msg = "… Maybe I've got it wrong? After all, what harm can paper do? It's so smooth!" },
  1314. {act = function () self.deathcount = 6 end}
  1315. }),
  1316. [6] = Dialogue:new({
  1317. {name = "Johan Mojos",
  1318. msg = "Alright, time to die of boredom. " },
  1319. {name = "Narrator",
  1320. msg = "What a fitting set of last words that makes."},
  1321. {name = "Narrator",
  1322. msg = "Having never read more than a few sentences in his life, Johan" ..
  1323. "hasn't built up the stamina required to read an entire book."},
  1324. {name = "Narrator",
  1325. msg = "Johan is an unfortunate victim of boredom-induced coma, from which he is unlikely to recover."},
  1326. {act = function () self.deathcount = 7 ; interacter:kill()ll() end} })
  1327. }
  1328. Thing.initialize(self, name)
  1329. end
  1330. function Librobretaro:interact(interacter)
  1331. print("ASLKDJASDLKASDJLKASJDLAKSJDLKASJDLAKSJDA")
  1332. self.dialogues[self.deathcount]:install()
  1333. if (self.should die == true) then
  1334. interacter:kill()
  1335. end
  1336. end
  1337. Pordo a = class("Pordo a", Thing)
  1338. function Pordo a:interact(interacter)
  1339. local dialogue = Dialogue:new({
  1340. {name = "Johan Mojos",
  1341. msg = "What a fine door! Even under such pressure, it refuses to break." },
  1342. {name = "Johan Mojos",
  1343. msg = "Doors of such bravery are hard to come by." },
  1344. {name = "John Mojos",
  1345. msg = "Probably shouldn't open it, though. There *are* a few meters of snow outside."}
  1346. })
  1347. dialogue:install()
  1348. end
  1349. Pordo b = class("Pordo b", Thing)
  1350. function Pordo b:interact(interacter)
  1351. local dialogue = Dialogue:new({
  1352. {name = "Johan Mojos",
  1353. msg = "I wonder if we're still snowed in." },
  1354. {name = "Johan Mojos",
  1355. msg = "Maybe I should open the door, just to check."},
  1356. {name = "Johan Mojos",
  1357. msg = "… On second thought, maybe it's best to let sleeping dogs lye." },
  1358. })
  1359. dialogue:install()
  1360. end
  1361. Komputilo = class("Komputilo", Thing)
  1362. function Komputilo:interact(interacter)
  1363. local dialogue = Dialogue:new({
  1364. {name = "Johan Mojos",
  1365. msg = "It's my room-mate's computer. He leaves it on all the time, for some reason."},
  1366. {name = "Johan Mojos",
  1367. msg = "As tempting as this might normally be, Koĥek's a bit of a fruitcake: Generally, sure, but also specifically right here."},
  1368. {name = "John Mojos",
  1369. msg = "He uses an anime girl mouse pad. I'll pass."}
  1370. })
  1371. dialogue:install()
  1372. end
  1373. Mia Lito = class("Mia Lito", Thing)
  1374. function Mia Lito:interact(interacter)
  1375. local dialogue = Dialogue:new({
  1376. {name = "Johan Mojos",
  1377. msg = "My wonderful, wonderful bed. How many precious nights have I let slip through my fingers, thanks to this thing?"},
  1378. {name = "Johan Mojos",
  1379. msg = "Quite a few, actually. I hate it."}
  1380. })
  1381. dialogue:install()
  1382. end
  1383. Lia Lito = class("Lia Lito", Thing)
  1384. function Lia Lito:interact(interacter)
  1385. local dialogue = Dialogue:new({
  1386. {name = "Johan Mojos",
  1387. msg = "Here's Koĥek's bed. I'll admit, it looks well-kept, but I still don't trust it. What a strange guy."},
  1388. {name = "Johan Mojos",
  1389. msg = "I'm watching you, bed. Just you wait."}
  1390. })
  1391. dialogue:install()
  1392. end
  1393. -- BATALSISTEMO :bear: :bee: :sweat: :100:
  1394. --------------------------------------------------------------------------------
  1395. -- BATALO
  1396. -------------------
  1397. Fight = class("Fight")
  1398. --
  1399. -- | Johan Mojos
  1400. -- | Mojos Koĥek
  1401. -- |
  1402. -- o O
  1403. -- -2 1 0 1 2
  1404. --
  1405. -- [o] [o]
  1406. -- | |
  1407. -- | [O]
  1408. -- [O] | 3
  1409. --
  1410. function Fight:initialize(friends, enemies, friend side, enemy side)
  1411. self.fighters = {}
  1412. local amikflanko = -2
  1413. local malamikflanko = 2
  1414. if (friend side ~= nil) and (friend side == RIGHT) then
  1415. amikflanko = 2
  1416. malamikflanko = -2
  1417. end
  1418. new camera()
  1419. for k,player in pairs(friends) do
  1420. local fighter = nil
  1421. if (player.name == "ludato") then
  1422. fighter = PlayerFighter:new(player, self, amikflanko)
  1423. else
  1424. fighter = Fighter:new(player, self, amikflanko)
  1425. end
  1426. self:install fighter(fighter)
  1427. end
  1428. for k,cpu in pairs(enemies) do
  1429. local fighter = Fighter:new(cpu, self, malamikflanko)
  1430. self:install fighter(fighter)
  1431. end
  1432. end
  1433. -- install state (A) :-(
  1434. function Fight:install()
  1435. local functions = {
  1436. ["update"] = { ["func"] = function (t) self:update(t) end, ["combine"] = false },
  1437. ["draw"] = { ["func"] = function (t) self:draw() end, ["combine"] = false }
  1438. }
  1439. add state({["functions"] = functions, ["name"] = "batalo"})
  1440. camera = stalker() -- Dependaĵoj: retfilmilo
  1441. camera:setFollowStyle('TOPDOWN')
  1442. end
  1443. -- -2 -1 0 1 2
  1444. -- 13 ←→
  1445. -- ?? mistere ↑↓ ? :w:
  1446. -- [-2 ] [-1 ] [ 0 ] [ 1 ] [ 2 ]
  1447. -- A Ŭ
  1448. -- [-2 ] [-1 ] [ 0 ] [ 1 ] [ 2 ] - vico 1
  1449. -- [-2 ] [-1 ] [ 0 ] [ 1 ] [ 2 ] - vico 2
  1450. -- [-2 ] [-1 ] [ 0 ] [ 1 ] [ 2 ] - vico 3
  1451. function Fight:install fighter(fighter)
  1452. if (self.fighters == nil) then self.fighters = {} end
  1453. print("INSTALANTE")
  1454. table.insert(self.fighters, fighter)
  1455. end
  1456. function Fight:update(t)
  1457. camera:update(t)
  1458. for k,fighter in pairs(self.fighters) do
  1459. print(k)
  1460. fighter:update(t)
  1461. end
  1462. end
  1463. function Fight:draw()
  1464. for k,fighter in pairs(self.fighters) do
  1465. fighter:draw()
  1466. end
  1467. end
  1468. -- BATALANTO -- o/\o Saluton!
  1469. -------------------
  1470. Fighter = class("Fighter")
  1471. function Fighter:initialize(character, fight, location)
  1472. self.animation = LoveAnimation.new("art/dwarf.lua")
  1473. self.name = character.name
  1474. self.loc = location
  1475. self.fight = fight
  1476. end
  1477. function Fighter:update(t)
  1478. print("Mi ĝisdatiĝas, kaj ", self.name, " loko estas", calc battle position(self.loc))
  1479. self.animation:setPosition(calc battle position(self.loc), 100)
  1480. self.animation:update(t)
  1481. end
  1482. function Fighter:draw()
  1483. self.animation:draw(2,2)
  1484. end
  1485. -- Takes a relative location on battlefield (-2 to 2), returns a screen position
  1486. function calc battle position(location)
  1487. return (location + 3) * 20
  1488. end
  1489. PlayerFighter = class("PlayerFighter", Fighter)
  1490. function PlayerFighter:initialize(character, fight, location)
  1491. self.name = "ludato"
  1492. Fighter.initialize(self, character, fight, location)
  1493. end
  1494. function PlayerFighter:update(t)
  1495. Fighter.update(self, t)
  1496. print("OWOWOWOWO")
  1497. camera:follow(calc battle position(self.loc), 100)
  1498. end
  1499. -- STATE MANAGEMENT -- State or mode tho
  1500. --------------------------------------------------------------------------------
  1501. -- Vi ne komprenos la teĥnikan signifon
  1502. -- Sed vi komprenos niajn sentojn
  1503. -- Por kompreni nian traktadon de reĝimoj pli bone, konsciu ĉi tion:
  1504. -- Reĝimoj estas iomete kiel ranoj.
  1505. -- Funkciostrukturo:
  1506. -- functions = { ["update"] = {["func"] = function, ["combine"] = combine?}, ["draw"] = {function, combine?},
  1507. -- ["keypressed"] = …, ["keyreleased"] = … }}
  1508. -- Tabelstrukturo:
  1509. -- state = { ["functions"] = functions, ["name"] = string }
  1510. --{ stato1, stato2 }
  1511. -- Menuo super ludo: ludo bildiĝu, poste menuo bildiĝu
  1512. -- Menuo super ludo: menuo aktualiĝu, ludo ne aktualiĝu
  1513. -- ĉinurso 🐼
  1514. function state function(func name, parameter)
  1515. local buffer o func = {}
  1516. for index,state in pairs(states) do
  1517. if (state.functions[func name] ~= nil) and (state.functions[func name].func ~= nil) then
  1518. insert element(buffer o func, state.functions[func name].func, 1)
  1519. if state.functions[func name].combine == false then break ; end
  1520. end
  1521. end
  1522. for index,func in pairs(buffer o func) do
  1523. func(parameter)
  1524. end
  1525. end
  1526. function add state(new state)
  1527. insert element(states, new state, 1)
  1528. end
  1529. function remove state(target name) -- Ⓐ
  1530. for index,state in pairs(states) do
  1531. if (state.name == target name) then -- Hurahhh /\(°v°)/\ \
  1532. print(state.name, index)
  1533. remove element(states, index)
  1534. return
  1535. end
  1536. end
  1537. end
  1538. -- UTIL
  1539. --------------------------------------------------------------------------------
  1540. function remove element(tabelo, index)
  1541. local oldtable = table.clone(tabelo)
  1542. tabelo[index] = nil
  1543. for k,v in pairs(oldtable) do
  1544. if (k > index) then
  1545. tabelo[k - 1] = v
  1546. end
  1547. end
  1548. end
  1549. function insert element(tabelo, element, index)
  1550. local oldtable = table.clone(tabelo)
  1551. for k,v in pairs(oldtable) do
  1552. if (k >= index) then
  1553. tabelo[k+1] = v
  1554. end
  1555. end
  1556. tabelo[index] = element
  1557. end
  1558. function is valid direction(number)
  1559. if (-4 <= number) and (number <= -1) then
  1560. return true
  1561. end
  1562. return false
  1563. end
  1564. function opposite direction(direction)
  1565. if (direction == UP) then return DOWN
  1566. elseif (direction == DOWN) then return UP
  1567. elseif (direction == LEFT) then return RIGHT
  1568. elseif (direction == RIGHT) then return LEFT
  1569. end
  1570. end
  1571. -- Replace the keys with the values, and vice versa
  1572. function invert table(table)
  1573. local newtable = {}
  1574. for k,v in pairs(table) do
  1575. newtable[v] = k
  1576. end
  1577. return newtable
  1578. end
  1579. function table.clone(org)
  1580. local newtable = {}
  1581. for k,v in pairs(org) do
  1582. newtable[k] = v
  1583. end
  1584. return newtable
  1585. end
  1586. function round(number)
  1587. return love.graphics.circle() -- Perfectly round.
  1588. end
  1589. -- box = { x1, y1, x2, y2 }
  1590. -- B) B) B) B)B)B)B)B)B))B
  1591. -- /\(•v•)/\ =B> =B> =B>
  1592. function are colliding(box1, box2)
  1593. return is colliding(box1, box2) or is colliding(box2, box1)
  1594. end
  1595. function is colliding(box1, box2)
  1596. local x interfrapo = ( -- Ĉu dekstra rando enas AŬ ĉu maldekstra?
  1597. (box1.x2 >= box2.x1 and box1.x2 <= box2.x2) or
  1598. (box1.x1 >= box2.x1 and box1.x1 <= box2.x2)
  1599. )
  1600. local y interfrapo = ( -- Ĉu supra rando enas AŬ ĉu malsupra?
  1601. (box1.y1 >= box2.y1 and box1.y1 <= box2.y2) or
  1602. (box1.y2 >= box2.y1 and box1.y2 <= box2.y2)
  1603. )
  1604. return (x interfrapo and y interfrapo)
  1605. end
  1606. frame line --[[the width thereof]] = 6
  1607. function draw frame(x, y, width, height)
  1608. love.graphics.setColor(1, 1, 1)
  1609. love.graphics.rectangle("fill",
  1610. x, y,
  1611. width, height)
  1612. -- This is for the outline; next we draw the inner rectangle.
  1613. love.graphics.setColor(0.4, 0.1, 0.1)
  1614. love.graphics.rectangle("fill",
  1615. x + frame line, y + frame line,
  1616. width - (frame line * 2), height - (frame line * 2))
  1617. love.graphics.setColor(1, 1, 1)
  1618. end