diff --git a/TODO b/TODO index 5ef2a7a4..2732d603 100644 --- a/TODO +++ b/TODO @@ -1,35 +1,16 @@ -==================================================== -High priority TODO in order (before first public disclose) - -multiline text edit -move windows, navigate in containers -complete miniwindow (close, minimize, resize, move) -create and bind all game events -player status icons (poison, etc) -load modules from zip files -display exit box when exiting from game -scrollbar and scrollable widgets - -==================================================== -Low priority TODO - == Core -review directories loading search -load modules from zip packages create a class for reading binary files rework lua/c++ logger -replace autoload-antencedence with load-before/load-after == Graphics -use CoordsBuffer in font -cache renders into framebuffers -use hardware buffer -use indices -fix opacity and cached framebuffers conflict map zoom rendering could be optimized using framebuffer caches -make low/medium/high settings for economizing graphics memory thus allowing to run the client smoothily in smartphones +implement graphics options menu -== Lua +== Modules +fix modules recursivity, it makes client crash +load modules from zip packages + +== Lua engine make possible to bind non LuaObject derived classes on lua engine (for usage with Point,Rect,Color,Size) review usage of x,y/width,height in lua instead of point/size @@ -37,40 +18,34 @@ review usage of x,y/width,height in lua instead of point/size port to MacOs and iphone == UI +review anchors API, add possibility to get/remove anchors multiline rich text widget move layout proprieties to widget style multiline text editor widget -fix style inheretance using a style translator +fix style inheritance using a style translator find a way to add new widgets without focusing them review UI/style loader and make more error prone with more warnings reapply anchor styles when adding new childs -ui text selection -find styles by scope make set of background/icon/image width alone work check for recursive anchors and print a error instead of crashing -make api to enable/disable capture of events to avoid massive event processing +make api to enable/disable capture of events like mouseMove to avoid massive event processing review style apply system -rework widgets rendering order -cache or preload otui files to avoid freezes because of hd reading +review widgets rendering order, consider adding z-index change Align/Anchors lua API from enum to text -== Client -fix modules recursivity, it makes client crash -implement left panel with dragging windows +== Game clean sprites cache periodically create a shader manager find a way to load map rendering styles move redering of creatures names, skulls, etc to UI -make protocol class compatible with old tibia protocols handle corrupt errors in dat/spr remake spr/dat using OTML and image files -game/graphics window with options -do lua game event calls from Game instead from GameProtocol +== Game modules minimap window login queue questlog edit texts trade window shop window -battle window + diff --git a/modules/core_lib/mouse.lua b/modules/core_lib/mouse.lua index d8c137cd..fbc48396 100644 --- a/modules/core_lib/mouse.lua +++ b/modules/core_lib/mouse.lua @@ -26,8 +26,9 @@ function Mouse.isCursorChanged() return cursorChanged end -function Mouse.isPressed() - return g_ui.getPressedWidget() ~= nil +function Mouse.isPressed(button) + if not button then button = MouseLeftButton end + return g_window.isMouseButtonPressed(button) end function Mouse.bindAutoPress(widget, callback) diff --git a/modules/core_lib/widgets/uiscrollbar.lua b/modules/core_lib/widgets/uiscrollbar.lua index 4399f8c9..5b8ab0e0 100644 --- a/modules/core_lib/widgets/uiscrollbar.lua +++ b/modules/core_lib/widgets/uiscrollbar.lua @@ -180,9 +180,17 @@ end function UIScrollBar:onMouseWheel(mousePos, mouseWheel) if mouseWheel == MouseWheelUp then - self:decrement() + if self.orientation == 'vertical' then + self:decrement() + else + self:increment() + end else - self:increment() + if self.orientation == 'vertical' then + self:increment() + else + self:decrement() + end end return true end diff --git a/modules/core_lib/widgets/uispinbox.lua b/modules/core_lib/widgets/uispinbox.lua index 8593f503..68e4e11f 100644 --- a/modules/core_lib/widgets/uispinbox.lua +++ b/modules/core_lib/widgets/uispinbox.lua @@ -5,60 +5,23 @@ function UISpinBox.create() spinbox:setValidCharacters('0123456789') spinbox.minimum = 0 spinbox.maximum = 0 - spinbox:setCurrentIndex(0) + spinbox.value = 0 spinbox:setText("0") return spinbox end -function UISpinBox:setCurrentIndex(index) - if index >= self.minimum and index <= self.maximum then - if self:getText():len() > 0 then - self:setText(index) - end - self.currentIndex = index - self:onIndexChange(index) - end -end - -function UISpinBox:setMinimum(minimum) - if minimum > self.maximum then - print("[UISpinBox:setMinimum]: minimum value cant be greater than maximum") - return false - end - if self.currentIndex < minimum then - self:setCurrentIndex(minimum) - end - self.minimum = minimum -end - -function UISpinBox:setMaximum(maximum) - if maximum < self.minimum then - print("[UISpinBox:setMaximum]: maximum value cant be lower than minimum") - return false - end - if self.currentIndex > maximum then - self:setCurrentIndex(maximum) - end - self.maximum = maximum -end - -function UISpinBox:getCurrentIndex() - return self.currentIndex -end - function UISpinBox:onMouseWheel(mousePos, direction) if direction == MouseWheelUp then - self:setCurrentIndex(self.currentIndex + 1) + self:setValue(self.value + 1) elseif direction == MouseWheelDown then - self:setCurrentIndex(self.currentIndex - 1) + self:setValue(self.value - 1) end return true end function UISpinBox:onTextChange(text, oldText) - if text:len() == 0 then - self:setCurrentIndex(self.minimum) + self:setValue(self.minimum) return end @@ -68,21 +31,45 @@ function UISpinBox:onTextChange(text, oldText) return end - self:setCurrentIndex(number) + self:setValue(number) end -function UISpinBox:onIndexChange(index) +function UISpinBox:onValueChange(value) -- nothing todo end function UISpinBox:onStyleApply(styleName, styleNode) - -- tonumber converts to 0 if not valid - if styleNode.maximum and tonumber(styleNode.maximum) then - self:setMaximum(tonumber(styleNode.maximum)) + for name, value in pairs(styleNode) do + if name == 'maximum' then + self:setMaximum(value) + elseif name == 'minimum' then + self:setMinimum(value) + end end - - if styleNode.minimum and tonumber(styleNode.minimum) then - self:setMinimum(tonumber(styleNode.minimum)) +end + +function UISpinBox:setValue(value) + value = math.max(math.min(self.maximum, value), self.minimum) + if value == self.value then return end + if self:getText():len() > 0 then + self:setText(value) + end + self.value = value + signalcall(self.onValueChange, self, value) +end + +function UISpinBox:setMinimum(minimum) + self.minimum = minimum + if self.value < minimum then + self:setValue(minimum) + end +end + +function UISpinBox:setMaximum(maximum) + self.maximum = maximum + if self.value > maximum then + self:setValue(maximum) end end +function UISpinBox:getValue() return self.value end diff --git a/modules/game/gameinterface.lua b/modules/game/gameinterface.lua index f226c628..144bc922 100644 --- a/modules/game/gameinterface.lua +++ b/modules/game/gameinterface.lua @@ -202,8 +202,9 @@ function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatu if creatureThing:asPlayer() then menu:addSeparator() - menu:addOption('Message to ' .. creatureThing:getName(), function() print('message') end) - menu:addOption('Add to VIP list', function() g_game.addVip(creatureThing:getName()) end) + local creatureName = creatureThing:getName() + menu:addOption('Message to ' .. creatureName, function() g_game.openPrivateChannel(creatureName) end) + menu:addOption('Add to VIP list', function() g_game.addVip(creatureName) end) local localPlayerShield = localPlayer:asCreature():getShield() local creatureShield = creatureThing:getShield() @@ -310,6 +311,31 @@ function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, l return false end +function GameInterface.moveStackableItem(item, toPos) + local count = item:getCount() + + local countWindow = createWidget('CountWindow', rootWidget) + local spinbox = countWindow:getChildById('countSpinBox') + local scrollbar = countWindow:getChildById('countScrollBar') + spinbox:setMaximum(count) + spinbox:setMinimum(1) + spinbox:setValue(count) + scrollbar:setMaximum(count) + scrollbar:setMinimum(1) + scrollbar:setValue(count) + scrollbar.onValueChange = function(self, value) spinbox:setValue(value) end + spinbox.onValueChange = function(self, value) scrollbar:setValue(value) end + + local okButton = countWindow:getChildById('buttonOk') + local moveFunc = function() + g_game.move(item, toPos, spinbox:getValue()) + okButton:getParent():destroy() + end + + countWindow.onEnter = moveFunc + okButton.onClick = moveFunc +end + function GameInterface.getRootPanel() return gameRootPanel end diff --git a/modules/game/styles/countwindow.otui b/modules/game/styles/countwindow.otui index eb40d20e..9228af3b 100644 --- a/modules/game/styles/countwindow.otui +++ b/modules/game/styles/countwindow.otui @@ -12,17 +12,17 @@ CountWindow < MainWindow margin-top: 2 SpinBox - id: spinbox + id: countSpinBox anchors.left: prev.right anchors.right: parent.right anchors.top: parent.top - HorizontalSeparator - id: separator + HorizontalScrollBar + id: countScrollBar anchors.left: parent.left anchors.right: parent.right - anchors.bottom: next.top - margin-bottom: 10 + anchors.top: prev.bottom + margin-top: 8 Button id: buttonOk @@ -30,7 +30,7 @@ CountWindow < MainWindow width: 64 anchors.right: next.left anchors.bottom: parent.bottom - margin-right: 10 + margin-right: 5 Button id: buttonCancel diff --git a/modules/game/widgets/uicountwindow.lua b/modules/game/widgets/uicountwindow.lua deleted file mode 100644 index ae33df27..00000000 --- a/modules/game/widgets/uicountwindow.lua +++ /dev/null @@ -1,2 +0,0 @@ -UICountWindow = {} - diff --git a/modules/game/widgets/uigamemap.lua b/modules/game/widgets/uigamemap.lua index c81f8fc9..3e4454a5 100644 --- a/modules/game/widgets/uigamemap.lua +++ b/modules/game/widgets/uigamemap.lua @@ -13,17 +13,13 @@ function UIGameMap:onDragEnter(mousePos) local thing = tile:getTopMoveThing() if not thing then return false end - self.parsed = false self.currentDragThing = thing Mouse.setTargetCursor() return true end function UIGameMap:onDragLeave(droppedWidget, mousePos) - if not self.parsed then - self.currentDragThing = nil - end - + self.currentDragThing = nil Mouse.restoreCursor() return true end @@ -34,33 +30,34 @@ function UIGameMap:onDrop(widget, mousePos) local tile = self:getTile(mousePos) if not tile then return false end - local count = widget.currentDragThing:getCount() - if widget.currentDragThing:isStackable() and count > 1 then - widget.parsed = true - local moveWindow = createWidget('CountWindow', rootWidget) - local spinbox = moveWindow:getChildById('spinbox') - spinbox:setMaximum(count) - spinbox:setMinimum(1) - spinbox:setCurrentIndex(count) - - local okButton = moveWindow:getChildById('buttonOk') - okButton.onClick = function() - g_game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex()) - okButton:getParent():destroy() - widget.currentDragThing = nil - end - moveWindow.onEnter = okButton.onClick + local item = widget.currentDragThing + local toPos = tile:getPosition() + if item:isStackable() and item:getCount() > 1 then + GameInterface.moveStackableItem(item, toPos) else - g_game.move(widget.currentDragThing, tile:getPosition(), 1) + g_game.move(item, toPos, 1) end return true end function UIGameMap:onMouseRelease(mousePosition, mouseButton) + if self.cancelNextRelease then + self.cancelNextRelease = false + return true + end + local tile = self:getTile(mousePosition) if tile == nil then return false end - if GameInterface.processMouseAction(mousePosition, mouseButton, nil, tile:getTopLookThing(), tile:getTopUseThing(), tile:getTopCreature(), tile:getTopMultiUseThing()) then + + if Options.getOption('classicControl') and + ((Mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton) or + (Mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then + local tile = self:getTile(mousePosition) + g_game.look(tile:getTopLookThing()) + self.cancelNextRelease = true + return true + elseif GameInterface.processMouseAction(mousePosition, mouseButton, nil, tile:getTopLookThing(), tile:getTopUseThing(), tile:getTopCreature(), tile:getTopMultiUseThing()) then return true elseif mouseButton == MouseLeftButton and self:isPressed() then local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), tile:getPosition(), 255) diff --git a/modules/game/widgets/uiitem.lua b/modules/game/widgets/uiitem.lua index b99c5c34..17d8eff9 100644 --- a/modules/game/widgets/uiitem.lua +++ b/modules/game/widgets/uiitem.lua @@ -5,8 +5,6 @@ function UIItem:onDragEnter(mousePos) if not item then return false end self:setBorderWidth(1) - - self.parsed = false self.currentDragThing = item Mouse.setTargetCursor() return true @@ -14,11 +12,7 @@ end function UIItem:onDragLeave(droppedWidget, mousePos) if self:isVirtual() then return false end - - if not self.parsed then - self.currentDragThing = nil - end - + self.currentDragThing = nil Mouse.restoreCursor() self:setBorderWidth(0) return true @@ -29,24 +23,12 @@ function UIItem:onDrop(widget, mousePos) if not widget or not widget.currentDragThing then return false end - local pos = self.position - local count = widget.currentDragThing:getCount() - if widget.currentDragThing:isStackable() and count > 1 then - widget.parsed = true - local countWindow = createWidget('CountWindow', rootWidget) - local spinbox = moveWindow:getChildById('spinbox') - spinbox:setMaximum(count) - spinbox:setMinimum(1) - spinbox:setCurrentIndex(count) - - local okButton = moveWindow:getChildById('buttonOk') - okButton.onClick = function() - g_game.move(widget.currentDragThing, pos, spinbox:getCurrentIndex()) okButton:getParent():destroy() - widget.currentDragThing = nil - end - moveWindow.onEnter = okButton.onClick + local item = widget.currentDragThing + local toPos = self.position + if item:isStackable() and item:getCount() > 1 then + GameInterface.moveStackableItem(item, toPos) else - g_game.move(widget.currentDragThing, pos, 1) + g_game.move(item, toPos, 1) end self:setBorderWidth(0) diff --git a/modules/game_battle/battle.otui b/modules/game_battle/battle.otui index f8258d97..a559bb13 100644 --- a/modules/game_battle/battle.otui +++ b/modules/game_battle/battle.otui @@ -39,7 +39,7 @@ BattleParty < BattleIcon MiniWindow id: battleWindow text: Battle - height: 100 + height: 166 icon: battle.png @onClose: Battle.toggle() diff --git a/modules/game_hotkeys/hotkeys_manager.lua b/modules/game_hotkeys/hotkeys_manager.lua index 15688ada..1058d711 100644 --- a/modules/game_hotkeys/hotkeys_manager.lua +++ b/modules/game_hotkeys/hotkeys_manager.lua @@ -37,7 +37,7 @@ function HotkeysManager.init() hotkeysWindow = displayUI('hotkeys_manager.otui') hotkeysWindow:setVisible(false) - hotkeysButton = TopMenu.addLeftButton('hotkeysButton', 'Hotkeys (Ctrl+K)', '/game_hotkeys/icon.png', HotkeysManager.toggle) + hotkeysButton = TopMenu.addGameButton('hotkeysButton', 'Hotkeys (Ctrl+K)', '/game_hotkeys/icon.png', HotkeysManager.toggle) Keyboard.bindKeyDown('Ctrl+K', HotkeysManager.toggle) currentHotkeysList = hotkeysWindow:getChildById('currentHotkeys') diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index dfb8b2a2..8ef58841 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -484,6 +484,7 @@ void Application::registerLuaFunctions() g_lua.bindClassStaticFunction("g_window", "getMousePosition", std::bind(&PlatformWindow::getMousePosition, &g_window)); g_lua.bindClassStaticFunction("g_window", "getKeyboardModifiers", std::bind(&PlatformWindow::getKeyboardModifiers, &g_window)); g_lua.bindClassStaticFunction("g_window", "isKeyPressed", std::bind(&PlatformWindow::isKeyPressed, &g_window, _1)); + g_lua.bindClassStaticFunction("g_window", "isMouseButtonPressed", std::bind(&PlatformWindow::isMouseButtonPressed, &g_window, _1)); g_lua.bindClassStaticFunction("g_window", "isVisible", std::bind(&PlatformWindow::isVisible, &g_window)); g_lua.bindClassStaticFunction("g_window", "isFullscreen", std::bind(&PlatformWindow::isFullscreen, &g_window)); g_lua.bindClassStaticFunction("g_window", "isMaximized", std::bind(&PlatformWindow::isMaximized, &g_window)); diff --git a/src/framework/platform/platformwindow.cpp b/src/framework/platform/platformwindow.cpp index b6956989..3ba7b541 100644 --- a/src/framework/platform/platformwindow.cpp +++ b/src/framework/platform/platformwindow.cpp @@ -104,6 +104,9 @@ void PlatformWindow::releaseAllKeys() processKeyUp(keyCode); } + + for(int i=0;i<4;++i) + m_mouseButtonStates[i] = false; } void PlatformWindow::fireKeysPress() @@ -133,3 +136,4 @@ void PlatformWindow::fireKeysPress() } } } + diff --git a/src/framework/platform/platformwindow.h b/src/framework/platform/platformwindow.h index 34005944..ec77921b 100644 --- a/src/framework/platform/platformwindow.h +++ b/src/framework/platform/platformwindow.h @@ -77,8 +77,9 @@ public: int getY() { return m_position.y; } Point getMousePosition() { return m_inputEvent.mousePos; } int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; } - bool isKeyPressed(Fw::Key keyCode) { return m_keysState[keyCode]; } + bool isKeyPressed(Fw::Key keyCode) { return m_keysState[keyCode]; } + bool isMouseButtonPressed(Fw::MouseButton mouseButton) { return m_mouseButtonStates[mouseButton]; } bool isVisible() { return m_visible; } bool isMaximized() { return m_maximized; } bool isFullscreen() { return m_fullscreen; } @@ -107,6 +108,7 @@ protected: Size m_unmaximizedSize; Point m_unmaximizedPos; InputEvent m_inputEvent; + Boolean m_mouseButtonStates[4]; Boolean m_created; Boolean m_visible; diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index 8ee01490..41591455 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -490,6 +490,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetCapture(m_window); m_inputEvent.reset(Fw::MousePressInputEvent); m_inputEvent.mouseButton = Fw::MouseLeftButton; + m_mouseButtonStates[Fw::MouseLeftButton] = true; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; @@ -498,6 +499,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetCapture(NULL); m_inputEvent.reset(Fw::MouseReleaseInputEvent); m_inputEvent.mouseButton = Fw::MouseLeftButton; + m_mouseButtonStates[Fw::MouseLeftButton] = false; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; @@ -506,6 +508,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetCapture(m_window); m_inputEvent.reset(Fw::MousePressInputEvent); m_inputEvent.mouseButton = Fw::MouseMidButton; + m_mouseButtonStates[Fw::MouseMidButton] = true; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; @@ -514,6 +517,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetCapture(NULL); m_inputEvent.reset(Fw::MouseReleaseInputEvent); m_inputEvent.mouseButton = Fw::MouseMidButton; + m_mouseButtonStates[Fw::MouseMidButton] = false; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; @@ -522,6 +526,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetCapture(m_window); m_inputEvent.reset(Fw::MousePressInputEvent); m_inputEvent.mouseButton = Fw::MouseRightButton; + m_mouseButtonStates[Fw::MouseRightButton] = true; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; @@ -530,6 +535,7 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetCapture(NULL); m_inputEvent.reset(Fw::MouseReleaseInputEvent); m_inputEvent.mouseButton = Fw::MouseRightButton; + m_mouseButtonStates[Fw::MouseRightButton] = false; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; diff --git a/src/framework/platform/x11window.cpp b/src/framework/platform/x11window.cpp index 459890ec..37845d13 100644 --- a/src/framework/platform/x11window.cpp +++ b/src/framework/platform/x11window.cpp @@ -719,12 +719,15 @@ void X11Window::poll() switch(event.xbutton.button) { case Button1: m_inputEvent.mouseButton = Fw::MouseLeftButton; + m_mouseButtonStates[Fw::MouseLeftButton] = (event.type == ButtonPress); break; case Button3: m_inputEvent.mouseButton = Fw::MouseRightButton; + m_mouseButtonStates[Fw::MouseRightButton] = (event.type == ButtonPress); break; case Button2: m_inputEvent.mouseButton = Fw::MouseMidButton; + m_mouseButtonStates[Fw::MouseMidButton] = (event.type == ButtonPress); break; case Button4: if(event.type == ButtonPress) {