From 6e11e98bfba78ac2055ce0bf3b38b9ff1a00242a Mon Sep 17 00:00:00 2001 From: parameterized Date: Thu, 20 Sep 2018 12:38:27 -0400 Subject: [PATCH] bag ui with draggable placeholder, lume --- chat.lua | 2 +- client.lua | 17 +- entityDefs/_base.lua | 6 +- entityDefs/slime.lua | 16 +- gfx/ui/bagui.png | Bin 0 -> 755 bytes hud.lua | 32 +- camera.lua => lib/camera.lua | 0 json.lua => lib/json.lua | 0 love_nut.lua => lib/love_nut.lua | 0 lib/lume.lua | 780 +++++++++++++++++++++++++++++++ loadassets.lua | 3 +- lootBags.lua | 123 ++++- main.lua | 22 +- menu.lua | 45 +- player.lua | 82 ++-- projectiles.lua | 4 +- server.lua | 2 +- text.lua | 6 +- utils.lua | 23 +- 19 files changed, 1006 insertions(+), 157 deletions(-) create mode 100644 gfx/ui/bagui.png rename camera.lua => lib/camera.lua (100%) rename json.lua => lib/json.lua (100%) rename love_nut.lua => lib/love_nut.lua (100%) create mode 100644 lib/lume.lua diff --git a/chat.lua b/chat.lua index a27d7fb..11eb994 100644 --- a/chat.lua +++ b/chat.lua @@ -3,7 +3,7 @@ chat = { log = {}, active = false, val = '', - lastMsgTime = 0 + lastMsgTime = -1 } function chat.addMsg(v) diff --git a/client.lua b/client.lua index 0759f01..cbf309a 100644 --- a/client.lua +++ b/client.lua @@ -170,13 +170,13 @@ function client.update(dt) print('clamp up ' .. math.abs(client.stateTime - cs_3.time)) end ]] - client.stateTime = clamp(client.stateTime + dt, cs_3.time, cs_0.time) + client.stateTime = lume.clamp(client.stateTime + dt, cs_3.time, cs_0.time) if client.stateTime > cs_1.time then --print('lerp down') - client.stateTime = lerp(client.stateTime, cs_1.time, clamp(dt, 0, 1)) + client.stateTime = lume.lerp(client.stateTime, cs_1.time, lume.clamp(dt, 0, 1)) elseif client.stateTime < cs_2.time then --print('lerp up') - client.stateTime = lerp(client.stateTime, cs_2.time, clamp(dt, 0, 1)) + client.stateTime = lume.lerp(client.stateTime, cs_2.time, lume.clamp(dt, 0, 1)) end --debugger.logVal('interpolation delay', client.serverTime - client.stateTime) while client.states[client.stateIdx+1] and client.states[client.stateIdx+2] @@ -185,7 +185,7 @@ function client.update(dt) end local t = (client.stateTime - client.states[client.stateIdx].time) / (client.states[client.stateIdx+1].time - client.states[client.stateIdx].time) - --t = clamp(t, 0, 1) -- t>1 = prediction + --t = lume.clamp(t, 0, 1) -- t>1 = prediction if not client.interpolate then t = 1 end @@ -196,8 +196,8 @@ function client.update(dt) if v2 then local obj = client.currentState.players[k] if obj then - obj.x = lerp(v.x, v2.x, t) - obj.y = lerp(v.y, v2.y, t) + obj.x = lume.lerp(v.x, v2.x, t) + obj.y = lume.lerp(v.y, v2.y, t) obj.body:setPosition(obj.x, obj.y) @@ -216,8 +216,8 @@ function client.update(dt) if v2 then local obj = client.currentState.projectiles[k] if obj then - obj.x = lerp(v.x, v2.x, t) - obj.y = lerp(v.y, v2.y, t) + obj.x = lume.lerp(v.x, v2.x, t) + obj.y = lume.lerp(v.y, v2.y, t) obj.startedMoving = true end end @@ -238,6 +238,7 @@ function client.update(dt) if not (server.running and server.paused) then gameTime = gameTime + dt hud.update(dt) + lootBags.client.update(dt) physics.client.update(dt) world.update(dt) player.update(dt) diff --git a/entityDefs/_base.lua b/entityDefs/_base.lua index 3415b80..fc97fac 100644 --- a/entityDefs/_base.lua +++ b/entityDefs/_base.lua @@ -13,7 +13,7 @@ end function base.server:new(o) o = o or {} local defaults = { - id = uuid(), + id = lume.uuid(), x = 0, y = 0 } for k, v in pairs(defaults) do @@ -104,7 +104,7 @@ end function base.client:new(o) o = o or {} local defaults = { - id = uuid(), + id = lume.uuid(), x = 0, y = 0 } for k, v in pairs(defaults) do @@ -128,7 +128,7 @@ end function base.client:lerpState(a, b, t) for _, v in pairs{'x', 'y'} do - self[v] = lerp(a[v], b[v], t) + self[v] = lume.lerp(a[v], b[v], t) end end diff --git a/entityDefs/slime.lua b/entityDefs/slime.lua index 0ba4e03..2f64f25 100644 --- a/entityDefs/slime.lua +++ b/entityDefs/slime.lua @@ -14,7 +14,7 @@ end function slime.server:new(o) o = o or {} local defaults = { - id = uuid(), + id = lume.uuid(), x = 0, y = 0, xv = 0, yv = 0, slimeType = math.random() < 0.5 and 'slime1' or 'slime2', @@ -92,7 +92,7 @@ function slime.server:damage(d, clientId) lootBags.server.spawn{ x = self.x, y = self.y, items = {'apl', 'banan'}, - life = 10, + life = 30, type = type } end @@ -129,7 +129,7 @@ end function slime.client:new(o) o = o or {} local defaults = { - id = uuid(), + id = lume.uuid(), x = 0, y = 0, hpMax = 5, hp = math.random(1, 5), @@ -189,7 +189,7 @@ end function slime.client:lerpState(a, b, t) local state = {} for _, v in pairs{'x', 'y', 'xv', 'yv'} do - state[v] = lerp(a[v], b[v], t) + state[v] = lume.lerp(a[v], b[v], t) end for _, v in pairs{'slimeType', 'hpMax', 'hp'} do state[v] = b[v] @@ -211,11 +211,11 @@ function slime.client:drawBody() shaders.outline:send('stepSize', {1/img:getWidth(), 1/img:getHeight()}) love.graphics.push() local vx, vy = self.body:getPosition() - love.graphics.translate(math.floor(vx), math.floor(vy)) + love.graphics.translate(lume.round(vx), lume.round(vy)) love.graphics.draw(img, 0, 0, 0, 1, 1, - math.floor(img:getWidth()/2), math.floor(img:getHeight()/2)) + lume.round(img:getWidth()/2), lume.round(img:getHeight()/2)) love.graphics.pop() love.graphics.setShader(_shader) end @@ -235,8 +235,8 @@ function slime.client:drawHP() love.graphics.setShader(_shader) love.graphics.push() local vx, vy = self.body:getPosition() - love.graphics.translate(math.floor(vx), math.floor(vy)) - love.graphics.draw(canvases.hpBar, math.floor(-canvases.hpBar:getWidth()/2), 10) + love.graphics.translate(lume.round(vx), lume.round(vy)) + love.graphics.draw(canvases.hpBar, lume.round(-canvases.hpBar:getWidth()/2), 10) love.graphics.pop() end diff --git a/gfx/ui/bagui.png b/gfx/ui/bagui.png new file mode 100644 index 0000000000000000000000000000000000000000..ee03387f1eca8a16b89d437620153ef227879c34 GIT binary patch literal 755 zcmeAS@N?(olHy`uVBq!ia0vp^!9eW5!3HGLK6sk~DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#S9F5he4R}c>anMprB-lYeY$Kep*R+Vo@qXL1JcJiC$i6iGqoq zfu51!M}^F(3=B-ko-U3d6>)E8Uo5_c%E}E!s+p~ zS#8hycD}p1`NEE^%NFiTZpulS|NU9t&B)6Zn~xh>XG^7j+Y{>37mNj+)%94xLp3<(43O84KuJ*jd=P#?)mUCL?Up*{-FoX5Qg3E^77aW%-i!EsOJFerv zKDRHjfzL{IGlOi2RT`t!i;^=;B^O@eSNQIjNiE-T8PP9OZP%`ro?JY+*lO87Cef($ zsp(%oSQZdr0x?#VC(p8LPwwOTb!y(VQsZSe+wV@BVf>H(g>1t57u!qDB+V+$NwUh2 zZM}0OMs0quyKP%k?ytg6TVJe*-PG|YtMNs5+F_%0)vQylS literal 0 HcmV?d00001 diff --git a/hud.lua b/hud.lua index ad82ef8..1dfc44e 100644 --- a/hud.lua +++ b/hud.lua @@ -3,7 +3,6 @@ hud = {} hud.panels = {} hud.buttons = {} -hud.buttonDown = false function hud.addPanel(t) local defaults = { @@ -26,13 +25,13 @@ function hud.addPanel(t) if not t.update then t.update = function(self, dt) if self.open then - self.timer = clamp(self.timer - 3*dt, 0, 1) + self.timer = lume.clamp(self.timer - 3*dt, 0, 1) else - self.timer = clamp(self.timer + 3*dt, 0, 1) + self.timer = lume.clamp(self.timer + 3*dt, 0, 1) end local t = ease.inOutCubic(self.timer) - self.x = lerp(self.openPos.x, self.closedPos.x, t) - self.y = lerp(self.openPos.y, self.closedPos.y, t) + self.x = lume.lerp(self.openPos.x, self.closedPos.x, t) + self.y = lume.lerp(self.openPos.y, self.closedPos.y, t) end end table.insert(hud.panels, t) @@ -83,7 +82,7 @@ function hud.load() img=gfx.hud.buttons.chat, x=16, y=235, update = function(self, dt) local t = ease.inOutCubic(hud.chatPanel.timer) - self.y = lerp(132, 235, t) + self.y = lume.lerp(132, 235, t) end, action = function(self) hud.chatPanel.open = not hud.chatPanel.open @@ -102,7 +101,7 @@ function hud.load() local r, g, b = love.graphics.getColor() love.graphics.setColor(r*0.8, g*0.8, b*0.8) end - love.graphics.draw(self.img, math.floor(self.x), math.floor(self.y)) + love.graphics.draw(self.img, lume.round(self.x), lume.round(self.y)) end } hud.addButton{ @@ -149,12 +148,12 @@ function hud.update(dt) end function hud.mousepressed(mx, my, btn) - mx, my = screen2game(mx, my) + mx, my = window2game(mx, my) local chatFieldPressed = false for _, v in pairs(hud.buttons) do if mx > v.x and mx < v.x + v.img:getWidth() and my > v.y and my < v.y + v.img:getHeight() then if v.action then v.action(v) end - hud.buttonDown = true + uiMouseDown = true if v.id == 'chatField' then chatFieldPressed = true end end end @@ -164,12 +163,11 @@ function hud.mousepressed(mx, my, btn) end function hud.mousereleased(mx, my, btn) - mx, my = screen2game(mx, my) - hud.buttonDown = false + end function hud.draw() - local mx, my = screen2game(love.mouse.getPosition()) + local mx, my = window2game(love.mouse.getPosition()) love.graphics.setColor(1, 1, 1) love.graphics.draw(gfx.hud.frame, 0, 0) @@ -182,7 +180,7 @@ function hud.draw() love.graphics.setColor(1, 1, 1) for _, v in pairs(hud.panels) do - love.graphics.draw(v.img, math.floor(v.x), math.floor(v.y)) + love.graphics.draw(v.img, lume.round(v.x), lume.round(v.y)) end for _, v in pairs(hud.buttons) do if v.draw then @@ -192,7 +190,7 @@ function hud.draw() if mx > v.x and mx < v.x + v.img:getWidth() and my > v.y and my < v.y + v.img:getHeight() then love.graphics.setColor(0.8, 0.8, 0.8) end - love.graphics.draw(v.img, math.floor(v.x), math.floor(v.y)) + love.graphics.draw(v.img, lume.round(v.x), lume.round(v.y)) end end @@ -200,13 +198,13 @@ function hud.draw() x, y = hud.statsPanel.x, hud.statsPanel.y love.graphics.setColor(221/255, 217/255, 0) local t = l - math.floor(l) - love.graphics.rectangle('fill', 191, math.floor(y + 20), t*99, 3) + love.graphics.rectangle('fill', 191, lume.round(y + 20), t*99, 3) love.graphics.setColor(1, 1, 1) local font = fonts.c17 love.graphics.setFont(font) local level = tostring(math.floor(l)) - love.graphics.print(level, math.floor(240 - font:getWidth(level)/2), math.floor(y)) + love.graphics.print(level, lume.round(240 - font:getWidth(level)/2), lume.round(y)) font = fonts.stats love.graphics.setFont(font) @@ -225,7 +223,7 @@ function hud.draw() sx = x + (sx - hud.statsPanel.openPos.x) sy = y + (sy - hud.statsPanel.openPos.y) local txt = tostring(player.stats[col][row]) - love.graphics.print(txt, math.floor(sx - font:getWidth(txt)/2), math.floor(sy - font:getHeight()/2)) + love.graphics.print(txt, lume.round(sx - font:getWidth(txt)/2), lume.round(sy - font:getHeight()/2)) end end diff --git a/camera.lua b/lib/camera.lua similarity index 100% rename from camera.lua rename to lib/camera.lua diff --git a/json.lua b/lib/json.lua similarity index 100% rename from json.lua rename to lib/json.lua diff --git a/love_nut.lua b/lib/love_nut.lua similarity index 100% rename from love_nut.lua rename to lib/love_nut.lua diff --git a/lib/lume.lua b/lib/lume.lua new file mode 100644 index 0000000..1c1b742 --- /dev/null +++ b/lib/lume.lua @@ -0,0 +1,780 @@ +-- +-- lume +-- +-- Copyright (c) 2018 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local lume = { _version = "2.3.0" } + +local pairs, ipairs = pairs, ipairs +local type, assert, unpack = type, assert, unpack or table.unpack +local tostring, tonumber = tostring, tonumber +local math_floor = math.floor +local math_ceil = math.ceil +local math_atan2 = math.atan2 or math.atan +local math_sqrt = math.sqrt +local math_abs = math.abs + +local noop = function() +end + +local identity = function(x) + return x +end + +local patternescape = function(str) + return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1") +end + +local absindex = function(len, i) + return i < 0 and (len + i + 1) or i +end + +local iscallable = function(x) + if type(x) == "function" then return true end + local mt = getmetatable(x) + return mt and mt.__call ~= nil +end + +local getiter = function(x) + if lume.isarray(x) then + return ipairs + elseif type(x) == "table" then + return pairs + end + error("expected table", 3) +end + +local iteratee = function(x) + if x == nil then return identity end + if iscallable(x) then return x end + if type(x) == "table" then + return function(z) + for k, v in pairs(x) do + if z[k] ~= v then return false end + end + return true + end + end + return function(z) return z[x] end +end + + + +function lume.clamp(x, min, max) + return x < min and min or (x > max and max or x) +end + + +function lume.round(x, increment) + if increment then return lume.round(x / increment) * increment end + return x >= 0 and math_floor(x + .5) or math_ceil(x - .5) +end + + +function lume.sign(x) + return x < 0 and -1 or 1 +end + + +function lume.lerp(a, b, amount) + return a + (b - a) * lume.clamp(amount, 0, 1) +end + + +function lume.smooth(a, b, amount) + local t = lume.clamp(amount, 0, 1) + local m = t * t * (3 - 2 * t) + return a + (b - a) * m +end + + +function lume.pingpong(x) + return 1 - math_abs(1 - x % 2) +end + + +function lume.distance(x1, y1, x2, y2, squared) + local dx = x1 - x2 + local dy = y1 - y2 + local s = dx * dx + dy * dy + return squared and s or math_sqrt(s) +end + + +function lume.angle(x1, y1, x2, y2) + return math_atan2(y2 - y1, x2 - x1) +end + + +function lume.vector(angle, magnitude) + return math.cos(angle) * magnitude, math.sin(angle) * magnitude +end + + +function lume.random(a, b) + if not a then a, b = 0, 1 end + if not b then b = 0 end + return a + math.random() * (b - a) +end + + +function lume.randomchoice(t) + return t[math.random(#t)] +end + + +function lume.weightedchoice(t) + local sum = 0 + for _, v in pairs(t) do + assert(v >= 0, "weight value less than zero") + sum = sum + v + end + assert(sum ~= 0, "all weights are zero") + local rnd = lume.random(sum) + for k, v in pairs(t) do + if rnd < v then return k end + rnd = rnd - v + end +end + + +function lume.isarray(x) + return (type(x) == "table" and x[1] ~= nil) and true or false +end + + +function lume.push(t, ...) + local n = select("#", ...) + for i = 1, n do + t[#t + 1] = select(i, ...) + end + return ... +end + + +function lume.remove(t, x) + local iter = getiter(t) + for i, v in iter(t) do + if v == x then + if lume.isarray(t) then + table.remove(t, i) + break + else + t[i] = nil + break + end + end + end + return x +end + + +function lume.clear(t) + local iter = getiter(t) + for k in iter(t) do + t[k] = nil + end + return t +end + + +function lume.extend(t, ...) + for i = 1, select("#", ...) do + local x = select(i, ...) + if x then + for k, v in pairs(x) do + t[k] = v + end + end + end + return t +end + + +function lume.shuffle(t) + local rtn = {} + for i = 1, #t do + local r = math.random(i) + if r ~= i then + rtn[i] = rtn[r] + end + rtn[r] = t[i] + end + return rtn +end + + +function lume.sort(t, comp) + local rtn = lume.clone(t) + if comp then + if type(comp) == "string" then + table.sort(rtn, function(a, b) return a[comp] < b[comp] end) + else + table.sort(rtn, comp) + end + else + table.sort(rtn) + end + return rtn +end + + +function lume.array(...) + local t = {} + for x in ... do t[#t + 1] = x end + return t +end + + +function lume.each(t, fn, ...) + local iter = getiter(t) + if type(fn) == "string" then + for _, v in iter(t) do v[fn](v, ...) end + else + for _, v in iter(t) do fn(v, ...) end + end + return t +end + + +function lume.map(t, fn) + fn = iteratee(fn) + local iter = getiter(t) + local rtn = {} + for k, v in iter(t) do rtn[k] = fn(v) end + return rtn +end + + +function lume.all(t, fn) + fn = iteratee(fn) + local iter = getiter(t) + for _, v in iter(t) do + if not fn(v) then return false end + end + return true +end + + +function lume.any(t, fn) + fn = iteratee(fn) + local iter = getiter(t) + for _, v in iter(t) do + if fn(v) then return true end + end + return false +end + + +function lume.reduce(t, fn, first) + local acc = first + local started = first and true or false + local iter = getiter(t) + for _, v in iter(t) do + if started then + acc = fn(acc, v) + else + acc = v + started = true + end + end + assert(started, "reduce of an empty table with no first value") + return acc +end + + +function lume.unique(t) + local rtn = {} + for k in pairs(lume.invert(t)) do + rtn[#rtn + 1] = k + end + return rtn +end + + +function lume.filter(t, fn, retainkeys) + fn = iteratee(fn) + local iter = getiter(t) + local rtn = {} + if retainkeys then + for k, v in iter(t) do + if fn(v) then rtn[k] = v end + end + else + for _, v in iter(t) do + if fn(v) then rtn[#rtn + 1] = v end + end + end + return rtn +end + + +function lume.reject(t, fn, retainkeys) + fn = iteratee(fn) + local iter = getiter(t) + local rtn = {} + if retainkeys then + for k, v in iter(t) do + if not fn(v) then rtn[k] = v end + end + else + for _, v in iter(t) do + if not fn(v) then rtn[#rtn + 1] = v end + end + end + return rtn +end + + +function lume.merge(...) + local rtn = {} + for i = 1, select("#", ...) do + local t = select(i, ...) + local iter = getiter(t) + for k, v in iter(t) do + rtn[k] = v + end + end + return rtn +end + + +function lume.concat(...) + local rtn = {} + for i = 1, select("#", ...) do + local t = select(i, ...) + if t ~= nil then + local iter = getiter(t) + for _, v in iter(t) do + rtn[#rtn + 1] = v + end + end + end + return rtn +end + + +function lume.find(t, value) + local iter = getiter(t) + for k, v in iter(t) do + if v == value then return k end + end + return nil +end + + +function lume.match(t, fn) + fn = iteratee(fn) + local iter = getiter(t) + for k, v in iter(t) do + if fn(v) then return v, k end + end + return nil +end + + +function lume.count(t, fn) + local count = 0 + local iter = getiter(t) + if fn then + fn = iteratee(fn) + for _, v in iter(t) do + if fn(v) then count = count + 1 end + end + else + if lume.isarray(t) then + return #t + end + for _ in iter(t) do count = count + 1 end + end + return count +end + + +function lume.slice(t, i, j) + i = i and absindex(#t, i) or 1 + j = j and absindex(#t, j) or #t + local rtn = {} + for x = i < 1 and 1 or i, j > #t and #t or j do + rtn[#rtn + 1] = t[x] + end + return rtn +end + + +function lume.first(t, n) + if not n then return t[1] end + return lume.slice(t, 1, n) +end + + +function lume.last(t, n) + if not n then return t[#t] end + return lume.slice(t, -n, -1) +end + + +function lume.invert(t) + local rtn = {} + for k, v in pairs(t) do rtn[v] = k end + return rtn +end + + +function lume.pick(t, ...) + local rtn = {} + for i = 1, select("#", ...) do + local k = select(i, ...) + rtn[k] = t[k] + end + return rtn +end + + +function lume.keys(t) + local rtn = {} + local iter = getiter(t) + for k in iter(t) do rtn[#rtn + 1] = k end + return rtn +end + + +function lume.clone(t) + local rtn = {} + for k, v in pairs(t) do rtn[k] = v end + return rtn +end + + +function lume.fn(fn, ...) + assert(iscallable(fn), "expected a function as the first argument") + local args = { ... } + return function(...) + local a = lume.concat(args, { ... }) + return fn(unpack(a)) + end +end + + +function lume.once(fn, ...) + local f = lume.fn(fn, ...) + local done = false + return function(...) + if done then return end + done = true + return f(...) + end +end + + +local memoize_fnkey = {} +local memoize_nil = {} + +function lume.memoize(fn) + local cache = {} + return function(...) + local c = cache + for i = 1, select("#", ...) do + local a = select(i, ...) or memoize_nil + c[a] = c[a] or {} + c = c[a] + end + c[memoize_fnkey] = c[memoize_fnkey] or {fn(...)} + return unpack(c[memoize_fnkey]) + end +end + + +function lume.combine(...) + local n = select('#', ...) + if n == 0 then return noop end + if n == 1 then + local fn = select(1, ...) + if not fn then return noop end + assert(iscallable(fn), "expected a function or nil") + return fn + end + local funcs = {} + for i = 1, n do + local fn = select(i, ...) + if fn ~= nil then + assert(iscallable(fn), "expected a function or nil") + funcs[#funcs + 1] = fn + end + end + return function(...) + for _, f in ipairs(funcs) do f(...) end + end +end + + +function lume.call(fn, ...) + if fn then + return fn(...) + end +end + + +function lume.time(fn, ...) + local start = os.clock() + local rtn = {fn(...)} + return (os.clock() - start), unpack(rtn) +end + + +local lambda_cache = {} + +function lume.lambda(str) + if not lambda_cache[str] then + local args, body = str:match([[^([%w,_ ]-)%->(.-)$]]) + assert(args and body, "bad string lambda") + local s = "return function(" .. args .. ")\nreturn " .. body .. "\nend" + lambda_cache[str] = lume.dostring(s) + end + return lambda_cache[str] +end + + +local serialize + +local serialize_map = { + [ "boolean" ] = tostring, + [ "nil" ] = tostring, + [ "string" ] = function(v) return string.format("%q", v) end, + [ "number" ] = function(v) + if v ~= v then return "0/0" -- nan + elseif v == 1 / 0 then return "1/0" -- inf + elseif v == -1 / 0 then return "-1/0" end -- -inf + return tostring(v) + end, + [ "table" ] = function(t, stk) + stk = stk or {} + if stk[t] then error("circular reference") end + local rtn = {} + stk[t] = true + for k, v in pairs(t) do + rtn[#rtn + 1] = "[" .. serialize(k, stk) .. "]=" .. serialize(v, stk) + end + stk[t] = nil + return "{" .. table.concat(rtn, ",") .. "}" + end +} + +setmetatable(serialize_map, { + __index = function(_, k) error("unsupported serialize type: " .. k) end +}) + +serialize = function(x, stk) + return serialize_map[type(x)](x, stk) +end + +function lume.serialize(x) + return serialize(x) +end + + +function lume.deserialize(str) + return lume.dostring("return " .. str) +end + + +function lume.split(str, sep) + if not sep then + return lume.array(str:gmatch("([%S]+)")) + else + assert(sep ~= "", "empty separator") + local psep = patternescape(sep) + return lume.array((str..sep):gmatch("(.-)("..psep..")")) + end +end + + +function lume.trim(str, chars) + if not chars then return str:match("^[%s]*(.-)[%s]*$") end + chars = patternescape(chars) + return str:match("^[" .. chars .. "]*(.-)[" .. chars .. "]*$") +end + + +function lume.wordwrap(str, limit) + limit = limit or 72 + local check + if type(limit) == "number" then + check = function(s) return #s >= limit end + else + check = limit + end + local rtn = {} + local line = "" + for word, spaces in str:gmatch("(%S+)(%s*)") do + local s = line .. word + if check(s) then + table.insert(rtn, line .. "\n") + line = word + else + line = s + end + for c in spaces:gmatch(".") do + if c == "\n" then + table.insert(rtn, line .. "\n") + line = "" + else + line = line .. c + end + end + end + table.insert(rtn, line) + return table.concat(rtn) +end + + +function lume.format(str, vars) + if not vars then return str end + local f = function(x) + return tostring(vars[x] or vars[tonumber(x)] or "{" .. x .. "}") + end + return (str:gsub("{(.-)}", f)) +end + + +function lume.trace(...) + local info = debug.getinfo(2, "Sl") + local t = { info.short_src .. ":" .. info.currentline .. ":" } + for i = 1, select("#", ...) do + local x = select(i, ...) + if type(x) == "number" then + x = string.format("%g", lume.round(x, .01)) + end + t[#t + 1] = tostring(x) + end + print(table.concat(t, " ")) +end + + +function lume.dostring(str) + return assert((loadstring or load)(str))() +end + + +function lume.uuid() + local fn = function(x) + local r = math.random(16) - 1 + r = (x == "x") and (r + 1) or (r % 4) + 9 + return ("0123456789abcdef"):sub(r, r) + end + return (("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"):gsub("[xy]", fn)) +end + + +function lume.hotswap(modname) + local oldglobal = lume.clone(_G) + local updated = {} + local function update(old, new) + if updated[old] then return end + updated[old] = true + local oldmt, newmt = getmetatable(old), getmetatable(new) + if oldmt and newmt then update(oldmt, newmt) end + for k, v in pairs(new) do + if type(v) == "table" then update(old[k], v) else old[k] = v end + end + end + local err = nil + local function onerror(e) + for k in pairs(_G) do _G[k] = oldglobal[k] end + err = lume.trim(e) + end + local ok, oldmod = pcall(require, modname) + oldmod = ok and oldmod or nil + xpcall(function() + package.loaded[modname] = nil + local newmod = require(modname) + if type(oldmod) == "table" then update(oldmod, newmod) end + for k, v in pairs(oldglobal) do + if v ~= _G[k] and type(v) == "table" then + update(v, _G[k]) + _G[k] = v + end + end + end, onerror) + package.loaded[modname] = oldmod + if err then return nil, err end + return oldmod +end + + +local ripairs_iter = function(t, i) + i = i - 1 + local v = t[i] + if v ~= nil then + return i, v + end +end + +function lume.ripairs(t) + return ripairs_iter, t, (#t + 1) +end + + +function lume.color(str, mul) + mul = mul or 1 + local r, g, b, a + r, g, b = str:match("#(%x%x)(%x%x)(%x%x)") + if r then + r = tonumber(r, 16) / 0xff + g = tonumber(g, 16) / 0xff + b = tonumber(b, 16) / 0xff + a = 1 + elseif str:match("rgba?%s*%([%d%s%.,]+%)") then + local f = str:gmatch("[%d.]+") + r = (f() or 0) / 0xff + g = (f() or 0) / 0xff + b = (f() or 0) / 0xff + a = f() or 1 + else + error(("bad color string '%s'"):format(str)) + end + return r * mul, g * mul, b * mul, a * mul +end + + +local chain_mt = {} +chain_mt.__index = lume.map(lume.filter(lume, iscallable, true), + function(fn) + return function(self, ...) + self._value = fn(self._value, ...) + return self + end + end) +chain_mt.__index.result = function(x) return x._value end + +function lume.chain(value) + return setmetatable({ _value = value }, chain_mt) +end + +setmetatable(lume, { + __call = function(_, ...) + return lume.chain(...) + end +}) + + +return lume diff --git a/loadassets.lua b/loadassets.lua index 2cc95c4..298fd55 100644 --- a/loadassets.lua +++ b/loadassets.lua @@ -27,7 +27,8 @@ gfx = { down = love.graphics.newImage('gfx/ui/buttons/down.png'), left = love.graphics.newImage('gfx/ui/buttons/left.png'), right = love.graphics.newImage('gfx/ui/buttons/right.png') - } + }, + bag = love.graphics.newImage('gfx/ui/bagui.png') }, hud = { frame = love.graphics.newImage('gfx/ui/hud/frame.png'), diff --git a/lootBags.lua b/lootBags.lua index e6e0ea8..44e52b1 100644 --- a/lootBags.lua +++ b/lootBags.lua @@ -3,7 +3,10 @@ lootBags = { server = { container = {} }, - client = {} + client = { + closest = {id=nil, dist=nil}, + heldItem = {bagId=nil, itemId=nil, offset={x=0, y=0}} + } } function lootBags.server.spawn(data) @@ -17,7 +20,7 @@ function lootBags.server.spawn(data) if data[k] == nil then data[k] = v end end - data.id = uuid() + data.id = lume.uuid() data.spawnTime = gameTime lootBags.server.container[data.id] = data @@ -46,8 +49,8 @@ function lootBags.server.reset() end function lootBags.server.update(dt) - for k, v in pairs(lootBags.server.container) do - if v.life and gameTime - v.spawnTime > v.life then + for k, bag in pairs(lootBags.server.container) do + if bag.life and gameTime - bag.spawnTime > bag.life then lootBags.server.destroy(k) end end @@ -55,18 +58,118 @@ end +lootBags.client.slots = {} +for i=1, 4 do + for j=1, 2 do + table.insert(lootBags.client.slots, { + x = 7 + (i-1)*18, + y = 22 + (j-1)*18, + w = 15, + h = 15 + }) + end +end + +function lootBags.client.update(dt) + local closest = {id=nil, dist=nil} + local px, py = player.body:getPosition() + for _, bag in pairs(client.currentState.lootBags) do + local dist = math.sqrt((bag.x - px)^2 + (bag.y - py)^2) + if not closest.dist or dist < closest.dist then + closest.id = bag.id + closest.dist = dist + end + end + lootBags.client.closest = closest +end + +function lootBags.client.mousepressed(x, y, btn) + local mx, my = window2game(x, y) + mx, my = lume.round(mx), lume.round(my) + mx, my = camera:screen2world(mx, my) + local bagId = lootBags.client.closest.id + if bagId and lootBags.client.closest.dist < 30 then + local bag = client.currentState.lootBags[bagId] + local img = gfx.ui.bag + local bmx = mx - (lume.round(bag.x) - lume.round(img:getWidth()/2)) + local bmy = my - (lume.round(bag.y) - img:getHeight() - 20) + for _, slot in ipairs(lootBags.client.slots) do + if bmx >= slot.x and bmx <= slot.x + slot.w + and bmy >= slot.y and bmy <= slot.y + slot.h then + local heldItem = lootBags.client.heldItem + heldItem.bagId = bag.id + -- item id + heldItem.offset.x = slot.x - bmx + heldItem.offset.y = slot.y - bmy + uiMouseDown = true + break + end + end + end +end + +function lootBags.client.mousereleased(x, y, btn) + local mx, my = window2game(x, y) + mx, my = lume.round(mx), lume.round(my) + mx, my = camera:screen2world(mx, my) + local bagId = lootBags.client.closest.id + local heldItem = lootBags.client.heldItem + if bagId and lootBags.client.closest.dist < 30 then + local bag = client.currentState.lootBags[bagId] + local img = gfx.ui.bag + local bmx = mx - (lume.round(bag.x) - lume.round(img:getWidth()/2)) + local bmy = my - (lume.round(bag.y) - img:getHeight() - 20) + for _, slot in ipairs(lootBags.client.slots) do + if bmx >= slot.x and bmx <= slot.x + slot.w + and bmy >= slot.y and bmy <= slot.y + slot.h then + -- drop item in slot + break + end + end + end + heldItem.bagId = nil +end + function lootBags.client.draw() - for _, v in pairs(client.currentState.lootBags) do + local mx, my = window2game(love.mouse.getPosition()) + mx, my = lume.round(mx), lume.round(my) + mx, my = camera:screen2world(mx, my) + for _, bag in pairs(client.currentState.lootBags) do local a = 1 - if v.life and client.serverTime - v.spawnTime > v.life - 3 then - local t = (client.serverTime - v.spawnTime - v.life + 3)/3 + if bag.life and client.serverTime - bag.spawnTime > bag.life - 3 then + local t = (client.serverTime - bag.spawnTime - bag.life + 3)/3 a = math.cos(t*5*math.pi)/4 + 1/4 + (1-t)/2 end love.graphics.setColor(1, 1, 1, a) love.graphics.push() - love.graphics.translate(math.floor(v.x), math.floor(v.y)) - local img = gfx.items[v.type] - love.graphics.draw(img, 0, 0, 0, 1, 1, img:getWidth()/2, img:getHeight()) + love.graphics.translate(lume.round(bag.x), lume.round(bag.y)) + local img = gfx.items[bag.type] + love.graphics.draw(img, 0, 0, 0, 1, 1, lume.round(img:getWidth()/2), img:getHeight()) + if bag.id == lootBags.client.closest.id and lootBags.client.closest.dist < 30 then + local img = gfx.ui.bag + love.graphics.push() + love.graphics.translate(-lume.round(img:getWidth()/2), -img:getHeight() - 20) + love.graphics.draw(img, 0, 0) + local bmx = mx - (lume.round(bag.x) - lume.round(img:getWidth()/2)) + local bmy = my - (lume.round(bag.y) - img:getHeight() - 20) + for _, slot in ipairs(lootBags.client.slots) do + if bmx >= slot.x and bmx <= slot.x + slot.w + and bmy >= slot.y and bmy <= slot.y + slot.h then + love.graphics.setColor(1, 1, 1, 0.8) + else + love.graphics.setColor(1, 1, 1, 0.2) + end + love.graphics.rectangle('fill', slot.x, slot.y, slot.w, slot.h) + end + love.graphics.setColor(1, 0, 0, 0.4) + love.graphics.rectangle('fill', bmx, bmy, 2, 2) + love.graphics.pop() + end love.graphics.pop() end + local heldItem = lootBags.client.heldItem + if heldItem.bagId then + love.graphics.setColor(1, 1, 1, 0.8) + love.graphics.rectangle('fill', mx + heldItem.offset.x, my + heldItem.offset.y, 15, 15) + end end diff --git a/main.lua b/main.lua index ec871e7..bafe051 100644 --- a/main.lua +++ b/main.lua @@ -1,11 +1,12 @@ +lume = require 'lib.lume' +nut = require 'lib.love_nut' +json = require 'lib.json' +Camera = require 'lib.camera' + require 'utils' require 'loadassets' require 'text' -Camera = require 'camera' -camera = Camera{ssx=gsx, ssy=gsy} -nut = require 'love_nut' -json = require 'json' require 'server' require 'client' require 'menu' @@ -19,9 +20,12 @@ require 'lootBags' require 'chat' function love.load() + camera = Camera{ssx=gsx, ssy=gsy} gameState = 'menu' time = 0 gameTime = 0 + -- don't shoot if pressing ui + uiMouseDown = false drawDebug = false menu.load() hud.load() @@ -34,7 +38,8 @@ function love.resize(w, h) gameScale = math.min(ssx/gsx, ssy/gsy) end -function screen2game(x, y) +-- window to game canvas +function window2game(x, y) x = x - (ssx-gameScale*gsx)/2 x = x / gameScale y = y - (ssy-gameScale*gsy)/2 @@ -75,6 +80,7 @@ function love.mousepressed(x, y, btn, isTouch) if gameState == 'playing' then player.mousepressed(x, y, btn) hud.mousepressed(x, y, btn) + lootBags.client.mousepressed(x, y, btn) end menu.mousepressed(x, y, btn) end @@ -83,8 +89,10 @@ function love.mousereleased(x, y, btn, isTouch) if gameState == 'playing' then player.mousereleased(x, y, btn) hud.mousereleased(x, y, btn) + lootBags.client.mousereleased(x, y, btn) end menu.mousereleased(x, y, btn) + uiMouseDown = false end function love.textinput(t) @@ -130,7 +138,7 @@ function love.keypressed(k, scancode, isrepeat) end function love.draw() - local mx, my = screen2game(love.mouse.getPosition()) + local mx, my = window2game(love.mouse.getPosition()) love.graphics.setCanvas(canvases.game2x) love.graphics.clear() love.graphics.setCanvas(canvases.game) @@ -169,7 +177,7 @@ function love.draw() chat.draw() love.graphics.setColor(1, 1, 1) - love.graphics.draw(gfx.cursors.main, math.floor(mx), math.floor(my), 0, 1, 1, 0, 0) -- hotspot 0, 0 + love.graphics.draw(gfx.cursors.main, lume.round(mx), lume.round(my), 0, 1, 1, 0, 0) -- hotspot 0, 0 end menu.draw() diff --git a/menu.lua b/menu.lua index 214a996..04440da 100644 --- a/menu.lua +++ b/menu.lua @@ -6,7 +6,6 @@ menu.buttons = {} menu.inputs = {} menu.infos = {} menu.activeInput = nil -menu.buttonDown = false menu.logoAnimTimer = 0 function menu.addButton(t) @@ -26,15 +25,15 @@ function menu.addButton(t) t.bw, t.bh = 0, 0 t.items = t.items or {''} for _, v in pairs(t.items) do - t.bw = math.max(math.floor(t.font:getWidth(v) + 8), t.bw) - t.bh = math.max(math.floor(t.font:getHeight() + 4), t.bh) + t.bw = math.max(lume.round(t.font:getWidth(v) + 8), t.bw) + t.bh = math.max(lume.round(t.font:getHeight() + 4), t.bh) end else - t.bw = math.floor(t.font:getWidth(t.text) + 8) - t.bh = math.floor(t.font:getHeight() + 4) + t.bw = lume.round(t.font:getWidth(t.text) + 8) + t.bh = lume.round(t.font:getHeight() + 4) end - t.bx = math.floor(t.x - t.bw/2) - t.by = math.floor(t.y - t.bh/2) + t.bx = lume.round(t.x - t.bw/2) + t.by = lume.round(t.y - t.bh/2) if not menu.buttons[t.state] then menu.buttons[t.state] = {} end table.insert(menu.buttons[t.state], t) return t @@ -52,11 +51,11 @@ function menu.addInput(t) for k, v in pairs(defaults) do if t[k] == nil then t[k] = v end end - t.w = math.floor(t.w or 80) + t.w = lume.round(t.w or 80) t.bw = t.w - t.bh = math.floor(t.font:getHeight() + 4) - t.bx = math.floor(t.x - t.bw/2) - t.by = math.floor(t.y - t.bh/2) + t.bh = lume.round(t.font:getHeight() + 4) + t.bx = lume.round(t.x - t.bw/2) + t.by = lume.round(t.y - t.bh/2) if not menu.inputs[t.state] then menu.inputs[t.state] = {} end table.insert(menu.inputs[t.state], t) return t @@ -205,14 +204,14 @@ function menu.load() love.graphics.rectangle('fill', v.bx, v.by, v.bw, v.bh) love.graphics.setColor(0.8, 0.8, 0.8) love.graphics.setFont(v.font) - text.print(v.text, math.floor(v.x - v.font:getWidth(v.text)/2), math.floor(v.by - v.font:getHeight())) + text.print(v.text, lume.round(v.x - v.font:getWidth(v.text)/2), lume.round(v.by - v.font:getHeight())) love.graphics.setColor(1, 1, 1) local txt = v.items[v.active] if fullscreen and fstype == 'desktop' then local w, h = love.graphics.getDimensions() txt = w .. 'x' .. h end - text.print(txt, math.floor(v.x - v.font:getWidth(txt)/2), math.floor(v.y - v.font:getHeight()/2)) + text.print(txt, lume.round(v.x - v.font:getWidth(txt)/2), lume.round(v.y - v.font:getHeight()/2)) end} menu.fullscreenBtn = menu.addButton{state='options', text='Fullscreen', y=exitY - h*3, type='cycle', items={'Windowed', 'Borderless Fullscreen Windowed', 'Fullscreen'}, @@ -288,7 +287,7 @@ function menu.update(dt) end function menu.mousepressed(mx, my, btn) - mx, my = screen2game(mx, my) + mx, my = window2game(mx, my) if gameState == 'menu' then menu.activeInput = nil for _, v in pairs(menu.buttons[menu.state] or {}) do @@ -302,7 +301,7 @@ function menu.mousepressed(mx, my, btn) else if v.action then v.action() end end - menu.buttonDown = true + uiMouseDown = true return end end @@ -316,7 +315,7 @@ function menu.mousepressed(mx, my, btn) end function menu.mousereleased(mx, my, btn) - menu.buttonDown = false + end function menu.textinput(t) @@ -363,13 +362,13 @@ end function menu.draw() if gameState == 'menu' then - local mx, my = screen2game(love.mouse.getPosition()) + local mx, my = window2game(love.mouse.getPosition()) if menu.state == 'main' then love.graphics.setColor(1, 1, 1) local logoFrameIdx = math.floor(menu.logoAnimTimer*12) % #anims.logo.quads + 1 local quad = anims.logo.quads[logoFrameIdx] - love.graphics.draw(gfx.logoAnim, quad, math.floor(gsx/2 - gfx.logo:getWidth()/2), 12) + love.graphics.draw(gfx.logoAnim, quad, lume.round(gsx/2 - gfx.logo:getWidth()/2), 12) end for _, v in pairs(menu.buttons[menu.state] or {}) do if v.draw then @@ -389,11 +388,11 @@ function menu.draw() love.graphics.setFont(v.font) if v.type == 'cycle' then love.graphics.setColor(0.8, 0.8, 0.8) - text.print(v.text, math.floor(v.x - v.font:getWidth(v.text)/2), math.floor(v.by - v.font:getHeight())) + text.print(v.text, lume.round(v.x - v.font:getWidth(v.text)/2), lume.round(v.by - v.font:getHeight())) txt = v.items[v.active] end love.graphics.setColor(1, 1, 1) - text.print(txt, math.floor(v.x - v.font:getWidth(txt)/2), math.floor(v.y - v.font:getHeight()/2)) + text.print(txt, lume.round(v.x - v.font:getWidth(txt)/2), lume.round(v.y - v.font:getHeight()/2)) end end for _, v in pairs(menu.inputs[menu.state] or {}) do @@ -409,12 +408,12 @@ function menu.draw() love.graphics.rectangle('fill', v.bx, v.by, v.bw, v.bh) love.graphics.setColor(0.8, 0.8, 0.8) love.graphics.setFont(v.font) - text.print(v.text, math.floor(v.x - v.font:getWidth(v.text)/2), math.floor(v.by - v.font:getHeight())) + text.print(v.text, lume.round(v.x - v.font:getWidth(v.text)/2), lume.round(v.by - v.font:getHeight())) local txt = v.value if menu.activeInput == v then txt = txt .. (time % 1 < 0.5 and '' or '|') end love.graphics.setColor(1, 1, 1) love.graphics.setFont(v.font) - text.print(txt, math.floor(v.x - v.font:getWidth(txt)/2), math.floor(v.y - v.font:getHeight()/2)) + text.print(txt, lume.round(v.x - v.font:getWidth(txt)/2), lume.round(v.y - v.font:getHeight()/2)) end end for _, v in pairs(menu.infos[menu.state] or {}) do @@ -423,7 +422,7 @@ function menu.draw() else love.graphics.setColor(1, 1, 1) love.graphics.setFont(v.font) - text.print(v.text, math.floor(v.x - v.font:getWidth(v.text)/2), math.floor(v.y - v.font:getHeight()/2)) + text.print(v.text, lume.round(v.x - v.font:getWidth(v.text)/2), lume.round(v.y - v.font:getHeight()/2)) end end end diff --git a/player.lua b/player.lua index e90e487..0fe2a53 100644 --- a/player.lua +++ b/player.lua @@ -29,30 +29,12 @@ end function player.newStats() local t = { - vit = { - base = 100, - arm = 14, - }, - atk = { - base = 80, - arm = 25, - }, - spd = { - base = 50, - arm = 9, - }, - wis = { - base = 100, - arm = 8, - }, - def = { - base = 20, - arm = 25, - }, - reg = { - base = 50, - arm = 10, - } + vit = {base = 100, arm = 14}, + atk = {base = 80, arm = 25}, + spd = {base = 50, arm = 9}, + wis = {base = 100, arm = 8}, + def = {base = 20, arm = 25}, + reg = {base = 50, arm = 10} } for _, v in pairs(t) do v.total = v.base + v.arm @@ -76,7 +58,7 @@ function player.serialize() end function player.swing() - local mx, my = screen2game(love.mouse.getPosition()) + local mx, my = window2game(love.mouse.getPosition()) player.direction = mx < gsx/2 and -1 or 1 player.swinging = true player.swingTimer = 0 @@ -94,7 +76,7 @@ function player.swing() end function player.update(dt) - local mx, my = screen2game(love.mouse.getPosition()) + local mx, my = window2game(love.mouse.getPosition()) if not chat.active then local dx, dy = 0, 0 @@ -104,7 +86,7 @@ function player.update(dt) dy = dy + (love.keyboard.isScancodeDown('s') and 1 or 0) local spd = player.spd*(love.keyboard.isScancodeDown('lshift') and 2.5 or 1) if not (dx == 0 and dy == 0) - and not (player.swinging or player.automaticSwing and love.mouse.isDown(1)) then + and not (player.swinging or player.automaticSwing and love.mouse.isDown(1) and not uiMouseDown) then local a = math.atan2(dx, dy) - math.pi/2 player.body:applyForce(math.cos(a)*spd, -math.sin(a)*spd) end @@ -127,8 +109,7 @@ function player.update(dt) if xv > 0 then player.direction = 1 end end end - if player.automaticSwing and love.mouse.isDown(1) - and not menu.buttonDown and not hud.buttonDown then + if player.automaticSwing and love.mouse.isDown(1) and not uiMouseDown then player.swing() end end @@ -137,13 +118,12 @@ function player.update(dt) local dy = my - gsy/2 local a = math.atan2(dx, dy) - math.pi/2 local d = math.min(math.sqrt(dx^2 + dy^2), gsy/2) - camera.x = math.floor(player.body:getX()) + math.floor(math.cos(a)*d/6) - camera.y = math.floor(player.body:getY() - 14) + math.floor(-math.sin(a)*d/6) + camera.x = lume.round(player.body:getX()) + lume.round(math.cos(a)*d/6) + camera.y = lume.round(player.body:getY() - 14) + lume.round(-math.sin(a)*d/6) end function player.mousepressed(x, y, btn) - if not player.automaticSwing and not player.swinging - and not menu.buttonDown and not hud.buttonDown then + if not player.automaticSwing and not player.swinging and not uiMouseDown then player.swing() end end @@ -164,7 +144,7 @@ function player.draw() -- shadow love.graphics.setColor(0, 0, 0, 0.2) local shadowWidth = 5 - love.graphics.ellipse('fill', math.floor(v.x), math.floor(v.y), shadowWidth, 2) + love.graphics.ellipse('fill', lume.round(v.x), lume.round(v.y), shadowWidth, 2) -- player love.graphics.setCanvas(canvases.tempGame) @@ -174,9 +154,9 @@ function player.draw() local quad = anims.player.swing.quads[1] local _, _, w, h = quad:getViewport() love.graphics.draw(anims.player.swing.sheet, quad, - math.floor(v.x), math.floor(v.y), - 0, 1, 1, - 23, h) + lume.round(v.x), lume.round(v.y), + 0, 1, 1, + 23, h) -- outline love.graphics.setCanvas(_canvas) @@ -195,7 +175,7 @@ function player.draw() -- name local font = fonts.c17 love.graphics.setFont(font) - text.printSmall(v.name, math.floor(v.x) - font:getWidth(v.name)/4, math.floor(v.y) - 40) + text.printSmall(v.name, lume.round(v.x) - font:getWidth(v.name)/4, lume.round(v.y) - 40) end end @@ -210,7 +190,7 @@ function player.draw() local walkFrameIdx = math.floor(player.walkTimer*12) % #anims.player.walk.quads + 1 local shadowWidth = ({6, 5, 4, 5, 5})[walkFrameIdx] if player.swinging or vd < 10 then shadowWidth = 6 end - love.graphics.ellipse('fill', math.floor(px), math.floor(py), shadowWidth, 2) + love.graphics.ellipse('fill', lume.round(px), lume.round(py), shadowWidth, 2) -- player love.graphics.setCanvas(canvases.tempGame) @@ -219,28 +199,28 @@ function player.draw() love.graphics.setColor(1, 1, 1) if player.swinging then local frameIdx = math.floor(player.swingTimer*12) + 1 - frameIdx = clamp(frameIdx, 1, 5) + frameIdx = lume.clamp(frameIdx, 1, 5) local quad = anims.player.swing.quads[frameIdx] local _, _, w, h = quad:getViewport() love.graphics.draw(anims.player.swing.sheet, quad, - math.floor(px), math.floor(py), - 0, player.direction, 1, - 23, h) + lume.round(px), lume.round(py), + 0, player.direction, 1, + 23, h) else if vd < 10 then local quad = anims.player.swing.quads[1] local _, _, w, h = quad:getViewport() love.graphics.draw(anims.player.swing.sheet, quad, - math.floor(px), math.floor(py), - 0, player.direction, 1, - 23, h) + lume.round(px), lume.round(py), + 0, player.direction, 1, + 23, h) else local quad = anims.player.walk.quads[walkFrameIdx] local _, _, w, h = quad:getViewport() love.graphics.draw(anims.player.walk.sheet, quad, - math.floor(px), math.floor(py), - 0, player.direction, 1, - 8, h) + lume.round(px), lume.round(py), + 0, player.direction, 1, + 8, h) end end @@ -261,11 +241,11 @@ function player.draw() -- name local font = fonts.c17 love.graphics.setFont(font) - text.printSmall(player.name, math.floor(px) - font:getWidth(player.name)/4, math.floor(py) - 40) + text.printSmall(player.name, lume.round(px) - font:getWidth(player.name)/4, lume.round(py) - 40) if drawDebug then love.graphics.setColor(1, 0, 0, 0.5) love.graphics.circle('fill', - math.floor(px), math.floor(py), player.shape:getRadius()) + lume.round(px), lume.round(py), player.shape:getRadius()) end end diff --git a/projectiles.lua b/projectiles.lua index f7108c3..dc93784 100644 --- a/projectiles.lua +++ b/projectiles.lua @@ -19,7 +19,7 @@ function projectiles.server.spawn(data) if data[k] == nil then data[k] = v end end - data.id = uuid() + data.id = lume.uuid() data.type = 'playerSwing' data.spawnTime = gameTime data.body = love.physics.newBody(physics.server.world, data.x, data.y, 'dynamic') @@ -104,7 +104,7 @@ function projectiles.client.draw() love.graphics.clear() love.graphics.setColor(192/255, 192/255, 192/255) love.graphics.push() - love.graphics.translate(math.floor(v.x), math.floor(v.y)) + love.graphics.translate(lume.round(v.x), lume.round(v.y)) love.graphics.rotate(-v.angle) for _, poly in pairs(v.polys) do love.graphics.polygon('fill', poly) diff --git a/server.lua b/server.lua index 21ab87c..7b91f9e 100644 --- a/server.lua +++ b/server.lua @@ -126,7 +126,7 @@ end function server.addPlayer(name, clientId) local p = { - id = uuid(), name = name, + id = lume.uuid(), name = name, x = (math.random()*2-1)*128, y = (math.random()*2-1)*128, xp = 0, stats = player.newStats() } diff --git a/text.lua b/text.lua index 03273df..7869d8c 100644 --- a/text.lua +++ b/text.lua @@ -4,7 +4,7 @@ text = {} function text.print(txt, x, y, fontAlias) local _shader = love.graphics.getShader() if fontAlias then love.graphics.setShader(shaders.fontAlias) end - love.graphics.print(txt, math.floor(x), math.floor(y)) + love.graphics.print(txt, lume.round(x), lume.round(y)) love.graphics.setShader(_shader) end @@ -23,8 +23,8 @@ function text.printSmall(txt, x, y, fontAlias) love.graphics.rotate(camera.rotation) love.graphics.translate(-camera.x*2, -camera.y*2) end - - love.graphics.print(txt, math.floor(x*2), math.floor(y*2)) + + love.graphics.print(txt, lume.round(x*2), lume.round(y*2)) love.graphics.pop() love.graphics.setCanvas(_canvas) diff --git a/utils.lua b/utils.lua index f96d4f7..84944df 100644 --- a/utils.lua +++ b/utils.lua @@ -7,19 +7,6 @@ function safeIndex(t, ...) return t end -function clamp(x, a, b) - if a < b then - return math.min(math.max(x, a), b) - else - return math.min(math.max(x, b), a) - end -end - -function lerp(a, b, t) - if math.abs(b-a) < 1e-9 then return b end - return clamp((1-t)*a + t*b, a, b) -end - function lerpAngle(a, b, t) local theta = b - a if theta > math.pi then @@ -27,7 +14,7 @@ function lerpAngle(a, b, t) elseif theta < -math.pi then a = a - 2*math.pi end - return lerp(a, b, t) + return lume.lerp(a, b, t) end function hash(x) @@ -58,11 +45,3 @@ ease = { function buildName(name, postfix) return name .. (postfix ~= 0 and '(' .. postfix .. ')' or '') end - -function uuid() - local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' - return string.gsub(template, '[xy]', function (c) - local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) - return string.format('%x', v) - end) -end