diff --git a/data/images/game/combatmodes/mount.png b/data/images/game/combatmodes/mount.png new file mode 100644 index 00000000..879646a1 Binary files /dev/null and b/data/images/game/combatmodes/mount.png differ diff --git a/data/images/game/combatmodes/redfistmode.png b/data/images/game/combatmodes/redfistmode.png new file mode 100644 index 00000000..e197210c Binary files /dev/null and b/data/images/game/combatmodes/redfistmode.png differ diff --git a/data/images/game/combatmodes/whitedovemode.png b/data/images/game/combatmodes/whitedovemode.png new file mode 100644 index 00000000..29d4e0c5 Binary files /dev/null and b/data/images/game/combatmodes/whitedovemode.png differ diff --git a/data/images/game/combatmodes/whitehandmode.png b/data/images/game/combatmodes/whitehandmode.png new file mode 100644 index 00000000..c010d828 Binary files /dev/null and b/data/images/game/combatmodes/whitehandmode.png differ diff --git a/data/images/game/combatmodes/yellowhandmode.png b/data/images/game/combatmodes/yellowhandmode.png new file mode 100644 index 00000000..13a0b02b Binary files /dev/null and b/data/images/game/combatmodes/yellowhandmode.png differ diff --git a/modules/game_combatcontrols/combatcontrols.lua b/modules/game_combatcontrols/combatcontrols.lua index 1f04b2fc..5d0f1644 100644 --- a/modules/game_combatcontrols/combatcontrols.lua +++ b/modules/game_combatcontrols/combatcontrols.lua @@ -5,7 +5,14 @@ fightBalancedBox = nil fightDefensiveBox = nil chaseModeButton = nil safeFightButton = nil +whiteDoveBox = nil +whiteHandBox = nil +yellowHandBox = nil +redFistBox = nil +mountButton = nil +pvpModesPanel = nil fightModeRadioGroup = nil +pvpModeRadioGroup = nil function init() combatControlsButton = modules.client_topmenu.addRightGameToggleButton('combatControlsButton', tr('Combat Controls'), '/images/topbuttons/combatcontrols', toggle) @@ -16,15 +23,33 @@ function init() fightOffensiveBox = combatControlsWindow:recursiveGetChildById('fightOffensiveBox') fightBalancedBox = combatControlsWindow:recursiveGetChildById('fightBalancedBox') fightDefensiveBox = combatControlsWindow:recursiveGetChildById('fightDefensiveBox') + chaseModeButton = combatControlsWindow:recursiveGetChildById('chaseModeBox') safeFightButton = combatControlsWindow:recursiveGetChildById('safeFightBox') + + mountButton = combatControlsWindow:recursiveGetChildById('mountButton') + mountButton.onClick = onMountButtonClick + + pvpModesPanel = combatControlsWindow:recursiveGetChildById('pvpModesPanel') + + whiteDoveBox = combatControlsWindow:recursiveGetChildById('whiteDoveBox') + whiteHandBox = combatControlsWindow:recursiveGetChildById('whiteHandBox') + yellowHandBox = combatControlsWindow:recursiveGetChildById('yellowHandBox') + redFistBox = combatControlsWindow:recursiveGetChildById('redFistBox') fightModeRadioGroup = UIRadioGroup.create() fightModeRadioGroup:addWidget(fightOffensiveBox) fightModeRadioGroup:addWidget(fightBalancedBox) fightModeRadioGroup:addWidget(fightDefensiveBox) + + pvpModeRadioGroup = UIRadioGroup.create() + pvpModeRadioGroup:addWidget(whiteDoveBox) + pvpModeRadioGroup:addWidget(whiteHandBox) + pvpModeRadioGroup:addWidget(yellowHandBox) + pvpModeRadioGroup:addWidget(redFistBox) connect(fightModeRadioGroup, { onSelectionChange = onSetFightMode }) + connect(pvpModeRadioGroup, { onSelectionChange = onSetPVPMode }) connect(chaseModeButton, { onCheckChange = onSetChaseMode }) connect(safeFightButton, { onCheckChange = onSetSafeFight }) connect(g_game, { @@ -33,9 +58,12 @@ function init() onFightModeChange = update, onChaseModeChange = update, onSafeFightChange = update, + onPVPModeChange = update, onWalk = check, onAutoWalk = check }) + + connect(LocalPlayer, { onOutfitChange = onOutfitChange }) if g_game.isOnline() then online() @@ -50,6 +78,7 @@ function terminate() end fightModeRadioGroup:destroy() + pvpModeRadioGroup:destroy() combatControlsWindow:destroy() combatControlsButton:destroy() @@ -59,9 +88,12 @@ function terminate() onFightModeChange = update, onChaseModeChange = update, onSafeFightChange = update, + onPVPModeChange = update, onWalk = check, onAutoWalk = check }) + + disconnect(LocalPlayer, { onOutfitChange = onOutfitChange }) end function update() @@ -79,6 +111,14 @@ function update() local safeFight = g_game.isSafeFight() safeFightButton:setChecked(not safeFight) + + if g_game.getFeature(GamePVPMode) then + local pvpMode = g_game.getPVPMode() + local pvpWidget = getPVPBoxByMode(pvpMode) + if pvpWidget then + pvpModeRadioGroup:selectWidget(pvpWidget) + end + end end function check() @@ -101,8 +141,26 @@ function online() g_game.setFightMode(lastCombatControls[char].fightMode) g_game.setChaseMode(lastCombatControls[char].chaseMode) g_game.setSafeFight(lastCombatControls[char].safeFight) + if g_game.getFeature(GamePVPMode) and lastCombatControls[char].pvpMode then + g_game.setPVPMode(lastCombatControls[char].pvpMode) + end end end + + if g_game.getFeature(GamePlayerMounts) then + mountButton:setVisible(true) + mountButton:setChecked(player:isMounted()) + else + mountButton:setVisible(false) + end + + if g_game.getFeature(GamePVPMode) then + pvpModesPanel:setVisible(true) + combatControlsWindow:setHeight(combatControlsWindow.extendedControlsHeight) + else + pvpModesPanel:setVisible(false) + combatControlsWindow:setHeight(combatControlsWindow.simpleControlsHeight) + end end update() @@ -123,6 +181,10 @@ function offline() safeFight = g_game.isSafeFight() } + if g_game.getFeature(GamePVPMode) then + lastCombatControls[char].pvpMode = g_game.getPVPMode() + end + -- save last combat control settings g_settings.setNode('LastCombatControls', lastCombatControls) end @@ -166,6 +228,57 @@ function onSetSafeFight(self, checked) g_game.setSafeFight(not checked) end +function onSetPVPMode(self, selectedPVPButton) + if selectedPVPButton == nil then + return + end + + local buttonId = selectedPVPButton:getId() + local pvpMode = PVPWhiteDove + if buttonId == 'whiteDoveBox' then + pvpMode = PVPWhiteDove + elseif buttonId == 'whiteHandBox' then + pvpMode = PVPWhiteHand + elseif buttonId == 'yellowHandBox' then + pvpMode = PVPYellowHand + elseif buttonId == 'redFistBox' then + pvpMode = PVPRedFist + end + + if g_game.getFeature(GamePVPMode) then + g_game.setPVPMode(pvpMode) + end +end + function onMiniWindowClose() combatControlsButton:setOn(false) end + +function onMountButtonClick(self, mousePos) + local player = g_game.getLocalPlayer() + if player then + player:toggleMount() + end +end + +function onOutfitChange(localPlayer, outfit, oldOutfit) + if outfit.mount == oldOutfit.mount then + return + end + + mountButton:setChecked(outfit.mount ~= nil and outfit.mount > 0) +end + +function getPVPBoxByMode(mode) + local widget = nil + if mode == PVPWhiteDove then + widget = whiteDoveBox + elseif mode == PVPWhiteHand then + widget = whiteHandBox + elseif mode == PVPYellowHand then + widget = yellowHandBox + elseif mode == PVPRedFist then + widget = redFistBox + end + return widget +end diff --git a/modules/game_combatcontrols/combatcontrols.otui b/modules/game_combatcontrols/combatcontrols.otui index df12d94e..57e92da2 100644 --- a/modules/game_combatcontrols/combatcontrols.otui +++ b/modules/game_combatcontrols/combatcontrols.otui @@ -1,12 +1,7 @@ CombatBox < UICheckBox size: 20 20 image-clip: 0 0 20 20 - anchors.top: parent.top - margin: 0 4 - $first: - margin: 0 1 - $last: - margin: 0 1 + margin: 2 4 $checked: image-clip: 0 20 20 20 @@ -21,33 +16,78 @@ ChaseModeBox < CombatBox image-source: /images/game/combatmodes/chasemode SafeFightBox < CombatBox image-source: /images/game/combatmodes/safefight + +MountButton < CombatBox + image-source: /images/game/combatmodes/mount + +WhiteDoveBox < CombatBox + image-source: /images/game/combatmodes/whitedovemode +WhiteHandBox < CombatBox + image-source: /images/game/combatmodes/whitehandmode +YellowHandBox < CombatBox + image-source: /images/game/combatmodes/yellowhandmode +RedFistBox < CombatBox + image-source: /images/game/combatmodes/redfistmode MiniWindow id: combatControlsWindow !text: tr('Combat Controls') icon: /images/topbuttons/combatcontrols - height: 48 + height: 49 &save: true + &simpleControlsHeight: 49 + &extendedControlsHeight: 72 @onClose: modules.game_combatcontrols.onMiniWindowClose() MiniWindowContents FightOffensiveBox id: fightOffensiveBox + anchors.top: parent.top anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter + margin: 2 1 FightBalancedBox id: fightBalancedBox + anchors.top: parent.top anchors.left: prev.right - anchors.verticalCenter: parent.verticalCenter FightDefensiveBox id: fightDefensiveBox + anchors.top: parent.top anchors.left: prev.right - anchors.verticalCenter: parent.verticalCenter + MountButton + id: mountButton + anchors.top: parent.top + anchors.right: next.left ChaseModeBox id: chaseModeBox + anchors.top: parent.top anchors.right: next.left - anchors.verticalCenter: parent.verticalCenter SafeFightBox id: safeFightBox + anchors.top: parent.top + anchors.right: parent.right + margin: 2 1 + + Panel + id: pvpModesPanel + anchors.left: parent.left anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter + anchors.bottom: parent.bottom + height: 20 + + WhiteDoveBox + id: whiteDoveBox + anchors.left: parent.left + anchors.bottom: parent.bottom + margin: 2 1 + WhiteHandBox + id: whiteHandBox + anchors.left: prev.right + anchors.bottom: parent.bottom + YellowHandBox + id: yellowHandBox + anchors.left: prev.right + anchors.bottom: parent.bottom + RedFistBox + id: redFistBox + anchors.left: prev.right + anchors.bottom: parent.bottom \ No newline at end of file diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index faf55c84..67e7afcd 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -47,6 +47,11 @@ FightDefensive = 3 DontChase = 0 ChaseOpponent = 1 +PVPWhiteDove = 0 +PVPWhiteHand = 1 +PVPYellowHand = 2 +PVPRedFist = 3 + GameProtocolChecksum = 1 GameAccountNames = 2 GameChallengeOnLogin = 3 @@ -94,6 +99,7 @@ GameMesssageLevel = 46 GameNewFluids = 47 GamePlayerStateU16 = 48 GameNewOutfitProtocol = 49 +GamePVPMode = 50 TextColors = { red = '#f55e5e', --'#c83200' diff --git a/src/client/const.h b/src/client/const.h index e9ad69ca..3a084a26 100644 --- a/src/client/const.h +++ b/src/client/const.h @@ -206,6 +206,13 @@ namespace Otc ChaseOpponent = 1 }; + enum PVPModes { + WhiteDove = 0, + WhiteHand = 1, + YellowHand = 2, + RedFist = 3 + }; + enum PlayerSkulls { SkullNone = 0, SkullYellow, diff --git a/src/client/game.cpp b/src/client/game.cpp index b648d099..b61dd958 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -51,6 +51,7 @@ Game::Game() m_canReportBugs = false; m_fightMode = Otc::FightBalanced; m_chaseMode = Otc::DontChase; + m_pvpMode = Otc::WhiteDove; m_safeFight = true; } @@ -76,6 +77,7 @@ void Game::resetGameStates() m_canReportBugs = false; m_fightMode = Otc::FightBalanced; m_chaseMode = Otc::DontChase; + m_pvpMode = Otc::WhiteDove; m_safeFight = true; m_followingCreature = nullptr; m_attackingCreature = nullptr; @@ -176,7 +178,7 @@ void Game::processGameStart() m_online = true; // synchronize fight modes with the server - m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight); + m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); // NOTE: the entire map description and local player information is not known yet (bot call is allowed here) enableBotCall(); @@ -239,15 +241,17 @@ void Game::processPlayerHelpers(int helpers) g_lua.callGlobalField("g_game", "onPlayerHelpersUpdate", helpers); } -void Game::processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode) +void Game::processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode, Otc::PVPModes pvpMode) { m_fightMode = fightMode; m_chaseMode = chaseMode; m_safeFight = safeMode; + m_pvpMode = pvpMode; g_lua.callGlobalField("g_game", "onFightModeChange", fightMode); g_lua.callGlobalField("g_game", "onChaseModeChange", chaseMode); g_lua.callGlobalField("g_game", "onSafeFightChange", safeMode); + g_lua.callGlobalField("g_game", "onPVPModeChange", pvpMode); } void Game::processPing() @@ -1195,7 +1199,7 @@ void Game::setChaseMode(Otc::ChaseModes chaseMode) if(m_chaseMode == chaseMode) return; m_chaseMode = chaseMode; - m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight); + m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); g_lua.callGlobalField("g_game", "onChaseModeChange", chaseMode); } @@ -1206,7 +1210,7 @@ void Game::setFightMode(Otc::FightModes fightMode) if(m_fightMode == fightMode) return; m_fightMode = fightMode; - m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight); + m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); g_lua.callGlobalField("g_game", "onFightModeChange", fightMode); } @@ -1217,10 +1221,21 @@ void Game::setSafeFight(bool on) if(m_safeFight == on) return; m_safeFight = on; - m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight); + m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); g_lua.callGlobalField("g_game", "onSafeFightChange", on); } +void Game::setPVPMode(Otc::PVPModes pvpMode) +{ + if(!canPerformGameAction()) + return; + if(m_pvpMode == pvpMode) + return; + m_pvpMode = pvpMode; + m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight, m_pvpMode); + g_lua.callGlobalField("g_game", "onPVPModeChange", pvpMode); +} + void Game::inspectNpcTrade(const ItemPtr& item) { if(!canPerformGameAction() || !item) diff --git a/src/client/game.h b/src/client/game.h index a63ff0f0..d2de19ed 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -74,7 +74,7 @@ protected: void processWalkCancel(Otc::Direction direction); void processPlayerHelpers(int helpers); - void processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode); + void processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode, Otc::PVPModes pvpMode); // message related void processTextMessage(Otc::MessageMode mode, const std::string& text); @@ -211,9 +211,11 @@ public: void setChaseMode(Otc::ChaseModes chaseMode); void setFightMode(Otc::FightModes fightMode); void setSafeFight(bool on); + void setPVPMode(Otc::PVPModes pvpMode); Otc::ChaseModes getChaseMode() { return m_chaseMode; } Otc::FightModes getFightMode() { return m_fightMode; } bool isSafeFight() { return m_safeFight; } + Otc::PVPModes getPVPMode() { return m_pvpMode; } // npc trade related void inspectNpcTrade(const ItemPtr& item); @@ -336,6 +338,7 @@ private: int m_pingDelay; Otc::FightModes m_fightMode; Otc::ChaseModes m_chaseMode; + Otc::PVPModes m_pvpMode; Otc::Direction m_lastWalkDir; bool m_safeFight; bool m_canReportBugs; diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index 22bfe4e3..f71dace8 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -218,9 +218,11 @@ void Client::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "removeVip", &Game::removeVip, &g_game); g_lua.bindSingletonFunction("g_game", "setChaseMode", &Game::setChaseMode, &g_game); g_lua.bindSingletonFunction("g_game", "setFightMode", &Game::setFightMode, &g_game); + g_lua.bindSingletonFunction("g_game", "setPVPMode", &Game::setPVPMode, &g_game); g_lua.bindSingletonFunction("g_game", "setSafeFight", &Game::setSafeFight, &g_game); g_lua.bindSingletonFunction("g_game", "getChaseMode", &Game::getChaseMode, &g_game); g_lua.bindSingletonFunction("g_game", "getFightMode", &Game::getFightMode, &g_game); + g_lua.bindSingletonFunction("g_game", "getPVPMode", &Game::getPVPMode, &g_game); g_lua.bindSingletonFunction("g_game", "isSafeFight", &Game::isSafeFight, &g_game); g_lua.bindSingletonFunction("g_game", "inspectNpcTrade", &Game::inspectNpcTrade, &g_game); g_lua.bindSingletonFunction("g_game", "buyItem", &Game::buyItem, &g_game); diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h index 87e35d73..d7d2df21 100644 --- a/src/client/protocolgame.h +++ b/src/client/protocolgame.h @@ -83,7 +83,7 @@ public: void sendCloseRuleViolation(const std::string& reporter); void sendCancelRuleViolation(); void sendCloseNpcChannel(); - void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight); + void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight, Otc::PVPModes pvpMode); void sendAttack(uint creatureId, uint seq); void sendFollow(uint creatureId, uint seq); void sendInviteToParty(uint creatureId); diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index 4bb6b0d5..343558f7 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -1158,11 +1158,11 @@ void ProtocolGame::parsePlayerModes(const InputMessagePtr& msg) int chaseMode = msg->getU8(); bool safeMode = msg->getU8(); - //TODO: implement pvp modes + int pvpMode = 0; if(g_game.getFeature(Otc::GamePVPMode)) - msg->getU8(); // pvp mode + pvpMode = msg->getU8(); - g_game.processPlayerModes((Otc::FightModes)fightMode, (Otc::ChaseModes)chaseMode, safeMode); + g_game.processPlayerModes((Otc::FightModes)fightMode, (Otc::ChaseModes)chaseMode, safeMode, (Otc::PVPModes)pvpMode); } void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg) diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index 35d7075a..aaa05d4c 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -573,7 +573,7 @@ void ProtocolGame::sendCloseNpcChannel() send(msg); } -void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight) +void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight, Otc::PVPModes pvpMode) { OutputMessagePtr msg(new OutputMessage); msg->addU8(Proto::ClientChangeFightModes); @@ -581,9 +581,8 @@ void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseMod msg->addU8(chaseMode); msg->addU8(safeFight ? 0x01: 0x00); - //TODO: implement pvp modes if(g_game.getFeature(Otc::GamePVPMode)) - msg->addU8(0); // pvp mode + msg->addU8(pvpMode); send(msg); }