Skip to content

Commit

Permalink
Merge pull request #1 from parameterized/dev
Browse files Browse the repository at this point in the history
0.1.0
  • Loading branch information
parameterized authored Jan 1, 2019
2 parents 5f8e03f + f419fdf commit 62fec4b
Show file tree
Hide file tree
Showing 82 changed files with 7,792 additions and 1 deletion.
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
# tier

# Tier

Open World RPG

*Current version: 0.1.0*<br>
*Uses Love2D version 11.1.0*

![](https://i.imgur.com/rF9idF9.png)

## Running
Windows builds can be found on the [releases](https://github.com/parameterized/tier/releases) page

Instructions for running Love2D games from source can be found [here](https://love2d.org/wiki/Getting_Started)
If you're on Windows, the easiest way to run is to drag the folder containing main.lua onto either love.exe or a shortcut to love.exe (C:\\Program Files\\LOVE\\love.exe)

## Controls
- WASD to move
- Left Shift to sprint
- Left Mouse Button to attack
- Right click to transfer item
- Shift-click or double-click to use item
- E to interact
- Enter to open chat
- Tab to toggle inventory
- M to toggle map
- L to toggle levels/stats
- F1 to toggle debug info
63 changes: 63 additions & 0 deletions chat.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

chat = {
log = {},
active = false,
val = '',
lastMsgTime = -1
}

function chat.addMsg(v)
table.insert(chat.log, v)
chat.lastMsgTime = gameTime
end

function chat.submit()
if chat.val ~= '' then
client.sendMessage(chat.val)
chat.lastMsgTime = gameTime
end
chat.val = ''
chat.active = false
end

function chat.textinput(t)
chat.val = chat.val .. t
end

function chat.keypressed(k, scancode, isrepeat)
if chat.active then
if k == 'escape' then
chat.val = ''
chat.active = false
elseif k == 'return' and not isrepeat then
chat.submit()
elseif k == 'backspace' then
chat.val = chat.val:sub(0, math.max(chat.val:len()-1, 0))
elseif k == 'v' and (love.keyboard.isScancodeDown('lctrl') or love.keyboard.isScancodeDown('rctrl')) then
local paste = love.system.getClipboardText()
chat.val = chat.val .. paste
end
elseif hud.chatPanel.open then
if k == 'escape' then
hud.chatPanel.open = false
end
end
end

function chat.draw()
love.graphics.setColor(1, 1, 1)
love.graphics.setFont(fonts.c17)
local startIdx = math.max(#chat.log - 10 + 1, 1)
local numMsgs = #chat.log - startIdx + 1
local cpy = hud.chatPanel.y
for i=1, numMsgs do
local v = chat.log[startIdx + (i-1)]
local y = cpy + 118 - (numMsgs - (i-1) + 1)*10 + 8
text.printSmall(v, 14, y)
end
local txt = chat.val
if chat.active then
txt = txt .. (time % 1 < 0.5 and '' or '|')
end
text.printSmall(txt, 14, cpy + 118)
end
243 changes: 243 additions & 0 deletions client.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@

client = {}

client.interpolate = true

function client.connect(ip, port)
port = tonumber(port)
client.nutClient = nut.client()
client.nutClient:addRPCs{
chatMsg = function(self, data)
chat.addMsg(data)
end,
serverClosed = function(self, data)
-- todo: show message in game
print('server closed')
gameState = 'menu'
menu.state = 'main'
client.close()
love.mouse.setGrabbed(false)
end
}
local bitserRPCs = {
returnPlayer = function(self, data)
client.startGame(data)
end,
add = function(self, data)
for _, v in pairs(data.projectiles) do
v.startedMoving = false
client.currentState.projectiles[v.id] = v
end
for _, v in pairs(data.entities) do
entities.client.defs[v.type]:new(v):spawn()
end
for _, v in pairs(data.lootBags) do
lootBag.client:new(v):spawn()
end
for _, v in pairs(data.portals) do
client.currentState.portals[v.id] = v
end
end,
remove = function(self, data)
for _, id in pairs(data.projectiles) do
client.currentState.projectiles[id] = nil
end
for _, id in pairs(data.entities) do
local ent = client.currentState.entities[id]
if ent then ent:destroy() end
end
for _, id in pairs(data.lootBags) do
local bag = clientRealm.lootBags[id]
if bag then bag:destroy() end
end
for _, id in pairs(data.portals) do
client.currentState.portals[id] = nil
end
end,
stateUpdate = function(self, data)
client.serverTime = data.time
-- todo: delete old states (or make replay feature)
-- todo: multiple states in update -
-- - 20fps update -> 60fps replay, (3 states per update)
table.insert(client.states, data)
--[[
if #client.states == 2 then
client.stateTime = client.states[1].time
end
]]
end,
returnItem = function(self, data)
items.client.container[data.id] = data.item
items.client.requested[data.id] = nil
end,
bagUpdate = function(self, data)
local bag = clientRealm.lootBags[data.id]
if bag then
for k, v in pairs(data) do
bag[k] = v
end
end
end,
setWorldChunk = function(self, data)
clientRealm.world:setChunk(data.x, data.y, data.chunk)
end,
teleportPlayer = function(self, data)
playerController.player.body:setPosition(data.x, data.y)
end,
healPlayer = function(self, data)
local p = playerController.player
p.hp = math.min(p.hp + data.hp, p.hpMax)
end
}
for k, v in pairs(bitserRPCs) do
bitserRPCs[k] = function(self, data)
local ok, data = pcall(bitser.loads, data)
if ok then
v(self, data)
else
print('error decoding client rpc ' .. k)
end
end
end
client.nutClient:addRPCs(bitserRPCs)
client.nutClient:addUpdate(function(self)
if gameState == 'playing' then
self:sendRPC('setPlayer', bitser.dumps(playerController.player:serialize()))
end
end)
client.nutClient:connect(ip, port)
client.connected = true
client.nutClient:sendRPC('requestPlayer', menu.nameInput.value)

client.serverTime = 0
client.states = {}
client.stateIdx = 1
client.stateTime = 0
-- cleanup previous connection
if client.currentState then
entities.client.reset()
clientRealm:destroy()
slimeBalls.reset()
items.client.reset()
collectgarbage()
end
client.currentState = client.newState()

menu.writeDefaults()

clientRealm:load()
playerController.load()
end

function client.newState()
return {entities={}, projectiles={}, lootBags={}, portals={}}
end

function client.startGame(data)
playerController.serverId = data.id
local p = playerController.player
p.name = data.name
p:setState(data)
gameState = 'playing'
if menu.cursorLockBtn.active then love.mouse.setGrabbed(true) end
end

function client.update(dt)
client.nutClient:update(dt)
if not (server.running and server.paused) then
client.serverTime = client.serverTime + dt
end
-- interpolate states
local cs_0 = client.states[#client.states]
local cs_1 = client.states[#client.states-1]
local cs_2 = client.states[#client.states-2]
local cs_3 = client.states[#client.states-3]
if cs_0 and cs_1 and cs_2 and cs_3 then
-- todo: better interpolation with less delay -
-- - no vsync on server seems to lessen jitter - threading probably will too
--[[
if client.stateTime >= cs_0.time then
print('clamp down ' .. math.abs(client.stateTime - cs_0.time))
elseif client.stateTime <= cs_3.time then
print('clamp up ' .. math.abs(client.stateTime - cs_3.time))
end
]]
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 = lume.lerp(client.stateTime, cs_1.time, lume.clamp(dt, 0, 1))
elseif client.stateTime < cs_2.time then
--print('lerp up')
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]
and client.states[client.stateIdx+1].time < client.stateTime do
client.stateIdx = client.stateIdx + 1
client.states[client.stateIdx-1] = false
end
local t = (client.stateTime - client.states[client.stateIdx].time)
/ (client.states[client.stateIdx+1].time - client.states[client.stateIdx].time)
--t = lume.clamp(t, 0, 1) -- t>1 = prediction
if not client.interpolate then
t = 1
end
local csi = client.states[client.stateIdx]
local csi_1 = client.states[client.stateIdx+1]
for k, v in pairs(csi.projectiles) do
local v2 = csi_1.projectiles[k]
if v2 then
local obj = client.currentState.projectiles[k]
if obj then
obj.x = lume.lerp(v.x, v2.x, t)
obj.y = lume.lerp(v.y, v2.y, t)
obj.startedMoving = true
end
end
end
for k, v in pairs(csi.entities) do
local v2 = csi_1.entities[k]
if v2 then
local obj = client.currentState.entities[k]
if obj then
if not entities.client.defs[obj.type].static then
obj:lerpState(v, v2, t)
end

if k == playerController.serverId then
local p = playerController.player
p.xp = obj.xp
p.stats = obj.stats
p.inventory = obj.inventory
end
end
end
end
end

if not (server.running and server.paused) then
gameTime = gameTime + dt
hud.update(dt)
clientRealm:update(dt)
playerController.update(dt)
entities.client.update(dt)
slimeBalls.update(dt)
end
end

function client.sendMessage(msg)
if client.connected then
client.nutClient:sendRPC('chatMsg', msg)
end
end

for _, v in pairs{'spawnProjectile', 'moveItem', 'dropItem', 'useItem', 'usePortal'} do
client[v] = function(data)
client.nutClient:sendRPC(v, bitser.dumps(data))
end
end

function client.close()
client.nutClient:close()
client.connected = false
end
10 changes: 10 additions & 0 deletions conf.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

function love.conf(t)
t.title = 'Tier'
t.identity = t.title
t.window.width = 480*3
t.window.height = 270*3
t.window.resizable = true
t.window.vsync = false
t.console = true
end
21 changes: 21 additions & 0 deletions cursor.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

cursor = {}

cursor.main = {
img = gfx.cursors.main,
ox = 0, oy = 0
}
cursor.hand = {
img = gfx.cursors.hand,
ox = 2, oy = 0
}

cursor.cursor = cursor.main

function cursor.draw()
local mx, my = window2game(love.mouse.getPosition())
mx, my = lume.round(mx), lume.round(my)

love.graphics.setColor(1, 1, 1)
love.graphics.draw(cursor.cursor.img, mx, my, 0, 1, 1, cursor.cursor.ox, cursor.cursor.oy)
end
Loading

0 comments on commit 62fec4b

Please sign in to comment.