local G = love.graphics local common = require 'common' local Camera = require'r.camera' local Pos = require"r.pos" local Rect = require'r.rect' local class = require'r.class' local enet = require'enet' local json = require'dkjson' local rle = require'r.rle' local print_good = require'r.print_good' local rmath = require'r.math' local msgbox = require'r.msgbox' local utf8 = require'utf8' local M = {} local SPEED = 8 -- tiles per second local colors = {[true]={141/255,128/255,22/255}, [false]={71/255,50/255,122/255}} local players = {} local chunks = common.ChunkMap() local lp = { pos=Pos(0,0), movetimer=0, dir=nil } -- local player local cam = Camera(nil, 20) local host, conn function M.load(_host,_conn,j) host=_host conn=_conn lp.pos=Pos(j.pos.x,j.pos.y) lp.name=j.name lp.color=j.color end local show={ui=true,debug=false} local chatmsg = nil local chatmsg_text = G.newText(G.getFont()) local function chat_key(k,s,r) if k == 'escape' then chatmsg = nil elseif k == 'return' then if #chatmsg>0 then msgbox.add(lp.name..': '..chatmsg) conn:send(json.encode{type='chat',msg=chatmsg}) end chatmsg = nil elseif k == 'backspace' and #chatmsg>0 then chatmsg = chatmsg:sub(1,utf8.offset(chatmsg,-1)-1) end end function M.textinput(str) if chatmsg then chatmsg = chatmsg..str end end local t = 0 local function smoovement(player) if not player.oldpos then return player.pos end return rmath.clerp(player.oldpos,player.pos,(t-player.at)*16) end local function moveplayer(player,newpos) player.oldpos = player.pos player.pos = newpos player.at = t end local directions = {w=Pos(0,-1),a=Pos(-1,0),s=Pos(0,1),d=Pos(1,0)} function M.keypressed(k,s,r) if chatmsg then chat_key(k,s,r) else if directions[s] then if not love.keyboard.isScancodeDown('lshift') then lp.dir = s else local tgt = lp.pos + directions[s] local val = not chunks:tile(tgt); chunks:set_tile(tgt,val) conn:send(json.encode{type='tile',pos=tgt,tile=val}) end elseif k=='space' then cam.zoom = cam.zoom == 10 and 20 or 10 elseif k=='tab' then show.ui = not show.ui elseif k=='return' then chatmsg = '' lp.dir = nil elseif k=='f3' then show.debug = not show.debug end end end function M.keyreleased(k,s) if s==lp.dir then lp.dir=nil end end function lp.update(dt) lp.movetimer = lp.movetimer - dt if lp.movetimer <= 0 and lp.dir then local d = directions[lp.dir] local newpos = lp.pos+d if chunks:tile(newpos) == false then conn:send(json.encode{type='move',pos=newpos}) moveplayer(lp,newpos) lp.movetimer = 1 / SPEED end end end local function draw_player(player,no_label) local effpos = smoovement(player) G.setColor(player.color) G.circle('fill',effpos.x,effpos.y,0.3) if show.ui and not no_label then local f = G.getFont() local txtw,h = f:getWidth(player.name), f:getHeight() local centre = cam:world_to_screen(effpos-Pos(0,.4))-Pos(0,h/2) local bb = Rect:from_centre_dims(centre,txtw,h) G.push() G.origin() G.setColor(0,0,0,0.4) bb:draw'fill' G.setColor(1,1,1) G.print(player.name,bb.tl:floor():vals()) G.pop() end end function lp.draw() draw_player(lp,true) end function M.update(dt) t = t + dt lp.update(dt) msgbox.update(dt) local ev = host and host:service() while ev do if ev.type == 'receive' then local j = json.decode(ev.data) local pos if j.pos then pos = Pos(j.pos.x,j.pos.y) end if j.type == 'player' then players[j.name] = {name=j.name,pos=pos,color=j.color,at=t} msgbox.add(j.name..' joined') elseif j.type == 'unplayer' then players[j.from] = nil msgbox.add(j.from..' left') elseif j.type == 'move' then moveplayer(players[j.from],pos) elseif j.type == 'chunk' then chunks:add(pos,{d=rle.decode(j.d)}) elseif j.type == 'unchunk' then chunks:remove(pos) elseif j.type == 'tile' then chunks:set_tile(pos,j.tile) elseif j.type == 'chat' then msgbox.add(j.from..': '..j.msg) end end ev = host and host:service() end end function M.draw() G.clear(1,1,1); G.origin() cam.pos = smoovement(lp); cam:apply_trans() local tl,br = cam:extents() tl = tl:floor() br = br:ceil() for x=tl.x,br.x do for y=tl.y,br.y do local t = chunks:tile(Pos(x,y)) if t ~= nil then G.setColor(colors[t~=(x<0)]) G.rectangle('fill',x-0.5,y-0.5,1,1) end end end lp.draw() local playernames = {} for _,player in pairs(players) do draw_player(player) table.insert(playernames,player.name) end table.sort(playernames) playernames = table.concat(playernames,'\n') G.origin() if show.ui then msgbox.draw() print_good(playernames,'end',0) end if chatmsg then chatmsg_text:setFont(G.getFont()) chatmsg_text:set(lp.name..': '..chatmsg) local W,H = G.getDimensions() local tw,th = chatmsg_text:getDimensions() local y = H-th-30 G.setColor(0,0,0,0.8) G.rectangle('fill',0,y,W,th) G.setColor(1,1,1) G.draw(chatmsg_text,0,y) G.setColor(.8,.8,.8) G.line(tw,y,tw,y+th) end if show.debug then G.setColor(1,0,0) G.print(tostring(lp.pos),100,100) G.setColor(0,0,0,0.8) G.rectangle('fill',0,0,100,100) G.setColor(1,1,1) for cx=-7,7 do for cy=-7,7 do local p=Pos(cx,cy) if chunks:get(p) then p = (p + Pos(7,7))*10 G.setColor(1,1,1) G.rectangle('fill',p.x,p.y,10,10) G.setColor(0,0,1) G.rectangle('line',p.x,p.y,10,10) end end end local p = (lp.pos/common.SIZE+Pos(7,7))*10 G.setColor(1,0,0) G.rectangle('fill',p.x-1,p.y-1,2,2) end end return M