menusurvival.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. local g = love.graphics
  2. MenuSurvival = class()
  3. local function lerpAnimation(code, key, val)
  4. ctx.prevAnimationTransforms[code][key] = ctx.animationTransforms[code][key]
  5. ctx.animationTransforms[code][key] = math.lerp(ctx.animationTransforms[code][key] or val, val, math.min(10 * ls.tickrate, 1))
  6. end
  7. local function lerpRune(rune, key, val)
  8. ctx.survival.prevRuneTransforms[rune][key] = ctx.survival.runeTransforms[rune][key]
  9. ctx.survival.runeTransforms[rune][key] = math.lerp(ctx.survival.runeTransforms[rune][key] or val, val, math.min(10 * ls.tickrate, 1))
  10. end
  11. function MenuSurvival:init()
  12. self.geometry = setmetatable({}, {__index = function(t, k)
  13. return rawset(t, k, self.geometryFunctions[k]())[k]
  14. end})
  15. self.geometryFunctions = {
  16. minionFrame = function()
  17. local u, v = ctx.u, ctx.v
  18. return {.07 * u - v * .02, .07 * u - v * .04, self.geometry.runesFrame[3], .5 * v}
  19. end,
  20. gutter = function()
  21. local u, v = love.graphics.getDimensions()
  22. local r = .06 * v
  23. local inc = (r * 2) + .08 * u
  24. local frame = self.geometry.runesFrame
  25. local ct = #self.gutter
  26. local x = frame[1] + frame[3] / 2 - inc * ((ct - 1) / 2)
  27. local y = .12 * v
  28. local runeSize = .035 * u
  29. local runeInc = runeSize + .01 * v
  30. local runey = y + .09 * v
  31. local res = {}
  32. for i = 1, ct do
  33. table.insert(res, {x, y, r, {}})
  34. local runex = x - (runeInc * (3 - 1) / 2)
  35. for j = 1, 3 do
  36. table.insert(res[i][4], {runex - runeSize / 2, runey - runeSize / 2, runeSize, runeSize})
  37. runex = runex + runeInc
  38. end
  39. x = x + inc
  40. end
  41. return res
  42. end,
  43. deck = function()
  44. local u, v = ctx.u, ctx.v
  45. local frame = self.geometry.minionFrame
  46. local size = .08 * u
  47. local inc = size + .12 * u
  48. local runeSize = .045 * u
  49. local runeInc = runeSize + .02 * v
  50. local x = frame[1] + frame[3] / 2 - (inc * .5)
  51. local y = .39 * v
  52. local runey = y + .15 * v
  53. local res = {}
  54. for i = 1, 2 do
  55. res[i] = {x, y, size / 2, {}}
  56. local runex = x - (runeInc * (3 - 1) / 2)
  57. for j = 1, 3 do
  58. table.insert(res[i][4], {runex - runeSize / 2, runey - runeSize / 2, runeSize, runeSize})
  59. runex = runex + runeInc
  60. end
  61. x = x + inc
  62. end
  63. return res
  64. end,
  65. runes = function()
  66. local u, v = ctx.u, ctx.v
  67. local size = .045 * u
  68. local inc = size + .01 * v
  69. local x = u * .07
  70. local ox = x
  71. local y = v * .675
  72. local res = {}
  73. for i = 1, 33 do
  74. table.insert(res, {math.round(x), math.round(y), size, size})
  75. x = x + inc
  76. if i % 11 == 0 then y = y + inc x = ox end
  77. end
  78. return res
  79. end,
  80. runesLabel = function()
  81. local u, v = ctx.u, ctx.v
  82. return {u * .07, v * .675 - v * .015 - v * .04}
  83. end,
  84. runesFrame = function()
  85. local u, v = ctx.u, ctx.v
  86. local label = self.geometry.runesLabel
  87. local x = label[1] - v * .02
  88. local y = label[2] - v * .01
  89. local w = ((self.geometry.runes[1][4] + .01 * v) * 11) + v * .03
  90. local h = ((self.geometry.runes[1][4] + .01 * v) * 3) + v * .055 + v * .02
  91. return {x, y, w, h}
  92. end,
  93. play = function()
  94. local u, v = ctx.u, ctx.v
  95. local frame = self.geometry.runesFrame
  96. local w, h = .2 * u, .13 * v
  97. local midx = (u + frame[1] + frame[3]) / 2
  98. return {midx - w / 2, .45 * v, w, h}
  99. end,
  100. muju = function()
  101. local u, v = ctx.u, ctx.v
  102. local x, y = u * .72, v * .8
  103. local res = {x, y, {}}
  104. local hats = ctx.user.hats or {}
  105. local hatSize = .04 * v
  106. local hatInc = hatSize + .08 * v
  107. local hatX = x + .12 * u
  108. local hatY = .77 * v
  109. for i = 1, math.min(#hats, 4) do
  110. table.insert(res[3], {hatX, hatY, hatSize})
  111. hatX = hatX + hatInc
  112. if i % 2 == 0 then
  113. hatX = x + .12 * u
  114. hatY = hatY + hatInc
  115. end
  116. end
  117. return res
  118. end,
  119. hatsFrame = function()
  120. local u, v = ctx.u, ctx.v
  121. local x, y = unpack(self.geometry.muju)
  122. local hatSize = .04 * v
  123. local hatInc = hatSize + .08 * v
  124. local hatX = x + .12 * u
  125. local hatY = .77 * v
  126. local padding = .04 * v
  127. return {hatX - hatSize / 2 - padding, hatY - hatSize / 2 - padding, 2 * padding + 2 * hatSize + .08 * v, 2 * padding + 2 * hatSize + .08 * v}
  128. end
  129. }
  130. self.play = ctx.gooey:add(Button, 'menu.survival.play')
  131. self.play.geometry = function() return self.geometry.play end
  132. self.play:on('click', function() ctx.animations.muju:set('death') end)
  133. self.play.text = 'Play'
  134. self.drag = MenuSurvivalDrag()
  135. end
  136. function MenuSurvival:activate()
  137. table.clear(self.geometry)
  138. -- Initialize runes
  139. self.runeTransforms = {}
  140. self.prevRuneTransforms = {}
  141. table.each(ctx.user.runes, function(list)
  142. table.each(list, function(rune)
  143. self.runeTransforms[rune] = {}
  144. self.prevRuneTransforms[rune] = {}
  145. end)
  146. end)
  147. self.hatHoverFactors = {}
  148. self.prevHatHoverFactors = {}
  149. self.drag.active = true
  150. self:refreshGutter()
  151. end
  152. function MenuSurvival:deactivate()
  153. self.drag.active = false
  154. end
  155. function MenuSurvival:update()
  156. if not self.active then return end
  157. local mx, my = love.mouse.getPosition()
  158. local runes = self.geometry.runes
  159. for i = 1, 33 do
  160. local rune = ctx.user.runes.stash[i]
  161. if rune and not self.drag:isDraggingRune('stash', i) then
  162. local x, y, w, h = unpack(runes[i])
  163. lerpRune(rune, 'x', x + w / 2)
  164. lerpRune(rune, 'y', y + h / 2)
  165. lerpRune(rune, 'size', h)
  166. if math.inside(mx, my, x, y, w, h) then
  167. ctx.tooltip:setRuneTooltip(rune)
  168. end
  169. end
  170. end
  171. local gutter = self.geometry.gutter
  172. for i = 1, #gutter do
  173. local x, y, r, runes = unpack(gutter[i])
  174. local minion = self.gutter[i]
  175. if not self.drag:isDraggingMinion('gutter', i) then
  176. lerpAnimation(minion, 'x', x)
  177. lerpAnimation(minion, 'y', y)
  178. lerpAnimation(minion, 'scale', .75)
  179. end
  180. for j = 1, #runes do
  181. local rune = ctx.user.runes[minion][j]
  182. if rune and not self.drag:isDraggingRune(minion, j) then
  183. local x, y, w, h = unpack(runes[j])
  184. lerpRune(rune, 'x', x + w / 2)
  185. lerpRune(rune, 'y', y + h / 2)
  186. lerpRune(rune, 'size', h)
  187. if math.inside(mx, my, x, y, w, h) then
  188. ctx.tooltip:setRuneTooltip(rune)
  189. end
  190. end
  191. end
  192. end
  193. local deck = self.geometry.deck
  194. for i = 1, #deck do
  195. local x, y, r, runes = unpack(deck[i])
  196. local minion = ctx.user.survival.minions[i]
  197. if minion then
  198. if not self.drag:isDraggingMinion('deck', i) then
  199. lerpAnimation(minion, 'x', x)
  200. lerpAnimation(minion, 'y', y)
  201. lerpAnimation(minion, 'scale', .9)
  202. end
  203. for j = 1, #runes do
  204. local rune = ctx.user.runes[minion][j]
  205. if rune and not self.drag:isDraggingRune(minion, j) then
  206. local x, y, w, h = unpack(runes[j])
  207. lerpRune(rune, 'x', x + w / 2)
  208. lerpRune(rune, 'y', y + h / 2)
  209. lerpRune(rune, 'size', h)
  210. if math.inside(mx, my, x, y, w, h) then
  211. ctx.tooltip:setRuneTooltip(rune)
  212. end
  213. end
  214. end
  215. end
  216. end
  217. local _, _, hats = unpack(self.geometry.muju)
  218. for i = 1, #ctx.user.hats do
  219. local hat = ctx.user.hats[i]
  220. if hat and hats[i] then
  221. local hover = math.insideCircle(mx, my, unpack(hats[i]))
  222. self.prevHatHoverFactors[hat] = self.hatHoverFactors[hat] or 0
  223. self.hatHoverFactors[hat] = math.lerp(self.hatHoverFactors[hat] or 0, hover and 1 or 0, math.min(10 * ls.tickrate, 1))
  224. end
  225. end
  226. self.drag:update()
  227. end
  228. function MenuSurvival:draw()
  229. if not self.active then return end
  230. local u, v = ctx.u, ctx.v
  231. local ps = love.window.getPixelScale()
  232. local atlas = data.atlas.hud
  233. -- Best Time
  234. local play = self.geometry.play
  235. local x = play[1] + play[3] / 2
  236. g.setFont('mesmerize', .08 * v)
  237. g.setColor(255, 255, 255)
  238. g.printShadow('Survival', x, .15 * v, true)
  239. g.setFont('mesmerize', .05 * v)
  240. local str = 'Best Time:\n' .. toTime(ctx.user.survival.bestTime, true)
  241. g.setColor(0, 0, 0)
  242. g.printf(str, x - .2 * u + 1, .26 * v + 1, .4 * u, 'center')
  243. g.setColor(255, 255, 255)
  244. g.printf(str, x - .2 * u, .26 * v, .4 * u, 'center')
  245. -- Rune Frame
  246. g.setColor(0, 0, 0, 100)
  247. g.rectangle('fill', unpack(self.geometry.runesFrame))
  248. -- Rune Frames
  249. g.setColor(255, 255, 255)
  250. local runes = self.geometry.runes
  251. for i = 1, #runes do
  252. local x, y, w, h = unpack(runes[i])
  253. local scale = w / atlas:getDimensions('frame')
  254. g.setColor(255, 255, 255)
  255. g.draw(atlas.texture, atlas.quads.frame, x, y, 0, scale, scale)
  256. end
  257. -- Runes
  258. for i = 1, #runes do
  259. local x, y, w, h = unpack(runes[i])
  260. if i == 33 then
  261. local image = data.media.graphics.menu.trashcan
  262. local scale = (h - .025 * v) / image:getHeight()
  263. local dragAlpha = math.lerp(self.drag.prevDragAlpha, self.drag.dragAlpha, ls.accum / ls.tickrate)
  264. g.setColor(255, 255, 255, 150 + 100 * (self.drag:isDraggingRune() and dragAlpha or 0))
  265. g.draw(image, x + w / 2, y + h / 2, 0, scale, scale, image:getWidth() / 2, image:getHeight() / 2)
  266. else
  267. local rune = ctx.user.runes.stash[i]
  268. if rune and not self.drag:isDraggingRune('stash', i) then
  269. local lerpd = {}
  270. for k, v in pairs(self.runeTransforms[rune]) do
  271. lerpd[k] = math.lerp(self.prevRuneTransforms[rune][k] or v, v, ls.accum / ls.tickrate)
  272. end
  273. lerpd.x = lerpd.x or x
  274. lerpd.y = lerpd.y or y
  275. lerpd.size = lerpd.size or h
  276. h = lerpd.size
  277. g.setColor(255, 255, 255)
  278. g.drawRune(rune, lerpd.x, lerpd.y, lerpd.size - .015 * v, (lerpd.size - .015 * v) * .5, table.has(ctx.rewards.runes, rune))
  279. end
  280. end
  281. end
  282. -- Rune Label
  283. g.setColor(255, 255, 255)
  284. g.setFont('mesmerize', v * .04)
  285. local x, y = unpack(self.geometry.runesLabel)
  286. g.print('Runes', x, y)
  287. -- Minion Gutter
  288. local gutter = self.geometry.gutter
  289. for i = 1, #gutter do
  290. local x, y, r, runes = unpack(gutter[i])
  291. local minion = self.gutter[i]
  292. if minion and not self.drag:isDraggingMinion('gutter', i) then
  293. local cw, ch = ctx.unitCanvas:getDimensions()
  294. ctx.unitCanvas:clear(0, 0, 0, 0)
  295. ctx.unitCanvas:renderTo(function()
  296. ctx.animations[minion]:draw(cw / 2, ch / 2)
  297. end)
  298. local lerpd = {}
  299. for k, v in pairs(ctx.animationTransforms[minion]) do
  300. lerpd[k] = math.lerp(ctx.prevAnimationTransforms[minion][k] or v, v, ls.accum / ls.tickrate)
  301. end
  302. lerpd.x = lerpd.x or x
  303. lerpd.y = lerpd.y or y
  304. lerpd.scale = lerpd.scale or .75
  305. local scale = (2 * r / cw) * lerpd.scale * 3
  306. g.setColor(255, 255, 255)
  307. g.draw(ctx.unitCanvas, lerpd.x, lerpd.y, 0, scale, scale, cw / 2, ch / 2)
  308. end
  309. -- Gutter Rune Frames
  310. for j = 1, #runes do
  311. local x, y, w, h = unpack(runes[j])
  312. local scale = w / atlas:getDimensions('frame')
  313. g.setColor(255, 255, 255)
  314. g.draw(atlas.texture, atlas.quads.frame, x, y, 0, scale, scale)
  315. end
  316. end
  317. -- Gutter Runes
  318. for i = 1, #gutter do
  319. local minion = self.gutter[i]
  320. local _, _, _, runes = unpack(gutter[i])
  321. for j = 1, #runes do
  322. local rune = ctx.user.runes[minion][j]
  323. local x, y, w, h = unpack(runes[j])
  324. if rune and not self.drag:isDraggingRune(minion, j) then
  325. local lerpd = {}
  326. for k, v in pairs(self.runeTransforms[rune]) do
  327. lerpd[k] = math.lerp(self.prevRuneTransforms[rune][k] or v, v, ls.accum / ls.tickrate)
  328. end
  329. lerpd.x = lerpd.x or x
  330. lerpd.y = lerpd.y or y
  331. lerpd.size = lerpd.size or h
  332. g.setColor(255, 255, 255)
  333. g.drawRune(rune, lerpd.x, lerpd.y, lerpd.size - .015 * v, (lerpd.size - .015 * v) * .5, table.has(ctx.rewards.runes, rune))
  334. end
  335. end
  336. end
  337. -- Deck
  338. local deck = self.geometry.deck
  339. for i = 1, #deck do
  340. local minion = ctx.user.survival.minions[i]
  341. local x, y, r, runes = unpack(deck[i])
  342. local xoff = .02 * v
  343. local height = .04 * v
  344. g.setColor(0, 0, 0, 100)
  345. g.polygon('fill', x - r - xoff, y + r - height, x + r + xoff, y + r - height, x + r, y + r, x - r, y + r)
  346. -- Deck Minion
  347. if minion and not self.drag:isDraggingMinion('deck', i) then
  348. local cw, ch = ctx.unitCanvas:getDimensions()
  349. ctx.unitCanvas:clear(0, 0, 0, 0)
  350. ctx.unitCanvas:renderTo(function()
  351. ctx.animations[minion]:draw(cw / 2, ch / 2)
  352. end)
  353. local lerpd = {}
  354. for k, v in pairs(ctx.animationTransforms[minion]) do
  355. lerpd[k] = math.lerp(ctx.prevAnimationTransforms[minion][k] or v, v, ls.accum / ls.tickrate)
  356. end
  357. lerpd.x = lerpd.x or x
  358. lerpd.y = lerpd.y or y
  359. lerpd.scale = lerpd.scale or .75
  360. local scale = (2 * r / cw) * lerpd.scale * 3
  361. g.setColor(255, 255, 255)
  362. g.draw(ctx.unitCanvas, lerpd.x, lerpd.y, 0, scale, scale, cw / 2, ch / 2)
  363. end
  364. -- Deck Rune Frames
  365. for j = 1, #runes do
  366. local x, y, w, h = unpack(runes[j])
  367. local scale = w / atlas:getDimensions('frame')
  368. g.setColor(255, 255, 255)
  369. g.draw(atlas.texture, atlas.quads.frame, x, y, 0, scale, scale)
  370. end
  371. end
  372. -- Deck Runes
  373. for i = 1, #deck do
  374. local minion = ctx.user.survival.minions[i]
  375. if minion then
  376. local _, _, _, runes = unpack(deck[i])
  377. for i = 1, #runes do
  378. local rune = ctx.user.runes[minion][i]
  379. if rune and not self.drag:isDraggingRune(minion, i) then
  380. local x, y, w, h = unpack(runes[i])
  381. local lerpd = {}
  382. for k, v in pairs(ctx.survival.runeTransforms[rune]) do
  383. lerpd[k] = math.lerp(ctx.survival.prevRuneTransforms[rune][k] or v, v, ls.accum / ls.tickrate)
  384. end
  385. lerpd.x = lerpd.x or x
  386. lerpd.y = lerpd.y or y
  387. lerpd.size = lerpd.size or h
  388. g.setColor(255, 255, 255)
  389. g.drawRune(rune, lerpd.x, lerpd.y, lerpd.size - .015 * v, (lerpd.size - .015 * v) * .5, table.has(ctx.rewards.runes, rune))
  390. end
  391. end
  392. end
  393. end
  394. -- Muju
  395. local color = ctx.user and ctx.user.color or 'purple'
  396. local animation = ctx.animations.muju
  397. -- Muju Robe Color
  398. for _, slot in pairs({'robebottom', 'torso', 'front_upper_arm', 'rear_upper_arm', 'front_bracer', 'rear_bracer'}) do
  399. local slot = animation.spine.skeleton:findSlot(slot)
  400. slot.r, slot.g, slot.b = unpack(config.player.colors[color])
  401. end
  402. -- Muju Hat
  403. animation.spine.skeleton:setSkin(ctx.user.hat or 'santa')
  404. animation.spine.skeleton:findSlot('hat').a = ctx.user.hat and 1 or 0
  405. animation.spine.skeleton:findBone('hat').scaleX = animation.scale
  406. animation.spine.skeleton:findBone('hat').scaleY = animation.scale
  407. -- Draw Muju
  408. local cw, ch = ctx.unitCanvas:getDimensions()
  409. ctx.unitCanvas:clear(0, 0, 0, 0)
  410. ctx.unitCanvas:renderTo(function()
  411. animation:draw(cw / 2, ch / 2)
  412. end)
  413. local scale = (.15 * v / cw) * 1 * 3
  414. g.setColor(255, 255, 255)
  415. local x, y, hats = unpack(self.geometry.muju)
  416. g.draw(ctx.unitCanvas, x, y, 0, scale, scale, cw / 2, ch / 2)
  417. -- Hats Frame
  418. g.setColor(0, 0, 0, 100)
  419. g.rectangle('fill', unpack(self.geometry.hatsFrame))
  420. -- Hats
  421. for i = 1, #hats do
  422. local hat = ctx.user.hats[i]
  423. if hat then
  424. local image = data.media.graphics.hats[hat]
  425. if image then
  426. local x, y, r = unpack(hats[i])
  427. local scale = r * 2 / math.max(image:getWidth(), image:getHeight())
  428. local factor = math.lerp(self.prevHatHoverFactors[hat], self.hatHoverFactors[hat], ls.accum / ls.tickrate)
  429. scale = scale * (.8 + .2 * factor)
  430. g.setColor(255, 255, 255, 120 + (130 * (ctx.user.hat == hat and 1 or 0)))
  431. g.draw(image, x, y, 0, scale, scale, image:getWidth() / 2, image:getHeight() / 2)
  432. end
  433. end
  434. end
  435. -- Modules
  436. self.play:draw()
  437. self.drag:draw()
  438. end
  439. function MenuSurvival:keyreleased(key)
  440. if not self.active then return end
  441. if key == 'escape' then
  442. ctx:setPage('start')
  443. return true
  444. end
  445. end
  446. function MenuSurvival:mousepressed(mx, my, b)
  447. if not self.active then return end
  448. self.drag:mousepressed(mx, my, b)
  449. end
  450. function MenuSurvival:mousereleased(mx, my, b)
  451. if not self.active then return end
  452. if ctx.optionsPane.active then return end
  453. self.drag:mousereleased(mx, my, b)
  454. local _, _, hats = unpack(self.geometry.muju)
  455. for i = 1, #hats do
  456. local hat = ctx.user.hats[i]
  457. if hat then
  458. local x, y, r = unpack(hats[i])
  459. if math.insideCircle(mx, my, x, y, r) then
  460. if b == 'l' then
  461. ctx.user.hat = hat
  462. elseif b == 'r' then
  463. ctx.user.hat = nil
  464. end
  465. saveUser(ctx.user)
  466. end
  467. end
  468. end
  469. end
  470. function MenuSurvival:gamepadpressed(gamepad, button)
  471. if not self.active then return end
  472. if button == 'dpleft' then self:previousBiome()
  473. elseif button == 'dpright' then self:nextBiome()
  474. elseif button == 'start' then ctx.animations.muju:set('death')
  475. elseif button == 'b' then
  476. ctx.page = 'start'
  477. ctx.start.active = true
  478. end
  479. end
  480. function MenuSurvival:resize()
  481. table.clear(self.geometry)
  482. end
  483. function MenuSurvival:setBiome(biome)
  484. self.biome = biome
  485. ctx:refreshBackground()
  486. end
  487. function MenuSurvival:mujuDead()
  488. local deck = ctx.user.survival.minions
  489. if not deck[1] and not deck[2] then return end
  490. if not deck[1] and deck[2] then table.remove(deck, 1) end
  491. if #deck >= 3 then return end
  492. ctx:startGame({mode = 'survival', biome = config.biomeOrder[love.math.random(1, #config.biomeOrder)]})
  493. end
  494. function MenuSurvival:refreshGutter()
  495. self.gutter = {config.biomes[config.biomeOrder[1]].minion}
  496. for i = 1, #config.biomeOrder do
  497. local biome = config.biomeOrder[i]
  498. local nextBiome = config.biomeOrder[i + 1]
  499. if nextBiome then
  500. local minion = config.biomes[nextBiome].minion
  501. if minion and ctx.user.campaign.medals[biome].silver then
  502. table.insert(self.gutter, minion)
  503. end
  504. end
  505. end
  506. local i = 1
  507. while i <= #self.gutter do
  508. if table.has(ctx.user.survival.minions, self.gutter[i]) then
  509. table.remove(self.gutter, i)
  510. else
  511. i = i + 1
  512. end
  513. end
  514. table.clear(self.geometry)
  515. end