-- Necklace of the Eye v5.2 roguelike frontend -- Copyright (C) 2010-2012 Zeno Rogue, see COPYING for details -- mode constants modeASCII = 1 modeTiles = 2 modeFPP = 3 modeISO = 4 modeMini = 5 modeMed = 6 -- profiling if not profiling then profiling = {} profilingq = {} end function profstart(x) if not profiling[x] then profiling[x] = 0 profilingq[x] = 0 end profiling[x] = profiling[x] - os.clock() profilingq[x] = profilingq[x] + 1 end function profend(x) profiling[x] = profiling[x] + os.clock() end function profinfo() logprint("profile results:\n") for k,v in pairs(profiling) do logprint(k.."="..v.." ("..profilingq[k]..")\n") end logprint("\n") end -- message system messages = {} function localmessage(str) message = str table.insert(messages, {at = os.clock() + 10, text = str}) end facedir = 0 function changeface(d, type, onlydown) ofd = facedir if gamefourdir then d = 2*d end if type == evKeyDown and onlydown then facedir = ofd + d drawandrefresh() elseif type == evKeyDown then facedir = ofd + 0.5 * d drawandrefresh() else facedir = math.floor((ofd + 0.5 * d) % 8 + .001) drawandrefresh() setfacedir(facedir) end end function upmodifier() return (diagleft and KMOD_LSHIFT or 0) + (diagright and KMOD_RSHIFT or 0) end function downmodifier() return (diagleft and KMOD_LCTRL or 0) + (diagright and KMOD_RCTRL or 0) end function modon(ev, x) return bAND(ev.mod, x) > 0 end function modup(ev) return modon(ev, upmodifier()) end function moddn(ev) return modon(ev, downmodifier()) end dirkeys = numpad function modupdown(ev) if ev.symbol == SDLK_RIGHT and modup(ev) then ev.symbol = SDLK_PAGEUP ev.mod = 0 end if ev.symbol == SDLK_RIGHT and moddn(ev) then ev.symbol = SDLK_PAGEDOWN ev.mod = 0 end if ev.symbol == SDLK_LEFT and modup(ev) then ev.symbol = SDLK_HOME ev.mod = 0 end if ev.symbol == SDLK_LEFT and moddn(ev) then ev.symbol = SDLK_END ev.mod = 0 end end function dorotate(ev) return mapon end function tryrotate(dirmap, ev) if not dirmap then return end for x=0,7 do if checkkey(ev, dirmap[x]) then local od = type(dirmap[x]) ~= "number" if mode == modeTiles or mode == modeASCII or mode == modeMini or mode == modeMed or not mapon then setfacedir(x) assignkey(ev, dirkeys[x]) return 1 elseif mode == modeISO then assignkey(ev, dirkeys[(1+x)%8]) return 1 elseif x == 4 and dirmap.ktype == 4 then changeface(1, ev.type, od) return 2 elseif x == 0 and dirmap.ktype == 4 then changeface(-1, ev.type, od) return 2 elseif x == 1 then changeface(-1, ev.type, od) return 2 elseif x == 3 then changeface( 1, ev.type, od) return 2 elseif x == 5 then changeface( 2, ev.type, od) return 2 elseif x == 7 then changeface(-2, ev.type, od) return 2 else local idx = math.floor((facedir+6+x)%8) assignkey(ev, dirkeys[idx]) return 1 end end end return nil end function sendrotated(ev) modupdown(ev) if dorotate(ev) then local v = tryrotate(currentKeymap.map,ev) or tryrotate(numpad,ev) or tryrotate(arrowkeys,ev) if not v and currentKeymap.extra then v = currentKeymap.extra(ev) end if v == 2 then return end end nsendkey(ev) end function namediag() if diagleft and diagright then return "both shift/ctrl" elseif diagleft then return "left shift/ctrl" elseif diagright then return "right shift/ctrl" else return "off" end end function boolonoff(x) return x and "on" or "off" end function switchKL(ev) if checkkey(ev, "k") then assignkey(ev, "m") end if checkkey(ev, "l") then assignkey(ev, "i") end return 0 end function switchLeft(ev) if checkkey(ev, "y") then assignkey(ev, "q") end if checkkey(ev, "u") then assignkey(ev, "e") end if checkkey(ev, "b") then assignkey(ev, "z") end if checkkey(ev, "n") then assignkey(ev, "c") end if checkkey(ev, "h") then assignkey(ev, "a") end if checkkey(ev, "j") then assignkey(ev, "x") end if checkkey(ev, "k") then assignkey(ev, "w") end if checkkey(ev, "l") then assignkey(ev, "d") end return 0 end function switchWASD(ev) if checkkey(ev, "h") then assignkey(ev, "a") end if checkkey(ev, "j") then assignkey(ev, "s") end if checkkey(ev, "k") then assignkey(ev, "w") end if checkkey(ev, "l") then assignkey(ev, "d") end return 0 end mapNone = {name = "none"} mapVI = {name = "YUHJKLBN (VI keys)", map = vikeytab} mapPseudoVI = {name = "YUIHJBNM + remap KL", map = pseudovikeytab, extra = switchKL} mapWASD = {name = "WASD", map = wasdkeytab} mapWASDplus = {name = "WASD + remaps", map = wasdkeytab, extra = switchWASD} mapQWEADZXC = {name = "QWEADZXC", map = leftkeytab} mapQWEADZXCplus = {name = "QWEADZXC + remaps", map = leftkeytabm, extra = switchLeft} gotKeymaps = {mapNone, mapVI, mapPseudoVI, mapWASD, mapQWEADZXC, mapQWEADZXCplus} currentKeymap = initialKeymap or mapNone lastKeymap = nil havemusic = true havebrogue = true useuserremaps = gotuserremaps and not remapsoff function curdate() return os.date("%Y-%m-%d-%H-%M-%S") end function applymod(val, mod) if bAND(mod, KMOD_LSHIFT + KMOD_RSHIFT) > 0 then return val / 2 elseif bAND(mod, KMOD_LCTRL + KMOD_RCTRL) > 0 then local ret = askstr(""..val, "Enter a new value:") if ret and tonumber(ret) then return tonumber(ret) else return val end else return val * 2 end end function modkey(sym) return sym == SDLK_LSHIFT or sym == SDLK_LCTRL or sym == SDLK_RSHIFT or sym == SDLK_RCTRL or sym == SDLK_LALT or sym == SDLK_RALT end cphase = 0 function addcursor(C) local Cur=tilerecolor(fget(Font, "_"), 0xF000000 + 0x10101 * (128 + math.floor(math.sin(cphase/3) * 100))) return tilemergeover(C, Cur) -- return tilemerge(tilerecolor(fget(Font, "_"), 0xF000000 + 0x10101 * (128 + math.floor(math.sin(cphase/3) * 100))), C) end function mainloop() while mainloopcyc() > 0 and not stoploop do end end menuF4 = true menuBracket = true menuCtrlM = true function ismenukey(ev) if menuF4 and ev.type == evKeyDown and ev.symbol == SDLK_F4 then return true elseif menuBracket and ev.type == evKeyDown and ev.chr == 29 then elseif menuCtrlM and ev.type == evKeyDown and ev.symbol ~= 13 and ev.symbol ~= SDLK_KP_ENTER and ev.chr == 13 then return true end return false end function isfullscreenkey(ev) return ev.type == evKeyDown and ev.symbol == SDLK_RETURN and modon(ev, KMOD_LALT + KMOD_RALT) end function sendquit() -- for libtcod as libnoteye user (not officially released) if vialibtcod then quitlibtcod() end end function mainloopcyc() inmenu = nil local ev = getevent() if ismenukey(ev) then ev.type = evKeyUp ev.symbol = SDLK_LCTRL nsendkey(ev) noteyemenu() drawandrefresh() elseif ev.type == evKeyDown and ev.symbol == SDLK_F2 and quickshots then local fname = shotdir..curdate()..".bmp" saveimage(1, fname) elseif isfullscreenkey(ev) then fscr = not fscr setvideomodex() drawandrefresh() elseif ev.type == evKeyDown or ev.type == evKeyUp then userremap(ev) sendrotated(ev) elseif ev.type == evMouseDown or ev.type == evMouseUp or ev.type == evMouseMotion then mousepos = ev sendmouse(ev) elseif ev.type == evBell then if not SndBell then SndBell = loadsound(sounddir.."rune.ogg") end playsound(SndBell, volsound) elseif ev.type == evQuit then if VIEW then delete(VIEW) VIEW = nil end if SERVER then delete(SERVER) SERVER = nil end sendquit() elseif ev.type == evProcQuit then EXIT = ev.exitcode stoploop = true return 0 elseif ev.type == evProcScreen then broadcast(sendscreen) broadcast(nflush) setcursor(proccur(P)) copymap() drawandrefresh() elseif VIEW and viewpause <= 0 then if neof(VIEW) then delete(VIEW) VIEW = nil localmessage("recording finished") else readdata(VIEW, true, true) end elseif checkstreams() then elseif ev.type == 0 then copymap() drawandrefresh() checkmusic() if REC then recpause = recpause + recspeed end if VIEW then viewpause = viewpause - viewspeed end noteyesleep() end return 1 end if not justrefreshing then function noteyesleep() sleep(1) end end function dftconfig() if haveascii then conssize = scrgetsize(openconsole()) else conssize = {x=80, y=25} end tilesize = {x=32, y=32} mapregion = {x0=0, y0=0, x1=80, y1=19} minipos = {x=1, y=1} end dftconfig() function setvideomodex() if havegfx then xscrsize = {x = scrsize.x, y = scrsize.y + msgreserve * fontsize.y} if fscr then xscrsize = findvideomode(xscrsize.x, xscrsize.y) end local res = setvideomode(xscrsize.x, xscrsize.y, fscr) if res == false then -- probably the font was too big if fallback then error("Error: unable to set any graphics mode") end fallback = true selectfontfull(loadfont("cp437-8", 32, 8)) fallback = false end scroffset = {x=(xscrsize.x-scrsize.x)/2, y = (xscrsize.y-scrsize.y)/2} -- print("resolution used: "..xscrsize.x.."x"..xscrsize.y) prepareextra() fppvar = { vx0 = 0, vy0 = 0, vx1 = xscrsize.x, vy1 = xscrsize.y, vxm = xscrsize.x/2, vym = xscrsize.y/2, vxs = xscrsize.y/2, vys = xscrsize.y/2, vimg = 1 } elseif hadgfx then closevideomode() end if haveascii then mainscreen = openconsole() elseif hadascii then delete(mainscreen) mainscreen = NIL end hadgfx = havegfx hadascii = haveascii end function updscr() updaterect(0, 0, xscrsize.x, xscrsize.y) end function drawandrefresh() profstart("drawandrefresh") if havegfx then drawdisplay() updaterect(0, 0, xscrsize.x, xscrsize.y) end if haveascii then scrcopy(IMG, 0, 0, mainscreen, 0, 0, conssize.x, conssize.y, eq) drawmessage() refreshconsole(pcursor.y, pcursor.x) end profend("drawandrefresh") end if noteyelogo == nil then noteyelogo = loadimage(gfxdir.."noteye-logo-dark.png") noteyetile = addtile(noteyelogo, 0, 0, 400, 300, -1) end OutOfMap = 0 function prepareconsole() scrsize = {x=fontsize.x*conssize.x, y=fontsize.y*conssize.y} S = renewscreen(S, conssize.x, conssize.y) IMG = renewscreen(IMG, conssize.x, conssize.y) IMGX = renewscreen(IMGX, conssize.x, conssize.y) -- auxiliary for shading mapsize = { x = mapregion.x1-mapregion.x0, y = mapregion.y1-mapregion.y0 } MAP = renewscreen(MAP, mapsize.x, mapsize.y) Tiles = renewscreen(Tiles, mapsize.x, mapsize.y) scrset(Tiles, 999, 999, OutOfMap) Minimap = renewscreen(Minimap, mapsize.x+2, mapsize.y+2) scrfill(Minimap, 0, 0, mapsize.x+2, mapsize.y+2, tilefill(0)) playerpos = {x=1, y=1} mapon = false setvideomodex() end function settilectr() tilectr = {x=scrsize.x/2, y=scrsize.y/2} end function settileextent() tileext = { left=math.ceil(tilectr.x/tilesize.x), up=math.ceil(tilectr.y/tilesize.y), right=math.ceil((scrsize.x-tilectr.x)/tilesize.x), down =math.ceil((scrsize.y-tilectr.y)/tilesize.y) } end function prepareextra() settilectr() settileextent() tileext.x = tileext.left+tileext.right+1 tileext.y = tileext.up+tileext.down+1 TileCut = renewscreen(TileCut, tileext.x, tileext.y) end function drawAsciiTransparent() scrcopy(IMG, 0,0, IMGX, 0,0, conssize.x, conssize.y, cellblack) drawscreen(1, IMGX,-1, 0, fontsize.x, fontsize.y) drawscreen(1, IMGX, 0,-1, fontsize.x, fontsize.y) drawscreen(1, IMGX, 1, 0, fontsize.x, fontsize.y) drawscreen(1, IMGX, 0, 1, fontsize.x, fontsize.y) scrcopy(IMG, 0,0, IMGX, 0,0, conssize.x, conssize.y, celltransorshade) drawscreen(1, IMGX, 0, 0, fontsize.x, fontsize.y) end function drawAsciiSemitransparent() drawscreenx(1, IMG, 0, 0, fontsize.x, fontsize.y, cellshade) drawscreenx(1, IMG, 0, 0, fontsize.x, fontsize.y, cellshade) drawAsciiTransparent() end function drawmessage() while table.getn(messages)>0 and (messages[1].at < os.clock() or table.getn(messages) > 5) do table.remove(messages, 1) end local yy = table.getn(messages) if yy>0 then if havegfx then drawtile(1, tilefill(vgaget(1)), 0, xscrsize.y-fontsize.y*yy, xscrsize.x, fontsize.y*yy) Msgline = renewscreen(Msgline, 80, 1) for y=1,yy do scrfill(Msgline, 0, 0, 80, 1, 0) scrwrite(Msgline, 0, 0, messages[y].text, Font, vgaget(14)) drawscreen(1, Msgline, 0, xscrsize.y-fontsize.y*(yy-y+1), fontsize.x, fontsize.y) end end if haveascii then for y=1,yy do scrwrite(mainscreen, 0, 24+y-yy, messages[y].text, Font, vgaget(14)) end end end if conshelp and mousepos then local xm = mousepos.x local ym = mousepos.y local xc = math.floor(mousepos.x / fontsize.x) local yc = math.floor(mousepos.y / fontsize.y) local sg = scrget(S, xc, yc) Msgline = renewscreen(Msgline, 80, 1) thelp = "at "..xc..","..yc.." ("..xm..","..ym..") char = "..gch(sg).."/"..av(gch(sg)).." color = "..ashex(gco(sg)).." back = "..ashex(gba(sg)) scrfill(Msgline, 0, 0, 80, 1, 0) scrwrite(Msgline, 0, 0, thelp, Font, vgaget(11)) drawscreen(1, Msgline, 0, xscrsize.y-fontsize.y*(yy+1), fontsize.x, fontsize.y) end end minimapborder = 0x808080 function drawMiniMap() local msx = 3*(mapsize.x+2) local msy = 3*(mapsize.y+2) scrfill(Minimap, 0, 0, msx, msy, tilefill(minimapborder)) scrcopy(MAP, 0,0, Minimap, 1,1, mapsize.x, mapsize.y, xminimap) if mode ~= modeMed then cminipos = { x = minipos.x*(scrsize.x-msx), y = minipos.y*(scrsize.y-msy) } else cminipos = {x=0, y=0} if playerpos.y > (mapregion.y0 + mapregion.y1) / 2 then cminipos.y = mapregion.y0 * fontsize.y else cminipos.y = mapregion.y1 * fontsize.y - msy end if playerpos.x > (mapregion.x0 + mapregion.x1) / 2 then cminipos.x = mapregion.x0 * fontsize.x else cminipos.x = mapregion.x1 * fontsize.x - msx end end cminipos.x2 = cminipos.x + msx cminipos.y2 = cminipos.y + msy drawscreen(1, Minimap, cminipos.x, cminipos.y, 3, 3) end function drawMiniAndStats() if mapon then drawMiniMap() drawAsciiTransparent() else drawAsciiSemitransparent() end end function drawBackground() -- if the game has a special background, then draw it -- and return true return false end function drawdisplayMini() if mapon then scrcopy(MAP, 0, 0, IMG, mapregion.x0, mapregion.y0, mapsize.x, mapsize.y, xtile) end if drawBackground() then drawAsciiSemitransparent() else drawdisplayASCII_layers() end end function drawdisplayASCII() drawscreen(1, IMG, 0, 0, fontsize.x, fontsize.y) end function drawdisplayASCII_layers() for k,v in pairs(tilelayers) do drawscreenx(1, IMG, 0, 0, fontsize.x, fontsize.y, getlayerX(v)) end end tilelayers = {0} function drawdisplayTile() if needfill then fillimage(Gfx, 0, 0, xscrsize.x, xscrsize.y, 0) end scrset(MAP, 999, 999, 0) scrcopy(MAP, playerpos.x-tileext.left, playerpos.y-tileext.up, TileCut, 0, 0, tileext.x, tileext.y, xtile) for k,v in pairs(tilelayers) do drawscreenx(1, TileCut, tilectr.x - (tileext.left + 0.5) * tilesize.x, tilectr.y - (tileext.up + 0.5) * tilesize.y, tilesize.x, tilesize.y, getlayerX(v)) end drawMiniAndStats() end function drawdisplayMed() drawdisplayASCII() if not mapon then return end -- if needfill then fillimage(Gfx, 0, 0, xscrsize.x, xscrsize.y, 0) end local medsize = math.floor((mapsize.x+1)/2) local tx = playerpos.x - math.floor(medsize/2) if tx < 0 then tx = 0 elseif tx + medsize > mapsize.x then tx = mapsize.x - medsize end MedTiles = renewscreen(MedTiles, medsize, mapsize.y) scrcopy(MAP, tx, 0, MedTiles, 0, 0, medsize, mapsize.y, xtile) for k,v in pairs(tilelayers) do drawscreenx(1, MedTiles, mapregion.x0 * fontsize.x, mapregion.y0 * fontsize.y, fontsize.x*2, fontsize.y, getlayerX(v)) end playerat = { x = (((mapregion.x0+playerpos.x+0.5) - (mapregion.x0+tx)) * 2 + mapregion.x0) * fontsize.x, y = (playerpos.y+0.5) * fontsize.y } drawMiniMap() end function drawdisplayFPP() fillimage(Gfx, 0, 0, xscrsize.x, xscrsize.y, 0) scrcopy(MAP, 0,0, Tiles, 0,0, mapsize.x, mapsize.y, xtile) fpp(fppvar, playerpos.x, playerpos.y, facedir * 45, Tiles) drawMiniAndStats() end function drawdisplayIso() fillimage(Gfx, 0, 0, xscrsize.x, xscrsize.y, 0) scrcopy(MAP, 0,0, Tiles, 0,0, mapsize.x, mapsize.y, xtile) scrset(Tiles, 999, 999, OutOfMap) local isi = isosizes(IsoParam) local rminx = (0 - tilectr.x) / 2 / isi.floor local rminy = (0 - tilectr.y) / isi.floor local rmaxx = (scrsize.x - tilectr.x) / 2 / isi.floor local rmaxy = (scrsize.y - tilectr.y) / isi.floor local dminx = math.floor(rminx + rminy) local dminy = math.floor(rminy - rmaxx) local dmaxx = math.ceil(rmaxx + rmaxy) local dmaxy = math.ceil(rmaxy - rminx) for dx=dminx,dmaxx do for dy=dminy,dmaxy do local drx = tilectr.x-isi.x/2+isi.floor*(dx-dy) local dry = tilectr.y-isi.y/2+isi.floor*(dx+dy)/2 if drx > -isi.x and dry > -isi.y and drx < scrsize.x and dry < scrsize.y then local sg = scrget(Tiles, playerpos.x+dx, playerpos.y+dy) local ip = isoproject(sg, IsoParam) drawtile(1, ip, drx, dry, isi.x, isi.y) end end end drawMiniAndStats() end function drawdisplay() if fps_start then frametime = os.clock() - fps_start frames = frames + 1 end if mode == modeASCII then drawdisplayASCII() elseif mode == modeMini then drawdisplayMini() elseif mode == modeMed then drawdisplayMed() elseif mode == modeTiles then drawdisplayTile() elseif mode == modeFPP then drawdisplayFPP() else drawdisplayIso() end drawmessage() end function sendmouse(ev) local d if ev.type == evMouseMotion then lastmm = ev return end if ev.type == evMouseUp then return end d = pixeltodir(ev) if d ~= -1 then ev.type = evKeyDown ev.mod = 0 assignkey(ev, dirkeys[d]) sendrotated(ev) else ev.type = evKeyDown ev.symbol = av(".") ev.chr = av(".") ev.mod = 0 nsendkey(ev) end end function xminimap(C) b = 0 local ch = gch(C) local av = av(ch) if ch == " " then b = 0 elseif ispc(C) then b = 0xFFFFFF elseif ch == "." then b = 0x8404040 elseif av == 250 then b = 0x8404040 elseif av == 249 then b = 0x8404040 elseif ch == "#" then b = 0xC0C0C0 elseif av == 176 then b = 0xC0C0C0 elseif av == 177 then b = 0xC0C0C0 elseif av == 178 then b = 0xC0C0C0 elseif (ch >= "A" and ch <= "Z") or (ch >= "a" and ch <= "z") or (ch == "@") then b = 0x2F08000 elseif ch == (">") or ch == ("<") then b = 0xFF00FF else b = 0x0000FF end return tilefill(b) end function ispc(C) return gch(C) == "@" end function inmapregion(point) return point.x > mapregion.x0 and point.x < mapregion.x1 and point.y > mapregion.y0 and point.y < mapregion.y1 end function pcat(where) return where and inmapregion(where) and ispc(scrget(S, where.x, where.y)) end function findpc() -- maybe player is under the cursor if pcat(pcursor) then ncursor = pcursor -- if not, look for him... else for x=mapregion.x0,mapregion.x1-1 do for y=mapregion.y0,mapregion.y1-1 do if ispc(scrget(S, x,y)) then ncursor = {x=x, y=y} end end end end mapon = pcat(ncursor) end function copymap() local ncs = scrgetsize(S) if ncs.x ~= conssize.x or ncs.y ~= conssize.y then conssize = ncs prepareconsole() end -- copy from the process map scrcopy(S, 0, 0, IMG, 0,0, conssize.x, conssize.y, eq) cphase = cphase + 1 cursor = pcursor scrset(IMG, cursor.x, cursor.y, addcursor(scrget(IMG, cursor.x, cursor.y))) findpc() if mapon then -- yeah, there he is! playerpos = {x=ncursor.x-mapregion.x0, y=ncursor.y-mapregion.y0} scrset(IMG, 999, 999, 0) -- 0 outside the map scrcopy(S, mapregion.x0, mapregion.y0, MAP, 0,0, mapsize.x, mapsize.y, eq) if mode ~= modeASCII then scrfill(IMG, mapregion.x0, mapregion.y0, mapsize.x, mapsize.y, 0) end readgmessages() else mapon = false end end function caller(name, dir, uname, wname) if manualcall and linux then return "sh -l" elseif manualcall then return "cmd" elseif linux then return "sh "..noteyedir.."caller.sh "..dir.." "..uname.." \""..name.."\"" else return ".\\caller.bat "..dir.." "..wname.." \""..name.."\"" end end function caller3(name, x) return caller(name, x, x, x) end function rungamex(cmdline) P = newprocess(S, Font, cmdline) end function rungame2(cmdline) prepareconsole() stoploop = false pcursor = {x=0, y=0} if autorec then startrecording() end if autoserve then startserver() end if viewmode then noteyemenu() else rungamex(cmdline) end mainloop() if REC then delete(REC); REC = nil end if VIEW then delete(VIEW); VIEW = nil end if ACCEPT then stopserver() end if SERVER then delete(SERVER); SERVER = nil end if havemain then createmain() end if P then delete(P); P = nil end end function rungame(cmdline) if justrefreshing then return end if threaded and not viewmode then local lnoteyesleep = noteyesleep function noteyesleep() uisleep() lnoteyesleep() end function rungamex(cmdline) P = internal(S, Font, cmdline) end function rg() rungame2(cmdline) end uicreate(rg) else rungame2(cmdline) end end function viewmenu() if havegfx then drawtile(1, noteyetile, 0, 0, scrsize.x, scrsize.y) scrcopy(IMG, 0,0, IMGX, 0,0, conssize.x, conssize.y, cellblacknb) drawscreen(1, IMGX,-1, 0, fontsize.x, fontsize.y) drawscreen(1, IMGX, 0,-1, fontsize.x, fontsize.y) drawscreen(1, IMGX, 1, 0, fontsize.x, fontsize.y) drawscreen(1, IMGX, 0, 1, fontsize.x, fontsize.y) drawscreen(1, IMG, 0, 0, fontsize.x, fontsize.y) drawmessage() updscr() end if haveascii then scrcopy(IMG, 0, 0, mainscreen, 0,0, conssize.x, conssize.y, eq) drawmessage() refreshconsole() end end function readline(Scr, x1, x2, y) s = "" for x = x1,x2-1 do s = s .. gch(scrget(Scr, x, y)) end return s end function gotgmessage(s) end function readgmessages() if msgbox == nil then return true end local oldgmsg = gmsg local function testeqmsg(oldofs, count, offset) for y = oldofs,count do if gmsg[y] ~= oldgmsg[y+offset] then return false end end return true end gmsg = {} msglines = msgbox.y1-msgbox.y0 for y = 1,msglines do gmsg[y] = readline(S, msgbox.x0, msgbox.x1, msgbox.y0-1+y) end if not oldgmsg then for y = 1,msglines do gotgmessage(gmsg[y]) end return end for nmsg = 0,msglines do if testeqmsg(1, msglines-nmsg, nmsg) then for y = 1,nmsg do gotgmessage(gmsg[msglines-nmsg+y]) end return end end end function ashex(v) return string.format("%02X", v) end function pixeltoproc(ev) if mode == modeASCII or mode == modeMini then ev.x = math.floor(ev.x / fontsize.x) ev.y = math.floor(ev.y / fontsize.y) elseif mode == modeMed then ev.x = playerpos.x + math.floor((ev.x - playerat.x + fontsize.x) / fontsize.x/2) ev.y = math.floor(ev.y / fontsize.y) elseif cminipos and ev.x > cminipos.x and ev.y > cminipos.y and ev.x < cminipos.x2 and ev.y < cminipos.y2 then ev.x = mapregion.x0 + mround((ev.x - cminipos.x) / 3) ev.y = mapregion.y0 + mround((ev.y - cminipos.y) / 3) elseif mode == modeTiles then ev.x = mapregion.x0 + playerpos.x + mround((ev.x - tilectr.x) / tilesize.x) ev.y = mapregion.y0 + playerpos.y + mround((ev.y - tilectr.y) / tilesize.y) elseif mode == modeFPP then return elseif mode == modeISO then local isi = isosizes(IsoParam) local rx = ev.x - tilectr.x local ry = ev.y - tilectr.y ry = ry / isi.floor rx = rx / 2 / isi.floor ev.x = mapregion.x0 + playerpos.x + mround(rx + ry) ev.y = mapregion.y0 + playerpos.y + mround(ry - rx) end end function pixeltodir(ev) if mode == modeASCII or mode == modeMini then return vectodir((ev.x - (playerpos.x+0.5) * fontsize.x) * fontsize.y, (ev.y - (playerpos.y+0.5) * fontsize.y) * fontsize.x, fontsize.x*fontsize.y) elseif mode == modeMed then return vectodir((ev.x - playerat.x) * fontsize.y, (ev.y - playerat.y)*fontsize.x*2, fontsize.x*fontsize.y*2) elseif mode == modeTiles then return vectodir(ev.x - tilectr.x, ev.y - tilectr.y, tilesize.x) elseif mode == modeISO then local isi = isosizes(IsoParam) local rx = (ev.x - tilectr.x) / 2 local ry = ev.y - tilectr.y return vectodir(rx + ry, ry - rx, isi.floor) else return vectodir(ev.x - fppvar.vxm, ev.y - fppvar.vym, 32) end end IsoParam = isoparam(32, 32, 32, 32) if not Fonts then Fonts = {} end function loadfont(fname, x, y, adjuster) if not Fonts[fname] then local F = {} local P = loadimage(gfxdir..fname..".png") if P == 0 then print("font not found: "..fname..", replacing by the default font") -- replace with P = loadimage(gfxdir.."cp437-8.png") x = 16 y = 16 end local Psize = imggetsize(P) F.png = P F.font = adjuster(P,x,y,Psize.x,Psize.y) F.alias = imagealias(F.png, fname..".png") F.size = {x=Psize.x/x, y=Psize.y/y, rx=x, ry=y} Fonts[fname] = F end return fname end function scalefont(fname, scx, scy) if scx == 1 and scy == 1 then return fname end local fname2 = fname.."-"..scx.."x"..scy if not Fonts[fname2] then local Psize = imggetsize(Fonts[fname].png) local P = newimage(Psize.x*scx, Psize.y*scy) local F = Fonts[fname].size imagetitle(P, fname2) local Psize = imggetsize(P) for y=0,Psize.y-1 do for x=0,Psize.x-1 do setpixel(P, x, y, getpixel(Fonts[fname].png, x/scx, y/scy)) end end Fonts[fname2] = {} Fonts[fname2].png = P Fonts[fname2].font = newfont(P, F.rx, F.ry, 0xFF000000) Fonts[fname2].size = {x=F.x*scx, y=F.y*scy, rx=F.rx, ry=F.ry} end return fname2 end function selectfont(fname) curfont = fname Font = Fonts[fname].font fontsize = Fonts[fname].size StreamSetFont = 2 end function fontSimple(P,fx,fy,sx,sy) for x=0,sx-1 do for y=0,sy-1 do local c = getpixel(P,x,y) -- c = colorset(c, 3, colorpart(c, 0)) c = 0x1000001 * colorpart(c, 0) setpixel(P, x,y, c) end end return newfont(P, fx, fy, 0) end function fontAlpha(P,fx,fy,sx,sy) return newfont(P,fx,fy,transAlpha) end function fontBrogue(P,fx,fy,sx,sy) for x=0,sx-1 do for y=0,sy-1 do pix = getpixel(P, x,y) if bAND(pix, 0xFF) > 0x60 then pix = bAND(pix, 0xFF0000FF) else pix = 0 end setpixel(P, x, y, pix) end end return newfont(P,fx,fy,transAlpha) end function selectfontfull(fname) if fname then selectfont(fname) prepareconsole() if P then setfont(P, Font) elseif S then setfont(S, Font) end end end -- baksoundtrack backs up the soundtrack as reconfigured by user soundtrackobj = {} function resetmusic() soundtrack = {} end function addmusic(s) table.insert(soundtrack, s) end function clonetrack(src, dst) dst = {} for k,v in pairs(src) do dst[k] = v end end if baksoundtrack then clonetrack(baksoundtrack, soundtrack) else resetmusic() addmusic(sounddir.."music1.ogg") addmusic(sounddir.."music2.ogg") end mid = 0 function checkmusic() if not musicon() then if volmusic == 0 then return end if #soundtrack == 0 then return end local s = soundtrack[1 + mid % #soundtrack] mid = mid + 1 if not soundtrackobj[s] then soundtrackobj[s] = loadmusic(s) end local obj = soundtrackobj[s] if not obj then return end musicvolume(volmusic) playmusic(obj) end end function disablemusic() if not forcemusic then resetmusic() musicvolume(0) havemusic = false end end -- user configurable keymapping if not userkeyremaps then userkeyremaps = {} end function remapkey(_orig, _new, _cond) gotuserremaps = true useuserremaps = not remapsoff table.insert(userkeyremaps, {orig = _orig, new = _new, cond = _cond}) end function ingame(G) return function(ev) return gamename == G and not inmenu end end function inallgames(ev) return not inmenu end function inallmenus(ev) return inmenu end function onlymenu(M) return function(ev) return inmenu == M end end function onlymap(c) return function(ev) return mapon and c(ev) end end function userremap(ev) if not useuserremaps then return end for k,v in pairs(userkeyremaps) do if checkkey(ev, v.orig) and v.cond(ev) then assignkey(ev, v.new) return end end end dofile(commondir.."menu.noe")