diff --git a/game/engines/default/data/keybinds/actions.lua b/game/engines/default/data/keybinds/actions.lua index 5f43ef94cec30eb77d536a2dd5cfc1eced4609f4..bba236c11d5397c104a4704e8a877cb48837f501 100644 --- a/game/engines/default/data/keybinds/actions.lua +++ b/game/engines/default/data/keybinds/actions.lua @@ -94,7 +94,7 @@ defineAction{ } defineAction{ - default = { "uni:C" }, + default = { "uni:c", "uni:C" }, type = "SHOW_CHARACTER_SHEET", group = "actions", name = "Show character sheet", diff --git a/game/engines/default/engine/HotkeysDisplay.lua b/game/engines/default/engine/HotkeysDisplay.lua index 4aa713b32f76189c807fc557b57d2420d59ea76d..5e0b24794044cbe966cb8989010fad982f9ff9c9 100644 --- a/game/engines/default/engine/HotkeysDisplay.lua +++ b/game/engines/default/engine/HotkeysDisplay.lua @@ -50,10 +50,6 @@ function _M:resize(x, y, w, h) self.texture, self.texture_w, self.texture_h = self.surface:glTexture() if self.actor then self.actor.changed = true end - local cw, ch = self.font:size(" ") - self.font_w = cw - self.max_char_w = math.min(127, math.floor(w / self.font_w)) - if self.bg_image then local fill = core.display.loadImage(self.bg_image) local fw, fh = fill:getSize() @@ -73,14 +69,17 @@ function _M:display() local a = self.actor if not a or not a.changed then return self.surface end + local page = a.hotkey_page + if page == 1 and core.key.modState("ctrl") then page = 2 + elseif page == 1 and core.key.modState("shift") then page = 3 end + local hks = {} for i = 1, 12 do - local j = i + (12 * (a.hotkey_page - 1)) - local ks = game.key:formatKeyString(game.key:findBoundKeys("HOTKEY_"..page_to_hotkey[a.hotkey_page]..i)) + local j = i + (12 * (page - 1)) if a.hotkey[j] and a.hotkey[j][1] == "talent" then - hks[#hks+1] = {a.hotkey[j][2], j, "talent", ks} + hks[#hks+1] = {a.hotkey[j][2], i, "talent"} elseif a.hotkey[j] and a.hotkey[j][1] == "inventory" then - hks[#hks+1] = {a.hotkey[j][2], j, "inventory", ks} + hks[#hks+1] = {a.hotkey[j][2], i, "inventory"} end end @@ -122,14 +121,14 @@ function _M:display() end end - txt = ("%1d/%2d) %-"..(self.max_char_w-4-24).."s Key: %s"):format(a.hotkey_page, i - (a.hotkey_page-1) * 12, txt, ts[4]) + txt = ("%1d/%2d) %s"):format(page, i, txt) local w, h, gen if self.cache[txt] then gen = self.cache[txt] w, h = gen.fw, gen.fh else w, h = self.font:size(txt) - gen = self.font:draw(txt, self.w, color[1], color[2], color[3], true)[1] + gen = self.font:draw(txt, self.w / 3, color[1], color[2], color[3], true)[1] gen.fw, gen.fh = w, h end gen.x, gen.y = x, y @@ -138,7 +137,7 @@ function _M:display() self.clics[i] = {x,y,w+4,h+4} if y + self.font_h * 2 > self.h then - x = x + self.w / 2 + x = x + self.w / 3 y = 0 else y = y + self.font_h diff --git a/game/engines/default/engine/LogDisplay.lua b/game/engines/default/engine/LogDisplay.lua index 6b6e3b50bc35a074b1d6e1b8f1067b307fa08cb2..83c31877a0d62ead956502018a3d2f03d7ded2c1 100644 --- a/game/engines/default/engine/LogDisplay.lua +++ b/game/engines/default/engine/LogDisplay.lua @@ -50,6 +50,10 @@ function _M:enableShadow(v) self.shadow = v end +function _M:enableFading(v) + self.fading = v +end + --- Resize the display area function _M:resize(x, y, w, h) self.display_x, self.display_y = math.floor(x), math.floor(y) @@ -72,9 +76,22 @@ function _M:resize(x, y, w, h) self.scrollbar = Slider.new{size=self.h - 20, max=1, inverse=true} end +--- Returns the full log +function _M:getLog() + local log = {} + for i = 1, #self.log do log[#log+1] = self.log[i].str end + return log +end + +function _M:getLogLast(channel) + if not self.log[1] then return 0 end + return self.log[1].timestamp +end + --- Make a dialog popup with the full log function _M:showLogDialog(title, shadow) - local d = require("engine.dialogs.ShowLog").new(title or "Message Log", shadow, self) + local log = self:getLog() + local d = require_first("mod.dialogs.ShowLog", "engine.dialogs.ShowLog").new(title or "Message Log", shadow, {log=log}) game:registerDialog(d) end @@ -86,7 +103,7 @@ function _M:call(str, ...) str = str:format(...) print("[LOG]", str) local tstr = str:toString() - table.insert(self.log, 1, tstr) + table.insert(self.log, 1, {str=tstr, timestamp = core.game.getTime()}) while #self.log > self.max_log do local old = table.remove(self.log) self.cache[old] = nil @@ -109,7 +126,7 @@ function _M:getLines(number) if from > #self.log then from = #self.log end local lines = { } for i = from, 1, -1 do - lines[#lines+1] = tostring(self.log[i]) + lines[#lines+1] = tostring(self.log[i].str) end return lines end @@ -125,7 +142,7 @@ function _M:display() local old_style = self.font:getStyle() for z = 1 + self.scroll, #self.log do local stop = false - local tstr = self.log[z] + local tstr = self.log[z].str local gen if self.cache[tstr] then gen = self.cache[tstr] @@ -134,7 +151,7 @@ function _M:display() self.cache[tstr] = gen end for i = #gen, 1, -1 do - self.dlist[#self.dlist+1] = gen[i] + self.dlist[#self.dlist+1] = {item=gen[i], date=self.log[z].timestamp} h = h + self.fh if h > self.h - self.fh then stop=true break end end @@ -146,16 +163,29 @@ end function _M:toScreen() self:display() + if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end + + local now = core.game.getTime() + local h = self.display_y + self.h - self.fh for i = 1, #self.dlist do - local item = self.dlist[i] - if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, self.fw, self.fh, item._tex_w, item._tex_h, 0,0,0, self.shadow) end - item._tex:toScreenFull(self.display_x, h, self.fw, self.fh, item._tex_w, item._tex_h) + local item = self.dlist[i].item + + local fade = 1 + if self.fading then + fade = now - self.dlist[i].date + if fade < self.fading * 1000 then fade = 1 + elseif fade < self.fading * 2000 then fade = (self.fading * 2000 - fade) / (self.fading * 1000) + else fade = 0 end + end + + if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, self.fw, self.fh, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade) end + item._tex:toScreenFull(self.display_x, h, self.fw, self.fh, item._tex_w, item._tex_h, 1, 1, 1, fade) h = h - self.fh end - if true then + if not self.fading then self.scrollbar.pos = self.scroll self.scrollbar.max = self.max - self.max_display + 1 self.scrollbar:display(self.display_x + self.w - self.scrollbar.w, self.display_y) diff --git a/game/engines/default/engine/Map.lua b/game/engines/default/engine/Map.lua index 7d74de5e6fa0d475bd616f3f764aedf1eca36d5b..6c5cea8443b1a9d609bc5cf3cf21ecfef7f7393f 100644 --- a/game/engines/default/engine/Map.lua +++ b/game/engines/default/engine/Map.lua @@ -182,6 +182,7 @@ function _M:save() _map = true, _fovcache = true, surface = true, + finished = true, }) end @@ -287,6 +288,7 @@ end --- Recreate the internal map using new dimensions function _M:recreate() + if not self.finished then return end self:makeCMap() self.changed = true diff --git a/game/engines/default/engine/UserChat.lua b/game/engines/default/engine/UserChat.lua index f16d257729b97a6ad2b75e49d6ca35d6c7d44eac..e2251515dc7bb0fdd76b71d493492cc329a4789e 100644 --- a/game/engines/default/engine/UserChat.lua +++ b/game/engines/default/engine/UserChat.lua @@ -34,6 +34,7 @@ function _M:init() self.cur_channel = "global" self.channels = {} self.max = 500 + self.do_display_chans = true end --- Hook up in the current running game @@ -63,7 +64,7 @@ end function _M:addMessage(channel, login, name, msg, extra_data, no_change) local log = self.channels[channel].log - table.insert(log, 1, {login=login, name=name, msg=msg, extra_data=extra_data}) + table.insert(log, 1, {login=login, name=name, msg=msg, extra_data=extra_data, timestamp=core.game.getTime()}) while #log > self.max do table.remove(log) end self.changed = true if not no_change and channel ~= self.cur_channel then self.channels[channel].changed = true self.channels_changed = true end @@ -254,15 +255,32 @@ end -- UI Section ---------------------------------------------------------------- ---- Make a dialog popup with the full log -function _M:showLogDialog(title, shadow) +--- Returns the full log +function _M:getLog(channel) + channel = channel or self.cur_channel local log = {} - if self.channels[self.cur_channel] then - for _, i in ipairs(self.channels[self.cur_channel].log) do + if self.channels[channel] then + for _, i in ipairs(self.channels[channel].log) do log[#log+1] = ("<%s> %s"):format(i.name, i.msg) end end - local d = require("engine.dialogs.ShowLog").new(title or "Chat Log", shadow, {log=log}) + return log +end + +function _M:getLogLast(channel) + channel = channel or self.cur_channel + if self.channels[channel] then + if not self.channels[channel].log[1] then return 0 end + return self.channels[channel].log[1].timestamp + else + return 0 + end +end + +--- Make a dialog popup with the full log +function _M:showLogDialog(title, shadow) + local log = self:getLog(self.cur_channel) + local d = require_first("mod.dialogs.ShowLog", "engine.dialogs.ShowLog").new(title or "Chat Log", shadow, {log=log}) game:registerDialog(d) end @@ -342,6 +360,14 @@ function _M:enableShadow(v) self.shadow = v end +function _M:enableFading(v) + self.fading = v +end + +function _M:enableDisplayChans(v) + self.do_display_chans = v +end + function _M:onMouse(fct) self.on_mouse = fct end @@ -386,9 +412,9 @@ function _M:display() for i = #gen, 1, -1 do gen[i].login = log[z].login gen[i].extra_data = log[z].extra_data - self.dlist[#self.dlist+1] = gen[i] + self.dlist[#self.dlist+1] = {item=gen[i], date=log[z].timestamp} h = h + self.fh - if h > self.h - self.fh - self.fh then stop=true break end + if h > self.h - self.fh - (self.do_display_chans and self.fh or 0) then stop=true break end end if stop then break end end @@ -400,30 +426,42 @@ function _M:toScreen() self:display() if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end local h = self.display_y + self.h - self.fh + local now = core.game.getTime() for i = 1, #self.dlist do - local item = self.dlist[i] + local item = self.dlist[i].item + + local fade = 1 + if self.fading then + fade = now - self.dlist[i].date + if fade < self.fading * 1000 then fade = 1 + elseif fade < self.fading * 2000 then fade = (self.fading * 2000 - fade) / (self.fading * 1000) + else fade = 0 end + end + item.dh = h - if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow) end - item._tex:toScreenFull(self.display_x, h, item.w, item.h, item._tex_w, item._tex_h) + if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade) end + item._tex:toScreenFull(self.display_x, h, item.w, item.h, item._tex_w, item._tex_h, 1, 1, 1, fade) h = h - self.fh end - local w = 0 - for i = 1, #self.display_chans do - local item = self.display_chans[i] - local f = item.sel and self.frame_sel or self.frame - f.w = item.w - - Base:drawFrame(f, self.display_x + w, self.display_y) - if self.channels[item.name].changed then - local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 120 - Base:drawFrame(f, self.display_x + w, self.display_y, 139/255, 210/255, 77/255, glow / 255) + if self.do_display_chans then + local w = 0 + for i = 1, #self.display_chans do + local item = self.display_chans[i] + local f = item.sel and self.frame_sel or self.frame + f.w = item.w + + Base:drawFrame(f, self.display_x + w, self.display_y) + if self.channels[item.name].changed then + local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 120 + Base:drawFrame(f, self.display_x + w, self.display_y, 139/255, 210/255, 77/255, glow / 255) + end + item._tex:toScreenFull(self.display_x + w, self.display_y, item.w, item.h, item._tex_w, item._tex_h) + w = w + item.w + 4 end - item._tex:toScreenFull(self.display_x + w, self.display_y, item.w, item.h, item._tex_w, item._tex_h) - w = w + item.w + 4 end - if true then + if not self.fading then self.scrollbar.pos = self.scroll self.scrollbar.max = self.max - self.max_display + 1 self.scrollbar:display(self.display_x + self.w - self.scrollbar.w, self.display_y) diff --git a/game/engines/default/engine/interface/GameTargeting.lua b/game/engines/default/engine/interface/GameTargeting.lua index b9661a75ae65853bd0736817d74cddf17e070b86..8748664d1d43af2ca6a214d92de72d2ffe2c2b35 100644 --- a/game/engines/default/engine/interface/GameTargeting.lua +++ b/game/engines/default/engine/interface/GameTargeting.lua @@ -195,6 +195,8 @@ end --- Handle mouse event for targeting -- @return true if the event was handled function _M:targetMouse(button, mx, my, xrel, yrel, event) + if not self.level then return end + -- Move tooltip self.tooltip_x, self.tooltip_y = mx, my local tmx, tmy = self.level.map:getMouseTile(mx, my) diff --git a/game/engines/default/engine/interface/PlayerMouse.lua b/game/engines/default/engine/interface/PlayerMouse.lua index 75d906890f8b89371a828039c3a81f0124f39388..426519d9abac4a502e5f152a2a0d0165ecc936a1 100644 --- a/game/engines/default/engine/interface/PlayerMouse.lua +++ b/game/engines/default/engine/interface/PlayerMouse.lua @@ -120,6 +120,7 @@ end -- @param key the Key object to which to pass the event if not treated, this should be your game default key handler probably -- @param allow_move true if this will allow player movement (you should use it to check that you are not in targetting mode) function _M:mouseHandleDefault(key, allow_move, button, mx, my, xrel, yrel, event) + if not game.level then return end local tmx, tmy = game.level.map:getMouseTile(mx, my) -- Move diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 5e232ccf6e65e1a3ee1c113ffc185f67492cd1a7..f5173515355fc829c29caef1151477d9db433c77 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -81,7 +81,7 @@ function _M:init() end function _M:run() - local size, size_mono, font, font_mono + local size, size_mono, font, font_mono, font_mono_h, font_h local flysize = ({normal=14, small=12, big=16})[config.settings.tome.fonts.size] if config.settings.tome.fonts.type == "fantasy" then size = ({normal=16, small=14, big=18})[config.settings.tome.fonts.size] @@ -94,16 +94,27 @@ function _M:run() font = "/data/font/Vera.ttf" font_mono = "/data/font/VeraMono.ttf" end + local f = core.display.newFont(font, size) + font_h = f:lineSkip() + f = core.display.newFont(font_mono, size_mono) + font_mono_h = f:lineSkip() self.delayed_log_damage = {} self.calendar = Calendar.new("/data/calendar_allied.lua", "Today is the %s %s of the %s year of the Age of Ascendancy of Maj'Eyal.\nThe time is %02d:%02d.", 122, 167, 11) - self.player_display = PlayerDisplay.new(0, 230, 200, self.h * 0.8 - 230, {30,30,0}, font_mono, size_mono) - self.flash = LogFlasher.new(0, 0, self.w, 20, nil, font, size, {255,255,255}, {0,0,0}) - self.logdisplay = LogDisplay.new(0, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, nil, font, size, {255,255,255}, "/data/gfx/ui/message-log.png") + self.player_display = PlayerDisplay.new(0, 200, 200, self.h - 200, {30,30,0}, font_mono, size_mono) +-- self.flash = LogFlasher.new(0, 0, self.w, 20, nil, font, size, {255,255,255}, {0,0,0}) + self.map_h_stop = self.h - font_mono_h * 4 + self.logdisplay = LogDisplay.new(216, self.map_h_stop - font_h * 5 -16, (self.w - 216) / 2, font_h * 5, nil, font, size, nil, nil) self.logdisplay:enableShadow(0.6) - profile.chat:resize(0, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, font, size, {255,255,255}, "/data/gfx/ui/message-log.png") - self.hotkeys_display = HotkeysDisplay.new(nil, self.w * 0.5 + 46, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, "/data/gfx/ui/talents-list.png", font_mono, size_mono) + self.logdisplay:enableFading(2) + + profile.chat:resize(216 + (self.w - 216) / 2, self.map_h_stop - font_h * 5 -16, (self.w - 216) / 2, font_h * 5, font, size, nil, nil) + profile.chat:enableShadow(0.6) + profile.chat:enableFading(6) + profile.chat:enableDisplayChans(false) + + self.hotkeys_display = HotkeysDisplay.new(nil, 216, self.h - font_mono_h * 4, self.w - 216, font_mono_h * 4, "/data/gfx/ui/talents-list.png", font_mono, size_mono) self.hotkeys_display:enableShadow(0.6) self.npcs_display = ActorsSeenDisplay.new(nil, self.w * 0.5 + 46, self.h * 0.8 + 7, self.w * 0.5 - 46, self.h * 0.2 - 7, "/data/gfx/ui/talents-list.png", font_mono, size_mono) self.tooltip = Tooltip.new(font_mono, size, {255,255,255}, {30,30,30,230}) @@ -116,34 +127,22 @@ function _M:run() self.nicer_tiles = NicerTiles.new() self:createSeparators() - self.log = function(style, ...) if type(style) == "number" then self.logdisplay(...) self.flash(style, ...) else self.logdisplay(style, ...) self.flash(self.flash.NEUTRAL, style, ...) end end + self.log = function(style, ...) if type(style) == "number" then self.logdisplay(...) else self.logdisplay(style, ...) end end self.logChat = function(style, ...) - if not config.settings.tome.chat_log then return end + if true or not config.settings.tome.chat_log then return end if type(style) == "number" then local old = self.logdisplay.changed - self.logdisplay(...) self.flash(style, ...) else self.logdisplay(style, ...) self.flash(self.flash.NEUTRAL, style, ...) end + self.logdisplay(...) else self.logdisplay(style, ...) end if self.show_userchat then self.logdisplay.changed = old end end self.logSeen = function(e, style, ...) if e and e.x and e.y and self.level.map.seens(e.x, e.y) then self.log(style, ...) end end self.logPlayer = function(e, style, ...) if e == self.player or e == self.party then self.log(style, ...) end end - self.log(self.flash.GOOD, "Welcome to #00FF00#Tales of Maj'Eyal!") +-- self.log(self.flash.GOOD, "Welcome to #00FF00#Tales of Maj'Eyal!") -- List of stuff to do on tick end self.on_tick_end = {} - -- Setup inputs - self:setupCommands() - self:setupMouse() - - -- Starting from here we create a new game - if not self.player then self:newGame() end - - self.hotkeys_display.actor = self.player - self.npcs_display.actor = self.player - - self:initTargeting() - -- Ok everything is good to go, activate the game in the engine! self:setCurrent() @@ -153,9 +152,21 @@ function _M:run() -- Start time self.real_starttime = os.time() - if self.level then self:setupDisplayMode(false, "postinit") end + self:setupDisplayMode(false, "postinit") if self.level and self.level.data.day_night then self.state:dayNightCycle() end if self.level and self.player then self.calendar = Calendar.new("/data/calendar_"..(self.player.calendar or "allied")..".lua", "Today is the %s %s of the %s year of the Age of Ascendancy of Maj'Eyal.\nThe time is %02d:%02d.", 122, 167, 11) end + + -- Setup inputs + self:setupCommands() + self:setupMouse() + + -- Starting from here we create a new game + if not self.player then self:newGame() end + + self:initTargeting() + + self.hotkeys_display.actor = self.player + self.npcs_display.actor = self.player end --- Checks if the current character is "tainted" by cheating @@ -315,6 +326,7 @@ function _M:loaded() Zone.post_filter = function(...) return self.state:entityFilterPost(...) end Map:setViewerActor(self.player) self:setupDisplayMode(false, "init") + self:setupDisplayMode(false, "postinit") if self.player then self.player.changed = true end self.key = engine.KeyBind.new() @@ -334,6 +346,14 @@ function _M:setupDisplayMode(reboot, mode) util.showMainMenu(false, nil, nil, self.__mod_info.short_name, self.save_name, false) end + local do_bg = true + + Map:resetTiles() + end + + if not mode or mode == "postinit" then + local gfx = config.settings.tome.gfx + -- Show a count for stacked objects Map.object_stack_count = true @@ -345,20 +365,14 @@ function _M:setupDisplayMode(reboot, mode) print("[DISPLAY MODE] Tileset: "..gfx.tiles) print("[DISPLAY MODE] Size: "..gfx.size) - local do_bg = true - if gfx.size == "64x64" then - Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 64, 64, nil, 44, do_bg) - Map:resetTiles() + Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 64, 64, nil, 44, do_bg) elseif gfx.size == "48x48" then - Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 48, 48, nil, 36, do_bg) - Map:resetTiles() + Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 48, 48, nil, 36, do_bg) elseif gfx.size == "32x32" then - Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 32, 32, nil, 22, do_bg) - Map:resetTiles() + Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 32, 32, nil, 22, do_bg) elseif gfx.size == "16x16" then - Map:setViewPort(216, 36, self.w - 216, math.floor(self.h * 0.80) - 36, 16, 16, "/data/font/FSEX300.ttf", 16, do_bg) - Map:resetTiles() + Map:setViewPort(216, 0, self.w - 216, (self.map_h_stop or 80) - 16, 16, 16, "/data/font/FSEX300.ttf", 16, do_bg) end Map.tiles.use_images = true @@ -367,19 +381,19 @@ function _M:setupDisplayMode(reboot, mode) if gfx.tiles == "shockbolt" then Map.tiles.nicer_tiles = true end if gfx.tiles == "oldrpg" then Map.tiles.nicer_tiles = true end - -- Create the framebuffer - self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height) - if self.fbo then self.fbo_shader = Shader.new("main_fbo") if not self.fbo_shader.shad then self.fbo = nil self.fbo_shader = nil end end - if self.player then self.player:updateMainShader() end - end - - if not mode or mode == "postinit" then if self.level then - self.level.map:recreate() + if self.level.map.finished then + self.level.map:recreate() + self.level.map:moveViewSurround(self.player.x, self.player.y, 8, 8) + end self:initTargeting() - self.level.map:moveViewSurround(self.player.x, self.player.y, 8, 8) end self:setupMiniMap() + + -- Create the framebuffer + self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height) + if self.fbo then self.fbo_shader = Shader.new("main_fbo") if not self.fbo_shader.shad then self.fbo = nil self.fbo_shader = nil end end + if self.player then self.player:updateMainShader() end end end @@ -389,7 +403,7 @@ end function _M:setupMiniMap() - if self.level and self.level.map then self.level.map._map:setupMiniMapGridSize(4) end + if self.level and self.level.map and self.level.map.finished then self.level.map._map:setupMiniMapGridSize(4) end end function _M:save() @@ -736,13 +750,13 @@ end function _M:displayDelayedLogDamage() for src, tgts in pairs(self.delayed_log_damage) do for target, dams in pairs(tgts) do - local flash = game.flash.NEUTRAL - if target == game.player then flash = game.flash.BAD end - if src == game.player then flash = game.flash.GOOD end +-- local flash = game.flash.NEUTRAL +-- if target == game.player then flash = game.flash.BAD end +-- if src == game.player then flash = game.flash.GOOD end if #dams.descs > 1 then - game.logSeen(target, flash, "%s hits %s for %s damage (total %0.2f).", src.name:capitalize(), target.name, table.concat(dams.descs, ", "), dams.total) + game.logSeen(target, "%s hits %s for %s damage (total %0.2f).", src.name:capitalize(), target.name, table.concat(dams.descs, ", "), dams.total) else - game.logSeen(target, flash, "%s hits %s for %s damage.", src.name:capitalize(), target.name, table.concat(dams.descs, ", ")) + game.logSeen(target, "%s hits %s for %s damage.", src.name:capitalize(), target.name, table.concat(dams.descs, ", ")) end local rsrc = src.resolveSource and src:resolveSource() or src @@ -852,9 +866,9 @@ function _M:display(nb_keyframes) map:displayEmotes(nb_keyframe or 1) -- Minimap display - self.minimap_bg:toScreen(0, 35, 200, 200) + self.minimap_bg:toScreen(0, 0, 200, 200) self.minimap_scroll_x, self.minimap_scroll_y = util.bound(self.player.x - 25, 0, map.w - 50), util.bound(self.player.y - 25, 0, map.h - 50) - map:minimapDisplay(0, 35, self.minimap_scroll_x, self.minimap_scroll_y, 50, 50, 1) + map:minimapDisplay(0, 0, self.minimap_scroll_x, self.minimap_scroll_y, 50, 50, 1) -- Mouse gestures self.gestures:update() @@ -862,10 +876,12 @@ function _M:display(nb_keyframes) end -- We display the player's interface - self.flash:toScreen(nb_keyframe) - if self.show_userchat then profile.chat:toScreen() - else self.logdisplay:toScreen() - end +-- self.flash:toScreen(nb_keyframe) +-- if self.show_userchat then profile.chat:toScreen() +-- else self.logdisplay:toScreen() +-- end + profile.chat:toScreen() + self.logdisplay:toScreen() self.player_display:toScreen(nb_keyframes) if self.show_npc_list then @@ -901,7 +917,7 @@ function _M:onUnregisterDialog(d) -- Clean up tooltip self.tooltip_x, self.tooltip_y = nil, nil self.tooltip2_x, self.tooltip2_y = nil, nil - if self.player then self.player:updateMainShader() end + if self.player then self.player:updateMainShader() self.player.changed = true end end function _M:setupCommands() @@ -955,7 +971,12 @@ function _M:setupCommands() self.key.any_key = function(sym) -- Control resets the tooltip - if sym == self.key._LCTRL or sym == self.key._RCTRL then self.tooltip.old_tmx = nil end + if sym == self.key._LCTRL or sym == self.key._RCTRL then + self.player.changed = true + self.tooltip.old_tmx = nil + elseif sym == self.key._LSHIFT or sym == self.key._RSHIFT then + self.player.changed = true + end end self.key:addBinds { @@ -1129,11 +1150,7 @@ function _M:setupCommands() end, SHOW_MESSAGE_LOG = function() - if not self.show_userchat then - self.logdisplay:showLogDialog(nil, 0.6) - else - profile.chat:showLogDialog(nil, 0.6) - end + self:registerDialog(require("mod.dialogs.ShowChatLog").new("Message Log", 0.6, self.logdisplay, profile.chat)) end, -- Show time @@ -1193,8 +1210,8 @@ function _M:setupCommands() end, LOOK_AROUND = function() - self.flash:empty(true) - self.flash(self.flash.GOOD, "Looking around... (direction keys to select interesting things, shift+direction keys to move freely)") +-- self.flash:empty(true) + self.log("Looking around... (direction keys to select interesting things, shift+direction keys to move freely)") local co = coroutine.create(function() self.player:getTarget{type="hit", no_restrict=true, range=2000} end) local ok, err = coroutine.resume(co) if not ok and err then print(debug.traceback(co)) error(err) end @@ -1244,6 +1261,7 @@ function _M:setupMouse(reset) self.player:mouseHandleDefault(self.key, self.key == self.normal_key, button, mx, my, xrel, yrel, event) end) -- Scroll message log +--[[ self.mouse:registerZone(self.logdisplay.display_x, self.logdisplay.display_y, self.w, self.h, function(button, mx, my, xrel, yrel, bx, by, event) if self.show_userchat then profile.chat.mouse:delegate(button, mx, my, xrel, yrel, bx, by, event) @@ -1253,6 +1271,7 @@ function _M:setupMouse(reset) if button == "left" then self.logdisplay:showLogDialog(nil, 0.6) end end end) +]] -- Use hotkeys with mouse self.mouse:registerZone(self.hotkeys_display.display_x, self.hotkeys_display.display_y, self.w, self.h, function(button, mx, my, xrel, yrel, bx, by, event) if event == "button" and button == "left" and self.zone and self.zone.wilderness then return end @@ -1277,11 +1296,11 @@ function _M:setupMouse(reset) if button == "left" then self:clickIcon(bx, by) end end) -- Tooltip over the player pane - self.mouse:registerZone(self.player_display.display_x, self.player_display.display_y, self.player_display.w, self.player_display.h, function(button, mx, my, xrel, yrel, bx, by, event) + self.mouse:registerZone(self.player_display.display_x, self.player_display.display_y, self.player_display.w, self.player_display.h - self.icons.h, function(button, mx, my, xrel, yrel, bx, by, event) self.player_display.mouse:delegate(button, mx, my, xrel, yrel, bx, by, event) end) -- Move using the minimap - self.mouse:registerZone(0, 35, 200, 200, function(button, mx, my, xrel, yrel, bx, by, event) + self.mouse:registerZone(0, 0, 200, 200, function(button, mx, my, xrel, yrel, bx, by, event) if button == "left" and not xrel and not yrel and event == "button" then local tmx, tmy = math.floor(bx / 4), math.floor(by / 4) self.player:mouseMove(tmx + self.minimap_scroll_x, tmy + self.minimap_scroll_y) @@ -1505,6 +1524,7 @@ local _sep_vert = {core.display.loadImage("/data/gfx/ui/separator-vert.png")} _s local _sep_top = {core.display.loadImage("/data/gfx/ui/separator-top.png")} _sep_top.tex = {_sep_top[1]:glTexture()} local _sep_bottom = {core.display.loadImage("/data/gfx/ui/separator-bottom.png")} _sep_bottom.tex = {_sep_bottom[1]:glTexture()} local _sep_bottoml = {core.display.loadImage("/data/gfx/ui/separator-bottom_line_end.png")} _sep_bottoml.tex = {_sep_bottoml[1]:glTexture()} +local _sep_left = {core.display.loadImage("/data/gfx/ui/separator-left.png")} _sep_left.tex = {_sep_left[1]:glTexture()} local _sep_leftl = {core.display.loadImage("/data/gfx/ui/separator-left_line_end.png")} _sep_leftl.tex = {_sep_leftl[1]:glTexture()} local _sep_rightl = {core.display.loadImage("/data/gfx/ui/separator-right_line_end.png")} _sep_rightl.tex = {_sep_rightl[1]:glTexture()} @@ -1521,116 +1541,107 @@ function _M:displayUI() local middle = self.w * 0.5 local bottom = self.h * 0.8 local bottom_h = self.h * 0.2 - local icon_x = middle - (_talents_icon_w*2) / 2 - local icon_x2 = middle + (_talents_icon_w*2) / 2 - local mid_min = icon_x - (_sep_vert[2]) - local mid_max = icon_x2 + local icon_x = 0 + local icon_y = self.h - (_talents_icon_h * 1) + local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 77 -- Icons - local x, y = icon_x, bottom + _sep_horiz[3] / 2 - _talents_icon:toScreenFull(x + _talents_icon_w, y, _talents_icon_w, _talents_icon_h, _talents_icon_w, _talents_icon_h) - if not self.show_npc_list then _sel_icon:toScreenFull(x + _talents_icon_w, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end - y = y + _talents_icon_h - _actors_icon:toScreenFull(x + _talents_icon_w, y, _actors_icon_w, _actors_icon_h, _actors_icon_w, _actors_icon_h) - if self.show_npc_list then _sel_icon:toScreenFull(x + _talents_icon_w, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end - y = y + _talents_icon_h - - local glow = (1+math.sin(core.game.getTime() / 500)) / 2 * 100 + 77 - local x, y = icon_x, bottom + _sep_horiz[3] / 2 - if self.logdisplay.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end + local x, y = icon_x, icon_y + _talents_icon:toScreenFull(x, y, _talents_icon_w, _talents_icon_h, _talents_icon_w, _talents_icon_h) + if not self.show_npc_list then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end + x = x + _talents_icon_w + _actors_icon:toScreenFull(x, y, _actors_icon_w, _actors_icon_h, _actors_icon_w, _actors_icon_h) + if self.show_npc_list then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end + x = x + _talents_icon_w + +-- if self.logdisplay.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end +-- _log_icon:toScreenFull(x, y, _log_icon_w, _log_icon_h, _log_icon_w, _log_icon_h) +-- if not self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end +-- x = x + _talents_icon_w + +-- if profile.chat.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end +-- _chat_icon:toScreenFull(x, y, _chat_icon_w, _chat_icon_h, _chat_icon_w, _chat_icon_h) +-- if self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end + +-- x = 0 +-- y = y + _chat_icon_h +-- x = x + _talents_icon_w + + _inventory_icon:toScreenFull(x, y, _inventory_icon_w, _inventory_icon_h, _inventory_icon_w, _inventory_icon_h) + x = x + _talents_icon_w + _charsheet_icon:toScreenFull(x, y, _charsheet_icon_w, _charsheet_icon_h, _charsheet_icon_w, _charsheet_icon_h) + x = x + _talents_icon_w + _main_menu_icon:toScreenFull(x, y, _main_menu_icon_w, _main_menu_icon_h, _main_menu_icon_w, _main_menu_icon_h) + x = x + _talents_icon_w _log_icon:toScreenFull(x, y, _log_icon_w, _log_icon_h, _log_icon_w, _log_icon_h) - if not self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end - y = y + _log_icon_h - if profile.chat.changed then core.display.drawQuad(x, y, _sel_icon_w, _sel_icon_h, 139, 210, 77, glow) end - _chat_icon:toScreenFull(x, y, _chat_icon_w, _chat_icon_h, _chat_icon_w, _chat_icon_h) - if self.show_userchat then _sel_icon:toScreenFull(x, y, _sel_icon_w, _sel_icon_h, _sel_icon_w, _sel_icon_h) end - y = y + _chat_icon_h - - _inventory_icon:toScreenFull(x + _talents_icon_w/2, y, _inventory_icon_w, _inventory_icon_h, _inventory_icon_w, _inventory_icon_h) y = y + _inventory_icon_h - _charsheet_icon:toScreenFull(x + _talents_icon_w/2, y, _charsheet_icon_w, _charsheet_icon_h, _charsheet_icon_w, _charsheet_icon_h) y = y + _charsheet_icon_h - _main_menu_icon:toScreenFull(x + _talents_icon_w/2, y, _main_menu_icon_w, _main_menu_icon_h, _main_menu_icon_w, _main_menu_icon_h) y = y + _main_menu_icon_h -- Separators - _sep_horiz.tex[1]:toScreenFull(0, 20, self.w, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3]) - _sep_horiz.tex[1]:toScreenFull(0, bottom - _sep_horiz[3] / 2, self.w, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3]) +-- _sep_horiz.tex[1]:toScreenFull(0, 20, self.w, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3]) + _sep_horiz.tex[1]:toScreenFull(216, self.map_h_stop - _sep_horiz[3], self.w - 216, _sep_horiz[3], _sep_horiz.tex[2], _sep_horiz.tex[3]) - _sep_vert.tex[1]:toScreenFull(mid_min, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3]) - _sep_vert.tex[1]:toScreenFull(mid_max, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3]) +-- _sep_vert.tex[1]:toScreenFull(mid_min, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3]) +-- _sep_vert.tex[1]:toScreenFull(mid_max, bottom, _sep_vert[2], bottom_h, _sep_vert.tex[2], _sep_vert.tex[3]) - _sep_vert.tex[1]:toScreenFull(200, 20, _sep_vert[2], bottom - 20, _sep_vert.tex[2], _sep_vert.tex[3]) + _sep_vert.tex[1]:toScreenFull(200, 0, _sep_vert[2], self.h, _sep_vert.tex[2], _sep_vert.tex[3]) -- Ornaments - _sep_top.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3]) - _sep_top.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3]) - _sep_bottoml.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3]) - _sep_bottoml.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3]) +-- _sep_top.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3]) +-- _sep_top.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_top[2]) / 2, bottom - 14, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3]) +-- _sep_bottoml.tex[1]:toScreenFull(mid_min - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3]) +-- _sep_bottoml.tex[1]:toScreenFull(mid_max - (-_sep_vert[2] + _sep_bottoml[2]) / 2, self.h - _sep_bottoml[3], _sep_bottoml[2], _sep_bottoml[3], _sep_bottoml.tex[2], _sep_bottoml.tex[3]) - _sep_leftl.tex[1]:toScreenFull(0, 20 - _sep_leftl[3] / 2 + 7, _sep_leftl[2], _sep_leftl[3], _sep_leftl.tex[2], _sep_leftl.tex[3]) - _sep_leftl.tex[1]:toScreenFull(0, bottom - _sep_leftl[3] / 2, _sep_leftl[2], _sep_leftl[3], _sep_leftl.tex[2], _sep_leftl.tex[3]) +-- _sep_leftl.tex[1]:toScreenFull(0, 20 - _sep_leftl[3] / 2 + 7, _sep_leftl[2], _sep_leftl[3], _sep_leftl.tex[2], _sep_leftl.tex[3]) + _sep_left.tex[1]:toScreenFull(200 - 7, self.map_h_stop - 7 - _sep_left[3] / 2, _sep_left[2], _sep_left[3], _sep_left.tex[2], _sep_left.tex[3]) - _sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], 20 - _sep_rightl[3] / 2 + 7, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3]) - _sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], bottom - _sep_rightl[3] / 2, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3]) +-- _sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], 20 - _sep_rightl[3] / 2 + 7, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3]) + _sep_rightl.tex[1]:toScreenFull(self.w - _sep_rightl[2], self.map_h_stop - _sep_left[3] / 2, _sep_rightl[2], _sep_rightl[3], _sep_rightl.tex[2], _sep_rightl.tex[3]) - _sep_top.tex[1]:toScreenFull(200 - (_sep_top[2] - _sep_vert[2]) / 2, 20 - 7, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3]) - _sep_bottom.tex[1]:toScreenFull(200 - (_sep_bottom[2] - _sep_vert[2]) / 2, bottom - 25, _sep_bottom[2], _sep_bottom[3], _sep_bottom.tex[2], _sep_bottom.tex[3]) + _sep_top.tex[1]:toScreenFull(200 - (_sep_top[2] - _sep_vert[2]) / 2, - 7, _sep_top[2], _sep_top[3], _sep_top.tex[2], _sep_top.tex[3]) +-- _sep_bottom.tex[1]:toScreenFull(200 - (_sep_bottom[2] - _sep_vert[2]) / 2, bottom - 25, _sep_bottom[2], _sep_bottom[3], _sep_bottom.tex[2], _sep_bottom.tex[3]) end function _M:createSeparators() - local middle = self.w * 0.5 - local bottom = self.h * 0.8 - local bottom_h = self.h * 0.2 + local icon_x = 0 + local icon_y = self.h - (_talents_icon_h * 1) self.icons = { - display_x = middle - (_talents_icon_w*2) / 2, - display_y = bottom + _sep_horiz[3] / 2, - w = _talents_icon_w*2, - h = 5*_talents_icon_h + display_x = icon_x, + display_y = icon_y, + w = 200, + h = self.h - icon_y, } end function _M:clickIcon(bx, by) - if by < _talents_icon_h then - if bx >= _talents_icon_w then - self.show_npc_list = false - self.player.changed = true - else - self.show_userchat = false - self.logdisplay.changed = true - end - elseif by < 2*_talents_icon_h then - if bx >= _talents_icon_w then - self.show_npc_list = true - self.player.changed = true - else - self.show_userchat = true - end - elseif by < 3*_talents_icon_h then + if bx < _talents_icon_w then + self.show_npc_list = false + self.player.changed = true + elseif bx < 2*_talents_icon_w then + self.show_npc_list = true + self.player.changed = true + elseif bx < 3*_talents_icon_w then self.key:triggerVirtual("SHOW_INVENTORY") - elseif by < 4*_talents_icon_h then + elseif bx < 4*_talents_icon_w then self.key:triggerVirtual("SHOW_CHARACTER_SHEET") - elseif by < 5*_talents_icon_h then + elseif bx < 5*_talents_icon_w then self.key:triggerVirtual("EXIT") + elseif bx < 6*_talents_icon_w then + self.key:triggerVirtual("SHOW_MESSAGE_LOG") end end function _M:mouseIcon(bx, by) - if by < _talents_icon_h then - if bx >= _talents_icon_w then - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display talents\nToggle with [tab]") - else - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display game log\nToggle with [ctrl+space]") - end - elseif by < 2*_talents_icon_h then - if bx >= _talents_icon_w then - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display creatures\nToggle with [tab]") - else - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display community chat\nToggle with [ctrl+space]") - end - elseif by < 3*_talents_icon_h then - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Inventory") - elseif by < 4*_talents_icon_h then - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Character Sheet") - elseif by < 5*_talents_icon_h then - self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Main menu") + if bx < _talents_icon_w then + self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display talents\nToggle with #{bold}##GOLD#[tab]#LAST##{normal}#") + elseif bx < 2*_talents_icon_w then + self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Display creatures\nToggle with #{bold}##GOLD#[tab]#LAST##{normal}#") + elseif bx < 3*_talents_icon_w then + self.tooltip:displayAtMap(nil, nil, self.w, self.h, "#{bold}##GOLD#I#LAST##{normal}#nventory") + elseif bx < 4*_talents_icon_w then + self.tooltip:displayAtMap(nil, nil, self.w, self.h, "#{bold}##GOLD#C#LAST##{normal}#haracter Sheet") + elseif bx < 5*_talents_icon_w then + self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Main menu (#{bold}##GOLD#Esc#LAST##{normal}#)") + elseif bx < 6*_talents_icon_w then + self.tooltip:displayAtMap(nil, nil, self.w, self.h, "Show message/chat log (#{bold}##GOLD#ctrl+m#LAST##{normal}#)") end end diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index fca6fca92985e321937993b4dff9bf416caacab2..6899a46f0fde5e1ccf4c2e50646bb6ea394911b4 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -219,7 +219,7 @@ function _M:act() self.old_life = self.life -- Clean log flasher - game.flash:empty() +-- game.flash:empty() -- Resting ? Running ? Otherwise pause if not self:restStep() and not self:runStep() and self.player then diff --git a/game/modules/tome/dialogs/ShowChatLog.lua b/game/modules/tome/dialogs/ShowChatLog.lua new file mode 100644 index 0000000000000000000000000000000000000000..3f5a7c2d762693de589532ac66a8b5f653fd62dd --- /dev/null +++ b/game/modules/tome/dialogs/ShowChatLog.lua @@ -0,0 +1,160 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010, 2011 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +require "engine.class" +local Dialog = require "engine.ui.Dialog" +local Tab = require "engine.ui.Tab" +local Mouse = require "engine.Mouse" +local Slider = require "engine.ui.Slider" + +module(..., package.seeall, class.inherit(Dialog)) + +function _M:init(title, shadow, log, chat) + local w = math.floor(game.w * 0.9) + local h = math.floor(game.h * 0.9) + Dialog.init(self, title, w, h) + if shadow then self.shadow = shadow end + + self.log, self.chat = log, chat + + local tabs = {} + + local order = {} + local list = {} + for name, data in pairs(chat.channels) do list[#list+1] = name end + table.sort(list, function(a,b) if a == "global" then return 1 elseif b == "global" then return nil else return a < b end end) + order[#order+1] = {timestamp=log:getLogLast(), tab="__log"} + + tabs[#tabs+1] = {top=0, left=0, ui = Tab.new{title="Game Log", fct=function() end, on_change=function() local i = #tabs self:switchTo(tabs[1]) end, default=true}, tab_channel="__log" } + for i, name in ipairs(list) do + local oname = name + local nb_users = 0 + for _, _ in pairs(chat.channels[name].users) do nb_users = nb_users + 1 end + name = name:capitalize().." ("..nb_users..")" + + local ii = i + tabs[#tabs+1] = {top=0, left=(#tabs==0) and 0 or tabs[#tabs].ui, ui = Tab.new{title=name, fct=function() end, on_change=function() local i = ii+1 self:switchTo(tabs[i]) end, default=false}, tab_channel=oname } + order[#order+1] = {timestamp=chat:getLogLast(oname), tab=oname} + end + + self.start_y = tabs[1].ui.h + 5 + + self:loadUI(tabs) + self.tabs = tabs + self:setupUI() + + self.scrollbar = Slider.new{size=self.h - 20, max=1, inverse=true} + + table.sort(order, function(a,b) return a.timestamp > b.timestamp end) + self:switchTo(self.last_tab or "__log") +end + +function _M:generate() + Dialog.generate(self) + + -- Add UI controls + local tabs = self.tabs + self.key:addBinds{ + MOVE_UP = function() self:setScroll(self.scroll - 1) end, + MOVE_DOWN = function() self:setScroll(self.scroll + 1) end, + ACCEPT = "EXIT", + EXIT = function() game:unregisterDialog(self) end, + } + self.key:addCommands{ + _TAB = function() local sel = 1 for i=1, #tabs do if tabs[i].ui.selected then sel = i break end end self:switchTo(tabs[util.boundWrap(sel+1, 1, #tabs)]) end, + _HOME = function() self:setScroll(1) end, + _END = function() self:setScroll(self.max) end, + _PAGEUP = function() self:setScroll(self.scroll - self.max_display) end, + _PAGEDOWN = function() self:setScroll(self.scroll + self.max_display) end, + } +end + +function _M:mouseEvent(button, x, y, xrel, yrel, bx, by, event) + Dialog.mouseEvent(self, button, x, y, xrel, yrel, bx, by, event) + + if button == "wheelup" and event == "button" then self.key:triggerVirtual("MOVE_UP") + elseif button == "wheeldown" and event == "button" then self.key:triggerVirtual("MOVE_DOWN") + end +end + +function _M:loadLog(log) + self.lines = {} + for i = #log, 1, -1 do + self.lines[#self.lines+1] = log[i] + end + + self.max_h = self.ih - self.iy + self.max = #log + self.max_display = math.floor(self.max_h / self.font_h) + + self.scrollbar.max = self.max - self.max_display + 1 + self.scroll = nil + self:setScroll(self.max - self.max_display + 1) +end + +function _M:switchTo(ui) + if type(ui) == "string" then for i, tab in ipairs(self.tabs) do if tab.tab_channel == ui then ui = tab end end end + if type(ui) == "string" then ui = self.tabs[1] end + + for i, ui in ipairs(self.tabs) do ui.ui.selected = false end + ui.ui.selected = true + if ui.tab_channel == "__log" then + self:loadLog(self.log:getLog()) + else + self:loadLog(self.chat:getLog(ui.tab_channel)) + end + -- Set it on the class to persist between invocations + _M.last_tab = ui.tab_channel +end + +function _M:setScroll(i) + local old = self.scroll + self.scroll = util.bound(i, 1, math.max(1, self.max - self.max_display + 1)) + if self.scroll == old then return end + + self.dlist = {} + local nb = 0 + local old_style = self.font:getStyle() + for z = 1 + self.scroll, #self.lines do + local stop = false + local tstr = self.lines[z] + if not tstr then break end + local gen = self.font:draw(tstr, self.iw - 10, 255, 255, 255) + for i = 1, #gen do + self.dlist[#self.dlist+1] = gen[i] + nb = nb + 1 + if nb >= self.max_display then stop = true break end + end + if stop then break end + end + self.font:setStyle(old_style) +end + +function _M:innerDisplay(x, y, nb_keyframes) + local h = y + self.iy + self.start_y + for i = 1, #self.dlist do + local item = self.dlist[i] + if self.shadow then item._tex:toScreenFull(x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow) end + item._tex:toScreenFull(x, h, item.w, item.h, item._tex_w, item._tex_h) + h = h + self.font_h + end + + self.scrollbar.pos = self.scrollbar.max - self.scroll + 1 + self.scrollbar:display(x + self.iw - self.scrollbar.w, y) +end