diff --git a/TODO b/TODO index efdad0b1..e4c9a02c 100644 --- a/TODO +++ b/TODO @@ -61,6 +61,7 @@ change Align/Anchors lua API from enum to text == Client make possible to reload modules +fix modules recursivity, it makes client crash implement left panel with dragging windows clean sprites cache periodically create a shader manager diff --git a/modules/client_topmenu/topmenu.otui b/modules/client_topmenu/topmenu.otui index 540bd9a8..288704b2 100644 --- a/modules/client_topmenu/topmenu.otui +++ b/modules/client_topmenu/topmenu.otui @@ -61,6 +61,7 @@ TopPanel type: horizontalBox spacing: 4 padding: 6 4 + visible: false Panel id: rightButtonsPanel diff --git a/modules/core_lib/const.lua b/modules/core_lib/const.lua index dc65c712..de7a2fd4 100644 --- a/modules/core_lib/const.lua +++ b/modules/core_lib/const.lua @@ -309,3 +309,11 @@ SpeakChannelRed = 11 SpeakChannelOrange = 12 SpeakMonsterSay = 13 SpeakMonsterYell = 14 + + +FightOffensive = 1 +FightBalanced = 2 +FightDefensive = 3 + +DontChase = 0 +ChaseOpponent = 1 diff --git a/modules/core_lib/globals.lua b/modules/core_lib/globals.lua index f74bf79c..5ef31a99 100644 --- a/modules/core_lib/globals.lua +++ b/modules/core_lib/globals.lua @@ -51,6 +51,11 @@ function displayUI(arg1, options) return widget end +function loadUI(otui, parent) + local otuiFilePath = resolvepath(otui, 2) + return g_ui.loadUI(otuiFilePath, parent) +end + function createWidget(style, parent) local className = g_ui.getStyleClass(style) if className == "" then diff --git a/modules/core_lib/util.lua b/modules/core_lib/util.lua index d0bc1292..5a83a349 100644 --- a/modules/core_lib/util.lua +++ b/modules/core_lib/util.lua @@ -57,6 +57,19 @@ function disconnect(object, signalsAndSlots) end end +function newclass() + local class = {} + function class.internalCreate() + local instance = {} + for k,v in pairs(class) do + instance[k] = v + end + return instance + end + class.create = class.internalCreate + return class +end + function extends(base) local derived = {} function derived.internalCreate() diff --git a/modules/core_widgets/core_widgets.otmod b/modules/core_widgets/core_widgets.otmod index 95836e90..0145bb15 100644 --- a/modules/core_widgets/core_widgets.otmod +++ b/modules/core_widgets/core_widgets.otmod @@ -25,6 +25,8 @@ Module dofile 'uimessagebox' dofile 'tooltip' + dofile 'radiogroup' + ToolTip.init() onUnload: | diff --git a/modules/core_widgets/radiogroup.lua b/modules/core_widgets/radiogroup.lua new file mode 100644 index 00000000..d4c0c833 --- /dev/null +++ b/modules/core_widgets/radiogroup.lua @@ -0,0 +1,43 @@ +RadioGroup = newclass() + +function RadioGroup.create() + local radiogroup = RadioGroup.internalCreate() + radiogroup.widgets = {} + return radiogroup +end + +function RadioGroup:destroy() + while #self.widgets ~= 0 do + self:removeWidget(self.widgets[1]) + end +end + +function RadioGroup:addWidget(widget) + table.insert(self.widgets, widget) + widget.onMousePress = function(widget) self:selectWidget(widget) end +end + +function RadioGroup:removeWidget(widget) + if self.selectedWidget == widget then + self:selectWidget(nil) + end + widget.onMousePress = nil + table.removevalue(self.widgets, widget) +end + +function RadioGroup:selectWidget(selectedWidget) + if selectedWidget == self.selectedWidget then return end + + local previousSelectedWidget = self.selectedWidget + self.selectedWidget = selectedWidget + + if previousSelectedWidget then + previousSelectedWidget:setChecked(false) + end + + if selectedWidget then + selectedWidget:setChecked(true) + end + + signalcall(self.onSelectionChange, self, selectedWidget, previousSelectedWidget) +end diff --git a/modules/core_widgets/tooltip.lua b/modules/core_widgets/tooltip.lua index be0a5929..6f8177c0 100644 --- a/modules/core_widgets/tooltip.lua +++ b/modules/core_widgets/tooltip.lua @@ -57,6 +57,8 @@ function ToolTip.terminate() currentHoveredWidget = nil toolTipLabel:destroy() toolTipLabel = nil + + ToolTip = nil end function ToolTip.display(text) diff --git a/modules/core_widgets/uicheckbox.lua b/modules/core_widgets/uicheckbox.lua index 09685d2d..016551f5 100644 --- a/modules/core_widgets/uicheckbox.lua +++ b/modules/core_widgets/uicheckbox.lua @@ -7,9 +7,7 @@ function UICheckBox.create() return checkbox end -function UICheckBox:onMouseRelease(mousePos, mouseButton) - if self:isPressed() and self:containsPoint(mousePos) then - self:setChecked(not self:isChecked()) - return true - end +function UICheckBox:onMousePress(mousePos, mouseButton) + self:setChecked(not self:isChecked()) + return true end diff --git a/modules/game_combatcontrols/combatcontrols.lua b/modules/game_combatcontrols/combatcontrols.lua index 4494fe70..521d6501 100644 --- a/modules/game_combatcontrols/combatcontrols.lua +++ b/modules/game_combatcontrols/combatcontrols.lua @@ -1,13 +1,132 @@ CombatControls = {} +-- private variables local combatControlsButton +local combatControlsWindow +local fightOffensiveBox +local fightBalancedBox +local fightDefensiveBox +local chaseModeButton +local safeFightButton +local fightModeRadioGroup +-- private functions +local function onFightModeChange(self, selectedFightButton) + if selectedFightButton == nil then return end + local buttonId = selectedFightButton:getId() + local fightMode + if buttonId == 'fightOffensiveBox' then + fightMode = FightOffensive + elseif buttonId == 'fightBalancedBox' then + fightMode = FightBalanced + else + fightMode = FightDefensive + end + if Game.getFightMode ~= fightMode then + Game.setFightMode(fightMode) + end +end + +local function onChaseModeChange(self, checked) + local chaseMode + if checked then + chaseMode = ChaseOpponent + else + chaseMode = DontChase + end + if Game.getChaseMode() ~= chaseMode then + Game.setChaseMode(chaseMode) + end +end + +local function onSafeFightChange(self, checked) + local safeFight = not checked + if Game.isSafeFight() ~= safeFight then + Game.setSafeFight(not checked) + end +end + +-- public functions function CombatControls.init() combatControlsButton = TopMenu.addGameButton('combatControlsButton', 'Combat Controls', 'combatcontrols.png', CombatControls.toggle) -end + combatControlsButton:setOn(true) + combatControlsWindow = loadUI('combatcontrols.otui') + fightOffensiveBox = combatControlsWindow:getChildById('fightOffensiveBox') + fightBalancedBox = combatControlsWindow:getChildById('fightBalancedBox') + fightDefensiveBox = combatControlsWindow:getChildById('fightDefensiveBox') + chaseModeButton = combatControlsWindow:getChildById('chaseModeBox') + safeFightButton = combatControlsWindow:getChildById('safeFightBox') + + fightModeRadioGroup = RadioGroup.create() + fightModeRadioGroup:addWidget(fightOffensiveBox) + fightModeRadioGroup:addWidget(fightBalancedBox) + fightModeRadioGroup:addWidget(fightDefensiveBox) + + connect(fightModeRadioGroup, { onSelectionChange = onFightModeChange }) + connect(chaseModeButton, { onCheckChange = onChaseModeChange }) + connect(safeFightButton, { onCheckChange = onSafeFightChange }) + connect(Game, { onLogin = CombatControls.online }) + connect(Game, { onLogout = CombatControls.offline }) + + if Game.isOnline() then + CombatControls.online() + end +end function CombatControls.terminate() + if Game.isOnline() then + CombatControls.offline() + end + + fightModeRadioGroup:destroy() + fightModeRadioGroup = nil + + fightOffensiveBox = nil + fightBalancedBox = nil + fightDefensiveBox = nil + chaseModeButton = nil + safeFightButton = nil + combatControlsButton:destroy() combatControlsButton = nil + + combatControlsWindow:destroy() + combatControlsWindow = nil + + disconnect(Game, { onLogin = CombatControls.online }) + disconnect(Game, { onLogout = CombatControls.offline }) + + CombatControls = nil end + +function CombatControls.online() + Game.gameRightPanel:addChild(combatControlsWindow) + combatControlsWindow:setVisible(combatControlsButton:isOn()) + + local fightMode = Game.getFightMode() + if fightMode == FightOffensive then + fightModeRadioGroup:selectWidget(fightOffensiveBox) + elseif fightMode == FightBalanced then + fightModeRadioGroup:selectWidget(fightBalancedBox) + else + fightModeRadioGroup:selectWidget(fightDefensiveBox) + end + + local chaseMode = Game.getChaseMode() + chaseModeButton:setChecked(chaseMode == ChaseOpponent) + + local safeFight = Game.isSafeFight() + safeFightButton:setChecked(not safeFight) +end + +function CombatControls.offline() + Game.gameRightPanel:removeChild(combatControlsWindow) +end + +function CombatControls.toggle() + local visible = not combatControlsWindow:isExplicitlyVisible() + combatControlsWindow:setVisible(visible) + combatControlsButton:setOn(visible) +end + diff --git a/modules/game_combatcontrols/combatcontrols.otui b/modules/game_combatcontrols/combatcontrols.otui index e69de29b..e9a3af05 100644 --- a/modules/game_combatcontrols/combatcontrols.otui +++ b/modules/game_combatcontrols/combatcontrols.otui @@ -0,0 +1,43 @@ +CombatBox < UICheckBox + size: 20 20 + image-clip: 0 0 20 20 + anchors.top: parent.top + margin-left: 5 + margin-right: 5 + + $checked: + image-clip: 0 20 20 20 + +FightOffensiveBox < CombatBox + image-source: /game_combatcontrols/icons/fightoffensive.png +FightBalancedBox < CombatBox + image-source: /game_combatcontrols/icons/fightbalanced.png +FightDefensiveBox < CombatBox + image-source: /game_combatcontrols/icons/fightdefensive.png +ChaseModeBox < CombatBox + image-source: /game_combatcontrols/icons/chasemode.png +SafeFightBox < CombatBox + image-source: /game_combatcontrols/icons/safefight.png + +UIWindow + width: 130 + height: 30 + margin-top: 10 + margin-left: 6 + margin-right: 6 + + FightOffensiveBox + id: fightOffensiveBox + anchors.right: next.left + FightBalancedBox + id: fightBalancedBox + anchors.right: next.left + FightDefensiveBox + id: fightDefensiveBox + anchors.horizontalCenter: parent.horizontalCenter + ChaseModeBox + id: chaseModeBox + anchors.left: prev.right + SafeFightBox + id: safeFightBox + anchors.left: prev.right diff --git a/modules/game_combatcontrols/icons/chasemode.png b/modules/game_combatcontrols/icons/chasemode.png new file mode 100644 index 00000000..f3ef7058 Binary files /dev/null and b/modules/game_combatcontrols/icons/chasemode.png differ diff --git a/modules/game_combatcontrols/icons/fightbalanced.png b/modules/game_combatcontrols/icons/fightbalanced.png new file mode 100644 index 00000000..31135387 Binary files /dev/null and b/modules/game_combatcontrols/icons/fightbalanced.png differ diff --git a/modules/game_combatcontrols/icons/fightdefensive.png b/modules/game_combatcontrols/icons/fightdefensive.png new file mode 100644 index 00000000..3829a215 Binary files /dev/null and b/modules/game_combatcontrols/icons/fightdefensive.png differ diff --git a/modules/game_combatcontrols/icons/fightoffensive.png b/modules/game_combatcontrols/icons/fightoffensive.png new file mode 100644 index 00000000..2fb6e794 Binary files /dev/null and b/modules/game_combatcontrols/icons/fightoffensive.png differ diff --git a/modules/game_combatcontrols/icons/safefight.png b/modules/game_combatcontrols/icons/safefight.png new file mode 100644 index 00000000..2117067a Binary files /dev/null and b/modules/game_combatcontrols/icons/safefight.png differ diff --git a/modules/game_inventory/inventory.otui b/modules/game_inventory/inventory.otui index 4f404a04..4e1d4a72 100644 --- a/modules/game_inventory/inventory.otui +++ b/modules/game_inventory/inventory.otui @@ -4,7 +4,6 @@ UIWindow margin-top: 10 margin-left: 6 margin-right: 6 - move-policy: free updated Item // head diff --git a/src/otclient/const.h b/src/otclient/const.h index 775523d0..08fdfff6 100644 --- a/src/otclient/const.h +++ b/src/otclient/const.h @@ -211,7 +211,7 @@ namespace Otc }; enum ChaseModes { - StandWhileFighting = 0, + DontChase = 0, ChaseOpponent = 1 }; diff --git a/src/otclient/core/game.cpp b/src/otclient/core/game.cpp index 3a9fd83d..5e0014ed 100644 --- a/src/otclient/core/game.cpp +++ b/src/otclient/core/game.cpp @@ -77,6 +77,12 @@ void Game::processLogin(const LocalPlayerPtr& localPlayer, int serverBeat) m_localPlayer = localPlayer; m_serverBeat = serverBeat; + // synchronize fight modes with the server + m_fightMode = Otc::FightBalanced; + m_chaseMode = Otc::DontChase; + m_safeFight = true; + m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight); + // NOTE: the entire map description is not known yet g_lua.callGlobalField("Game", "onLogin", localPlayer); } @@ -384,6 +390,33 @@ void Game::move(const ThingPtr& thing, const Position& toPos, int count) m_protocolGame->sendThrow(thing->getPosition(), thing->getId(), thing->getStackpos(), toPos, count); } +void Game::setChaseMode(Otc::ChaseModes chaseMode) +{ + if(!isOnline() || !checkBotProtection()) + return; + + m_chaseMode = chaseMode; + m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight); +} + +void Game::setFightMode(Otc::FightModes fightMode) +{ + if(!isOnline() || !checkBotProtection()) + return; + + m_fightMode = fightMode; + m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight); +} + +void Game::setSafeFight(bool on) +{ + if(!isOnline() || !checkBotProtection()) + return; + + m_safeFight = on; + m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight); +} + void Game::attack(const CreaturePtr& creature) { if(!isOnline() || !creature || !checkBotProtection()) diff --git a/src/otclient/core/game.h b/src/otclient/core/game.h index 48b3fe23..6f83ca04 100644 --- a/src/otclient/core/game.h +++ b/src/otclient/core/game.h @@ -74,6 +74,14 @@ public: void useInventoryItemWith(int itemId, const ThingPtr& toThing); void move(const ThingPtr &thing, const Position& toPos, int count); + // fight tatics related + void setChaseMode(Otc::ChaseModes chaseMode); + void setFightMode(Otc::FightModes fightMode); + void setSafeFight(bool on); + Otc::ChaseModes getChaseMode() { return m_chaseMode; } + Otc::FightModes getFightMode() { return m_fightMode; } + bool isSafeFight() { return m_safeFight; } + // attack/follow related void attack(const CreaturePtr& creature); void cancelAttack(); @@ -124,6 +132,10 @@ private: ProtocolGamePtr m_protocolGame; bool m_dead; int m_serverBeat; + + Otc::FightModes m_fightMode; + Otc::ChaseModes m_chaseMode; + bool m_safeFight; }; extern Game g_game; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 0549ed0b..9a778363 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -204,6 +204,12 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("turn", std::bind(&Game::turn, &g_game, _1)); g_lua.bindClassStaticFunction("walk", std::bind(&Game::walk, &g_game, _1)); g_lua.bindClassStaticFunction("forceWalk", std::bind(&Game::forceWalk, &g_game, _1)); + g_lua.bindClassStaticFunction("setChaseMode", std::bind(&Game::setChaseMode, &g_game, _1)); + g_lua.bindClassStaticFunction("setFightMode", std::bind(&Game::setFightMode, &g_game, _1)); + g_lua.bindClassStaticFunction("setSafeFight", std::bind(&Game::setSafeFight, &g_game, _1)); + g_lua.bindClassStaticFunction("getChaseMode", std::bind(&Game::getChaseMode, &g_game)); + g_lua.bindClassStaticFunction("getFightMode", std::bind(&Game::getFightMode, &g_game)); + g_lua.bindClassStaticFunction("isSafeFight", std::bind(&Game::isSafeFight, &g_game)); g_lua.bindClassStaticFunction("attack", std::bind(&Game::attack, &g_game, _1)); g_lua.bindClassStaticFunction("cancelAttack", std::bind(&Game::cancelAttack, &g_game)); g_lua.bindClassStaticFunction("follow", std::bind(&Game::follow, &g_game, _1));