From 5520501673b1fc463a9b5e638dfeaa0bf0d77484 Mon Sep 17 00:00:00 2001 From: BeniS Date: Sun, 15 Jul 2012 23:49:28 +1200 Subject: [PATCH] Implemented the mount interface, Fixed some interface stuff, Some cosmetics, and Updated the outfits window * Added new arrow buttons. * Fixed the vertical separator. * Added new game_playermount module to handle player mounting. * Moved the battle icons to /images. * Outfit window accommodates for mounts, loads addons more efficiently and keeps addons set on update, added new Outfit.randomize function that allows you to randomize your outfit colors, and set up a new layout. --- .../skins/default/images/arrow_down.png | Bin 0 -> 3534 bytes .../skins/default/images/arrow_left.png | Bin 0 -> 3614 bytes .../skins/default/images/arrow_right.png | Bin 0 -> 3536 bytes .../skins/default/images/arrow_up.png | Bin 0 -> 3520 bytes .../default/images/vertical_separator.png | Bin 0 -> 2804 bytes .../skins/default/styles/buttons.otui | 2 +- .../skins/default/styles/separators.otui | 2 +- modules/corelib/mouse.lua | 2 +- modules/game/game.otmod | 1 + modules/game_battle/battle.lua | 6 +- modules/game_battle/battle.otui | 10 +- .../{ => images}/battle_monsters.png | Bin .../game_battle/{ => images}/battle_npcs.png | Bin .../game_battle/{ => images}/battle_party.png | Bin .../{ => images}/battle_players.png | Bin .../{ => images}/battle_skulls.png | Bin modules/game_interface/gameinterface.lua | 10 +- modules/game_minimap/minimap.lua | 10 +- modules/game_minimap/minimap.otui | 14 +- modules/game_outfit/outfit.lua | 175 ++++++++++---- modules/game_outfit/outfit.otui | 145 ------------ modules/game_outfit/outfitwindow.otui | 221 ++++++++++++++++++ modules/game_playerdeath/playerdeath.lua | 4 +- modules/game_playerdeath/playerdeath.otmod | 2 +- modules/game_playermount/playermount.lua | 38 +++ modules/game_playermount/playermount.otmod | 15 ++ modules/game_playermount/playermount.otui | 0 modules/game_textwindow/textwindow.lua | 6 +- src/otclient/game.cpp | 32 ++- src/otclient/game.h | 15 +- src/otclient/luafunctions.cpp | 1 + src/otclient/luavaluecasts.cpp | 8 + src/otclient/luavaluecasts.h | 1 + src/otclient/outfit.h | 4 +- src/otclient/protocolcodes.h | 6 +- src/otclient/protocolgame.h | 2 +- src/otclient/protocolgameparse.cpp | 25 +- src/otclient/protocolgamesend.cpp | 16 +- src/otclient/uimap.cpp | 2 +- 39 files changed, 507 insertions(+), 268 deletions(-) create mode 100644 modules/client_skins/skins/default/images/arrow_down.png create mode 100644 modules/client_skins/skins/default/images/arrow_left.png create mode 100644 modules/client_skins/skins/default/images/arrow_right.png create mode 100644 modules/client_skins/skins/default/images/arrow_up.png create mode 100644 modules/client_skins/skins/default/images/vertical_separator.png rename modules/game_battle/{ => images}/battle_monsters.png (100%) rename modules/game_battle/{ => images}/battle_npcs.png (100%) rename modules/game_battle/{ => images}/battle_party.png (100%) rename modules/game_battle/{ => images}/battle_players.png (100%) rename modules/game_battle/{ => images}/battle_skulls.png (100%) delete mode 100644 modules/game_outfit/outfit.otui create mode 100644 modules/game_outfit/outfitwindow.otui create mode 100644 modules/game_playermount/playermount.lua create mode 100644 modules/game_playermount/playermount.otmod create mode 100644 modules/game_playermount/playermount.otui diff --git a/modules/client_skins/skins/default/images/arrow_down.png b/modules/client_skins/skins/default/images/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..c808639a43e61ba8a4bd4623b7cdfdece914f120 GIT binary patch literal 3534 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 IM6N<$f}KsW=l}o! literal 0 HcmV?d00001 diff --git a/modules/client_skins/skins/default/images/arrow_left.png b/modules/client_skins/skins/default/images/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..87e99664e806c2015308cf784b418065a3508310 GIT binary patch literal 3614 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 literal 0 HcmV?d00001 diff --git a/modules/client_skins/skins/default/images/arrow_right.png b/modules/client_skins/skins/default/images/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..e8f6b4309440c4224f2919a5d9cb4ef3160ffe3a GIT binary patch literal 3536 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 MAX_FLOOR_UP) then + if pos.z > MAX_FLOOR_UP then minimapWidget:setCameraPosition(pos) end elseif id == "floorDown" then local pos = minimapWidget:getCameraPosition() pos.z = pos.z + 1 - if(pos.z < MAX_FLOOR_DOWN) then + if pos.z < MAX_FLOOR_DOWN then minimapWidget:setCameraPosition(pos) end end diff --git a/modules/game_minimap/minimap.otui b/modules/game_minimap/minimap.otui index aca13288..60fe4554 100644 --- a/modules/game_minimap/minimap.otui +++ b/modules/game_minimap/minimap.otui @@ -1,5 +1,6 @@ MapControl < Button size: 20 20 + icon-clip: 0 32 16 16 $pressed: icon-clip: 0 0 16 16 @@ -7,19 +8,16 @@ MapControl < Button $hover !pressed: icon-clip: 0 16 16 16 - $!pressed !hover: - icon-clip: 0 32 16 16 - FloorUpControl < MapControl icon-source: /game_minimap/floor_up.png FloorDownControl < MapControl icon-source: /game_minimap/floor_down.png -//ZoomOutControl < MapControl +ZoomOutControl < MapControl //image-source: /game_minimap/zoom_out.png -//ZoomInControl < MapControl +ZoomInControl < MapControl //image-source: /game_minimap/zoom_in.png MiniWindow @@ -64,10 +62,9 @@ MiniWindow enabled: true @onClick: Minimap.onButtonClick(self:getId()) - Button + ZoomInControl id: zoomIn text: + - size: 20 20 anchors.right: parent.right anchors.bottom: parent.bottom margin-right: 4 @@ -75,11 +72,10 @@ MiniWindow enabled: true @onClick: Minimap.onButtonClick(self:getId()) - Button + ZoomOutControl id: zoomOut text: - font: terminus-14px-bold - size: 20 20 anchors.right: parent.right anchors.bottom: parent.bottom margin-right: 4 diff --git a/modules/game_outfit/outfit.lua b/modules/game_outfit/outfit.lua index 11a3afd8..e97d6d6e 100644 --- a/modules/game_outfit/outfit.lua +++ b/modules/game_outfit/outfit.lua @@ -1,13 +1,30 @@ Outfit = {} -- private variables +local addonSets = { + [1] = { 1 }, + [2] = { 2 }, + [3] = { 1, 2 }, + [4] = { 3 }, + [5] = { 1, 3 }, + [6] = { 2, 3 }, + [7] = { 1, 2, 3 } +} local outfitWindow -local outfitCreature local outfit local outfits +local outfitCreature local currentOutfit = 1 + +local addons local currentColorBox local currentClotheButtonBox +local colorBoxes = {} + +local mount +local mounts +local mountCreature +local currentMount = 1 -- private functions local function onAddonCheckChange(addon, value) @@ -71,51 +88,50 @@ local function onClotheCheckChange(clotheButtonBox) end end -local function update() +local function updateOutfit() + if table.empty(outfits) then + return + end local nameWidget = outfitWindow:getChildById('outfitName') nameWidget:setText(outfits[currentOutfit][2]) local availableAddons = outfits[currentOutfit][3] - local addon1 = outfitWindow:getChildById('addon1') - local addon2 = outfitWindow:getChildById('addon2') - local addon3 = outfitWindow:getChildById('addon3') - addon1:setChecked(false) - addon2:setChecked(false) - addon3:setChecked(false) - addon1.onCheckChange = function(self) onAddonCheckChange(self, 1) end - addon2.onCheckChange = function(self) onAddonCheckChange(self, 2) end - addon3.onCheckChange = function(self) onAddonCheckChange(self, 4) end - addon1:setEnabled(false) - addon2:setEnabled(false) - addon3:setEnabled(false) - - -- Maybe rework this someday - if availableAddons == 1 then - addon1:setEnabled(true) - elseif availableAddons == 2 then - addon2:setEnabled(true) - elseif availableAddons == 3 then - addon1:setEnabled(true) - addon2:setEnabled(true) - elseif availableAddons == 4 then - addon3:setEnabled(true) - elseif availableAddons == 5 then - addon1:setEnabled(true) - addon3:setEnabled(true) - elseif availableAddons == 6 then - addon2:setEnabled(true) - addon3:setEnabled(true) - elseif availableAddons == 7 then - addon1:setEnabled(true) - addon2:setEnabled(true) - addon3:setEnabled(true) + + local prevAddons = {} + for k, addon in pairs(addons) do + prevAddons[k] = addon.widget:isChecked() + addon.widget:setChecked(false) + addon.widget:setEnabled(false) + end + + if availableAddons > 0 then + for _, i in pairs(addonSets[availableAddons]) do + addons[i].widget:setEnabled(true) + end end - outfit.type = outfits[currentOutfit][1] outfit.addons = 0 + for k, addon in pairs(prevAddons) do + if addon and addons[k].widget:isEnabled() then + addons[k].widget:setChecked(true) + end + end + + outfit.type = outfits[currentOutfit][1] outfitCreature:setOutfit(outfit) end +function updateMount() + if table.empty(mounts) then + return + end + local nameMountWidget = outfitWindow:getChildById('mountName') + nameMountWidget:setText(mounts[currentMount][2]) + + mount.type = mounts[currentMount][1] + mountCreature:setOutfit(mount) +end + -- public functions function Outfit.init() connect(g_game, { onOpenOutfitWindow = Outfit.create, @@ -126,20 +142,36 @@ function Outfit.terminate() disconnect(g_game, { onOpenOutfitWindow = Outfit.create, onGameEnd = Outfit.destroy }) Outfit.destroy() - Outfit = nil end -function Outfit.create(creature, outfitList) - outfitCreature = creature +function Outfit.create(creatureOutfit, outfitList, creatureMount, mountList) + outfitCreature = creatureOutfit + mountCreature = creatureMount outfits = outfitList - Outfit.destroy() - - outfitWindow = g_ui.displayUI('outfit.otui') - --outfitWindow:lock() + mounts = mountList + Outfit.destroy() + outfitWindow = g_ui.displayUI('outfitwindow.otui') outfit = outfitCreature:getOutfit() - + mount = mountCreature:getOutfit() + + addons = { + [1] = {widget = outfitWindow:getChildById('addon1'), value = 1}, + [2] = {widget = outfitWindow:getChildById('addon2'), value = 2}, + [3] = {widget = outfitWindow:getChildById('addon3'), value = 4} + } + + for k, addon in pairs(addons) do + addon.widget.onCheckChange = function(self) onAddonCheckChange(self, addon.value) end + end + + if outfit.addons > 0 then + for _, i in pairs(addonSets[outfit.addons]) do + addons[i].widget:setChecked(true) + end + end + currentClotheButtonBox = outfitWindow:getChildById('head') outfitWindow:getChildById('head').onCheckChange = onClotheCheckChange outfitWindow:getChildById('primary').onCheckChange = onClotheCheckChange @@ -150,6 +182,9 @@ function Outfit.create(creature, outfitList) local colorBoxPanel = outfitWindow:getChildById('colorBoxPanel') outfitCreatureBox:setCreature(outfitCreature) + local mountCreatureBox = outfitWindow:getChildById('mountCreatureBox') + mountCreatureBox:setCreature(mountCreature) + for j=0,6 do for i=0,18 do local colorBox = g_ui.createWidget('ColorBox', colorBoxPanel) @@ -163,6 +198,7 @@ function Outfit.create(creature, outfitList) colorBox:setChecked(true) end colorBox.onCheckChange = onColorCheckChange + table.insert(colorBoxes, colorBox) end end @@ -173,8 +209,16 @@ function Outfit.create(creature, outfitList) break end end + currentMount = 1 + for i=1,#mountList do + if mountList[i][1] == mount.type then + currentMount = i + break + end + end - update() + updateOutfit() + updateMount() end function Outfit.destroy() @@ -182,29 +226,62 @@ function Outfit.destroy() outfitWindow:destroy() outfitWindow = nil outfitCreature = nil + mountCreature = nil currentColorBox = nil currentClotheButtonBox = nil end end +function Outfit.randomize() + local outfitTemplate = { + outfitWindow:getChildById('head'), + outfitWindow:getChildById('primary'), + outfitWindow:getChildById('secondary'), + outfitWindow:getChildById('detail') + } + + for k, section in pairs(outfitTemplate) do + section:setChecked(true) + colorBoxes[math.random(1, #colorBoxes)]:setChecked(true) + section:setChecked(false) + end + outfitTemplate[1]:setChecked(true) +end + function Outfit.accept() + outfit.mount = mount.type g_game.changeOutfit(outfit) Outfit.destroy() end -function Outfit.nextType() +function Outfit.nextOutfitType() currentOutfit = currentOutfit + 1 if currentOutfit > #outfits then currentOutfit = 1 end - update() + updateOutfit() end -function Outfit.previousType() +function Outfit.previousOutfitType() currentOutfit = currentOutfit - 1 if currentOutfit <= 0 then currentOutfit = #outfits end - update() + updateOutfit() end +function Outfit.nextMountType() + currentMount = currentMount + 1 + if currentMount > #mounts then + currentMount = 1 + end + updateMount() +end + +function Outfit.previousMountType() + currentMount = currentMount - 1 + if currentMount <= 0 then + currentMount = #mounts + end + updateMount() +end diff --git a/modules/game_outfit/outfit.otui b/modules/game_outfit/outfit.otui deleted file mode 100644 index 71e50046..00000000 --- a/modules/game_outfit/outfit.otui +++ /dev/null @@ -1,145 +0,0 @@ -Window - !text: tr('Select Outfit') - size: 550 280 - padding: 0 0 0 0 - - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - - @onEnter: Outfit.accept() - @onEscape: Outfit.destroy() - - Label - id: outfitName - !text: tr('Outfit Name') - width: 100 - anchors.top: parent.top - anchors.left: parent.left - margin-top: 34 - margin-left: 20 - - Creature - id: outfitCreatureBox - anchors.top: outfitName.bottom - anchors.left: outfitName.left - margin-top: 5 - padding: 4 4 4 4 - fixed-creature-size: true - - Panel - id: colorBoxPanel - anchors.top: parent.top - anchors.right: parent.right - margin-top: 54 - margin-right: 20 - width: 323 - height: 119 - layout: - type: grid - cell-size: 16 16 - cell-spacing: 2 - num-columns: 19 - num-lines: 7 - - ButtonBox - id: head - !text: tr('Head') - anchors.top: outfitCreatureBox.top - anchors.left: outfitCreatureBox.right - margin-left: 10 - checked: true - width: 90 - - ButtonBox - id: primary - !text: tr('Primary') - anchors.top: prev.bottom - anchors.left: prev.left - width: 90 - - ButtonBox - id: secondary - !text: tr('Secondary') - anchors.top: prev.bottom - anchors.left: prev.left - width: 90 - - ButtonBox - id: detail - !text: tr('Detail') - anchors.top: prev.bottom - anchors.left: prev.left - width: 90 - - Button - id: outfitNextButton - @onClick: Outfit.nextType() - text: >> - width: 32 - margin-top: 4 - anchors.top: outfitCreatureBox.bottom - anchors.right: outfitCreatureBox.right - - Button - id: outfitPreviousButton - @onClick: Outfit.previousType() - text: << - width: 32 - margin-top: 4 - anchors.top: outfitCreatureBox.bottom - anchors.left: outfitCreatureBox.left - - CheckBox - id: addon1 - !text: tr('Addon 1') - enabled: false - margin-top: 6 - width: 100 - anchors.top: prev.bottom - anchors.left: prev.left - - CheckBox - id: addon2 - !text: tr('Addon 2') - enabled: false - margin-top: 2 - width: 100 - anchors.top: prev.bottom - anchors.left: prev.left - - CheckBox - id: addon3 - !text: tr('Addon 3') - enabled: false - margin-top: 2 - width: 100 - anchors.top: prev.bottom - anchors.left: prev.left - - HorizontalSeparator - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: next.top - margin-left: 16 - margin-right: 16 - margin-bottom: 10 - - Button - id: outfitOkButton - !text: tr('Ok') - width: 64 - anchors.right: next.left - anchors.bottom: parent.bottom - margin-bottom: 16 - margin-right: 16 - @onClick: Outfit.accept() - - Button - id: outfitCancelButton - !text: tr('Cancel') - width: 64 - anchors.right: parent.right - anchors.bottom: parent.bottom - margin-bottom: 16 - margin-right: 16 - @onClick: Outfit.destroy() diff --git a/modules/game_outfit/outfitwindow.otui b/modules/game_outfit/outfitwindow.otui new file mode 100644 index 00000000..09b9bea6 --- /dev/null +++ b/modules/game_outfit/outfitwindow.otui @@ -0,0 +1,221 @@ +BrowseButton < Button + size: 20 29 + icon-clip: 0 0 12 21 + + $hover !disabled: + icon-clip: 0 21 12 21 + + $pressed: + icon-clip: 0 22 12 21 + + $disabled: + color: #f0ad4d88 + +NextOutfitButton < BrowseButton + icon-source: /images/arrow_right.png + +PrevOutfitButton < BrowseButton + icon-source: /images/arrow_left.png + +NextMountButton < BrowseButton + icon-source: /images/arrow_right.png + +PrevMountButton < BrowseButton + icon-source: /images/arrow_left.png + +Window + !text: tr('Select Outfit') + size: 338 375 + padding: 0 0 0 0 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + @onEnter: Outfit.accept() + @onEscape: Outfit.destroy() + + // Creature Boxes + + Creature + id: outfitCreatureBox + anchors.top: parent.top + anchors.left: parent.left + margin-top: 48 + margin-left: 40 + padding: 4 4 4 4 + fixed-creature-size: true + + Label + id: outfitName + !text: tr('No Outfit') + width: 100 + anchors.bottom: prev.top + anchors.left: prev.left + margin-bottom: 2 + + NextOutfitButton + id: outfitNextButton + anchors.left: outfitCreatureBox.right + anchors.verticalCenter: outfitCreatureBox.verticalCenter + margin-left: 3 + enabled: true + @onClick: Outfit.nextOutfitType() + + PrevOutfitButton + id: outfitPrevButton + anchors.right: outfitCreatureBox.left + anchors.verticalCenter: outfitCreatureBox.verticalCenter + margin-right: 3 + enabled: true + @onClick: Outfit.previousOutfitType() + + Creature + id: mountCreatureBox + anchors.top: parent.top + anchors.right: parent.right + margin-top: 48 + margin-right: 40 + padding: 4 4 4 4 + fixed-creature-size: true + + Label + id: mountName + !text: tr('No Mount') + width: 140 + anchors.bottom: prev.top + anchors.left: prev.left + margin-bottom: 2 + + NextMountButton + id: mountNextButton + anchors.left: mountCreatureBox.right + anchors.verticalCenter: mountCreatureBox.verticalCenter + margin-left: 3 + enabled: true + @onClick: Outfit.nextMountType() + + PrevMountButton + id: mountPreviousButton + anchors.right: mountCreatureBox.left + anchors.verticalCenter: mountCreatureBox.verticalCenter + margin-right: 3 + enabled: true + @onClick: Outfit.previousMountType() + + // Addon Check Boxes + + CheckBox + id: addon1 + !text: tr('Addon 1') + width: 80 + anchors.top: outfitCreatureBox.bottom + anchors.left: parent.left + margin-top: 6 + margin-left: 18 + enabled: false + + CheckBox + id: addon2 + !text: tr('Addon 2') + width: 80 + anchors.top: prev.top + anchors.left: prev.right + enabled: false + + CheckBox + id: addon3 + !text: tr('Addon 3') + width: 80 + anchors.top: prev.top + anchors.left: prev.right + enabled: false + + // Body Selection Buttons + + ButtonBox + id: head + !text: tr('Head') + anchors.top: addon1.bottom + anchors.left: addon1.left + margin-top: 5 + checked: true + width: 76 + + ButtonBox + id: primary + !text: tr('Primary') + anchors.top: prev.top + anchors.left: prev.right + width: 76 + + ButtonBox + id: secondary + !text: tr('Secondary') + anchors.top: prev.top + anchors.left: prev.right + width: 76 + + ButtonBox + id: detail + !text: tr('Detail') + anchors.top: prev.top + anchors.left: prev.right + width: 76 + + // Color Panel + + Panel + id: colorBoxPanel + anchors.top: head.bottom + anchors.left: head.left + margin-top: 3 + margin-right: 20 + width: 323 + height: 119 + layout: + type: grid + cell-size: 14 14 + cell-spacing: 2 + num-columns: 19 + num-lines: 7 + + // Action Button Section + + Button + id: randomizeButton + !text: tr('Randomize') + !tooltip: tr('Randomize characters outfit') + width: 75 + anchors.left: prev.left + anchors.top: prev.bottom + margin-right: 16 + @onClick: Outfit.randomize() + + HorizontalSeparator + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: next.top + margin-left: 16 + margin-right: 16 + margin-bottom: 10 + margin-top: 5 + + Button + id: outfitOkButton + !text: tr('Okay') + width: 64 + anchors.right: next.left + anchors.bottom: parent.bottom + margin-bottom: 16 + margin-right: 16 + @onClick: Outfit.accept() + + Button + id: outfitCancelButton + !text: tr('Cancel') + width: 64 + anchors.right: parent.right + anchors.bottom: parent.bottom + margin-bottom: 16 + margin-right: 16 + @onClick: Outfit.destroy() diff --git a/modules/game_playerdeath/playerdeath.lua b/modules/game_playerdeath/playerdeath.lua index 9700f1b7..a74d6d62 100644 --- a/modules/game_playerdeath/playerdeath.lua +++ b/modules/game_playerdeath/playerdeath.lua @@ -23,7 +23,7 @@ end function PlayerDeath.reset() GameInterface.getMapPanel():recursiveGetChildById('centerAdvance'):hide() - if(deathWindow) then + if deathWindow then deathWindow:destroy() deathWindow = nil end @@ -44,7 +44,7 @@ function PlayerDeath.displayDeadMessage() end function PlayerDeath.openWindow() - if(deathWindow) then + if deathWindow then return end deathWindow = g_ui.createWidget('DeathWindow', rootWidget) diff --git a/modules/game_playerdeath/playerdeath.otmod b/modules/game_playerdeath/playerdeath.otmod index a9c98b5c..0618344f 100644 --- a/modules/game_playerdeath/playerdeath.otmod +++ b/modules/game_playerdeath/playerdeath.otmod @@ -1,7 +1,7 @@ Module name: game_playerdeath description: Manage player deaths - author: edubart, BeniS + author: BeniS, edubart website: www.otclient.info dependencies: diff --git a/modules/game_playermount/playermount.lua b/modules/game_playermount/playermount.lua new file mode 100644 index 00000000..a3618b83 --- /dev/null +++ b/modules/game_playermount/playermount.lua @@ -0,0 +1,38 @@ +PlayerMount = {} + +-- private variables + +-- private functions + +-- public functions +function PlayerMount.init() + g_ui.importStyle('playermount.otui') + + connect(g_game, { onDeath = PlayerMount.dismount, + onGameEnd = PlayerMount.dismount }) + + g_keyboard.bindKeyDown('Ctrl+R', PlayerMount.toggleMount, gameRootPanel) +end + +function PlayerMount.terminate() + disconnect(g_game, { onDeath = PlayerMount.dismount, + onGameEnd = PlayerMount.dismount }) + + g_keyboard.unbindKeyDown('Ctrl+R', PlayerMount.toggleMount, gameRootPanel) + PlayerMount.reset() + + PlayerMount = nil +end + +-- hooked events +function PlayerMount.toggleMount() + if g_game.isMounted() then + g_game.mount(false) + else + g_game.mount(true) + end +end + +function PlayerMount.dismount() + g_game.mount(false) +end \ No newline at end of file diff --git a/modules/game_playermount/playermount.otmod b/modules/game_playermount/playermount.otmod new file mode 100644 index 00000000..a3ff087b --- /dev/null +++ b/modules/game_playermount/playermount.otmod @@ -0,0 +1,15 @@ +Module + name: game_playermount + description: Manage player mounts + author: BeniS + website: www.otclient.info + + dependencies: + - client_entergame + + @onLoad: | + dofile 'playermount' + PlayerMount.init() + + @onUnload: | + PlayerMount.terminate() diff --git a/modules/game_playermount/playermount.otui b/modules/game_playermount/playermount.otui new file mode 100644 index 00000000..e69de29b diff --git a/modules/game_textwindow/textwindow.lua b/modules/game_textwindow/textwindow.lua index c2ff43d9..7c2c93c4 100644 --- a/modules/game_textwindow/textwindow.lua +++ b/modules/game_textwindow/textwindow.lua @@ -5,7 +5,7 @@ local textWindow -- private functions local function onGameEditText(id, itemId, maxLength, text, writter, time) - if(textWindow) then + if textWindow then return end textWindow = g_ui.createWidget('TextWindow', rootWidget) @@ -61,7 +61,7 @@ local function onGameEditText(id, itemId, maxLength, text, writter, time) end local function onGameEditList(id, doorId, text) - if(textWindow) then + if textWindow then return end textWindow = g_ui.createWidget('TextWindow', rootWidget) @@ -105,7 +105,7 @@ function TextWindow.terminate() end function TextWindow.destroy() - if(textWindow) then + if textWindow then textWindow:destroy() textWindow = nil end diff --git a/src/otclient/game.cpp b/src/otclient/game.cpp index 0be8bb58..cb55f016 100644 --- a/src/otclient/game.cpp +++ b/src/otclient/game.cpp @@ -257,7 +257,7 @@ void Game::processCreatureTeleport(const CreaturePtr& creature) g_lua.callGlobalField("g_game", "onCreatureTeleport", creature); } -void Game::processChannelList(const std::vector>& channelList) +void Game::processChannelList(const std::vector >& channelList) { g_lua.callGlobalField("g_game", "onChannelList", channelList); } @@ -324,21 +324,31 @@ void Game::processAutomapFlag(const Position& pos, int icon, const std::string& g_lua.callGlobalField("g_game", "onAutomapFlag", pos, icon, message); } -void Game::processOpenOutfitWindow(const Outfit& currentOufit, const std::vector>& outfitList) +void Game::processOpenOutfitWindow(const Outfit& currentOufit, const std::vector >& outfitList, + const std::vector >& mountList) { - CreaturePtr virtualCreature = CreaturePtr(new Creature); - virtualCreature->setDirection(Otc::South); - virtualCreature->setOutfit(currentOufit); + // create virtual creature outfit + CreaturePtr virtualOutfitCreature = CreaturePtr(new Creature); + virtualOutfitCreature->setDirection(Otc::South); + virtualOutfitCreature->setOutfit(currentOufit); - g_lua.callGlobalField("g_game", "onOpenOutfitWindow", virtualCreature, outfitList); + // creature virtual mount outfit + CreaturePtr virtualMountCreature = CreaturePtr(new Creature); + virtualMountCreature->setDirection(Otc::South); + + Outfit mountOutfit; + mountOutfit.setId(currentOufit.getMount()); + virtualMountCreature->setOutfit(mountOutfit); + + g_lua.callGlobalField("g_game", "onOpenOutfitWindow", virtualOutfitCreature, outfitList, virtualMountCreature, mountList); } -void Game::processOpenNpcTrade(const std::vector>& items) +void Game::processOpenNpcTrade(const std::vector >& items) { g_lua.callGlobalField("g_game", "onOpenNpcTrade", items); } -void Game::processPlayerGoods(int money, const std::vector>& goods) +void Game::processPlayerGoods(int money, const std::vector >& goods) { g_lua.callGlobalField("g_game", "onPlayerGoods", money, goods); } @@ -373,12 +383,12 @@ void Game::processEditList(uint id, int doorId, const std::string& text) g_lua.callGlobalField("g_game", "onEditList", id, doorId, text); } -void Game::processQuestLog(const std::vector>& questList) +void Game::processQuestLog(const std::vector >& questList) { g_lua.callGlobalField("g_game", "onQuestLog", questList); } -void Game::processQuestLine(int questId, const std::vector>& questMissions) +void Game::processQuestLine(int questId, const std::vector >& questMissions) { g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions); } @@ -1044,7 +1054,7 @@ void Game::mount(bool mount) { if(!canPerformGameAction()) return; - m_protocolGame->sendMount(mount); + m_protocolGame->sendMounted(mount); } bool Game::checkBotProtection() diff --git a/src/otclient/game.h b/src/otclient/game.h index b8c90175..3f00c8df 100644 --- a/src/otclient/game.h +++ b/src/otclient/game.h @@ -71,7 +71,7 @@ protected: void processContainerRemoveItem(int containerId, int slot); // channel related - void processChannelList(const std::vector>& channelList); + void processChannelList(const std::vector >& channelList); void processOpenChannel(int channelId, const std::string& name); void processOpenPrivateChannel(const std::string& name); void processOpenOwnPrivateChannel(int channelId, const std::string& name); @@ -92,11 +92,12 @@ protected: void processAutomapFlag(const Position& pos, int icon, const std::string& message); // outfit - void processOpenOutfitWindow(const Outfit& currentOufit, const std::vector>& outfitList); + void processOpenOutfitWindow(const Outfit& currentOufit, const std::vector >& outfitList, + const std::vector >& mountList); // npc trade - void processOpenNpcTrade(const std::vector>& items); - void processPlayerGoods(int money, const std::vector>& goods); + void processOpenNpcTrade(const std::vector >& items); + void processPlayerGoods(int money, const std::vector >& goods); void processCloseNpcTrade(); // player trade @@ -109,8 +110,8 @@ protected: void processEditList(uint id, int doorId, const std::string& text); // questlog - void processQuestLog(const std::vector>& questList); - void processQuestLine(int questId, const std::vector>& questMissions); + void processQuestLog(const std::vector >& questList); + void processQuestLine(int questId, const std::vector >& questMissions); friend class ProtocolGame; friend class Map; @@ -245,6 +246,7 @@ public: bool isDead() { return m_dead; } bool isAttacking() { return !!m_attackingCreature; } bool isFollowing() { return !!m_followingCreature; } + bool isMounted() { return m_mounted; } ContainerPtr getContainer(int index) { return m_containers[index]; } std::map getContainers() { return m_containers; } @@ -276,6 +278,7 @@ private: bool m_denyBotCall; bool m_dead; + bool m_mounted; int m_serverBeat; Otc::FightModes m_fightMode; Otc::ChaseModes m_chaseMode; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 2df9dd06..5da82d68 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -177,6 +177,7 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "isDead", &Game::isDead, &g_game); g_lua.bindSingletonFunction("g_game", "isAttacking", &Game::isAttacking, &g_game); g_lua.bindSingletonFunction("g_game", "isFollowing", &Game::isFollowing, &g_game); + g_lua.bindSingletonFunction("g_game", "isMounted", &Game::isMounted, &g_game); g_lua.bindSingletonFunction("g_game", "getContainer", &Game::getContainer, &g_game); g_lua.bindSingletonFunction("g_game", "getContainers", &Game::getContainers, &g_game); g_lua.bindSingletonFunction("g_game", "getVips", &Game::getVips, &g_game); diff --git a/src/otclient/luavaluecasts.cpp b/src/otclient/luavaluecasts.cpp index 6bf8a6fa..ef4052a7 100644 --- a/src/otclient/luavaluecasts.cpp +++ b/src/otclient/luavaluecasts.cpp @@ -38,6 +38,10 @@ int push_luavalue(const Outfit& outfit) g_lua.setField("legs"); g_lua.pushInteger(outfit.getFeet()); g_lua.setField("feet"); + if(g_game.getFeature(Otc::GamePlayerMounts)) { + g_lua.pushInteger(outfit.getMount()); + g_lua.setField("mount"); + } return 1; } @@ -56,6 +60,10 @@ bool luavalue_cast(int index, Outfit& outfit) outfit.setLegs(g_lua.popInteger()); g_lua.getField("feet", index); outfit.setFeet(g_lua.popInteger()); + if(g_game.getFeature(Otc::GamePlayerMounts)) { + g_lua.getField("mount", index); + outfit.setMount(g_lua.popInteger()); + } return true; } return false; diff --git a/src/otclient/luavaluecasts.h b/src/otclient/luavaluecasts.h index 5b42e091..fc9fce66 100644 --- a/src/otclient/luavaluecasts.h +++ b/src/otclient/luavaluecasts.h @@ -25,6 +25,7 @@ #include "global.h" #include +#include "game.h" #include "outfit.h" // outfit diff --git a/src/otclient/outfit.h b/src/otclient/outfit.h index 70caf8c9..20f84150 100644 --- a/src/otclient/outfit.h +++ b/src/otclient/outfit.h @@ -44,6 +44,7 @@ public: void setLegs(int legs) { m_legs = legs; m_legsColor = getColor(legs); } void setFeet(int feet) { m_feet = feet; m_feetColor = getColor(feet); } void setAddons(int addons) { m_addons = addons; } + void setMount(int mount) { m_mount = mount; } void setCategory(DatCategory category) { m_category = category; } void resetClothes(); @@ -54,6 +55,7 @@ public: int getLegs() const { return m_legs; } int getFeet() const { return m_feet; } int getAddons() const { return m_addons; } + int getMount() const { return m_mount; } DatCategory getCategory() const { return m_category; } Color getHeadColor() const { return m_headColor; } @@ -63,7 +65,7 @@ public: private: DatCategory m_category; - int m_id, m_head, m_body, m_legs, m_feet, m_addons; + int m_id, m_head, m_body, m_legs, m_feet, m_addons, m_mount; Color m_headColor, m_bodyColor, m_legsColor, m_feetColor; }; diff --git a/src/otclient/protocolcodes.h b/src/otclient/protocolcodes.h index 86f3ee05..b30c274d 100644 --- a/src/otclient/protocolcodes.h +++ b/src/otclient/protocolcodes.h @@ -57,7 +57,7 @@ namespace Proto { OsFlash = 3, OsOtclientLinux = 10, OsOtclientWindows = 11, - OsOtclientMac = 12, + OsOtclientMac = 12 }; #ifdef OSTYPE @@ -177,7 +177,7 @@ namespace Proto { GameServerMarketEnter = 246, // 944 GameServerMarketLeave = 247, // 944 GameServerMarketDetail = 248, // 944 - GameServerMarketBrowse = 249, // 944 + GameServerMarketBrowse = 249 // 944 }; enum ClientOpcodes { @@ -267,7 +267,7 @@ namespace Proto { ClientMarketBrowse = 245, // 944 ClientMarketCreate = 246, // 944 ClientMarketCancel = 247, // 944 - ClientMarketAccept = 248, // 944 + ClientMarketAccept = 248 // 944 }; enum ServerSpeakType { diff --git a/src/otclient/protocolgame.h b/src/otclient/protocolgame.h index c8372d00..8229277f 100644 --- a/src/otclient/protocolgame.h +++ b/src/otclient/protocolgame.h @@ -102,7 +102,7 @@ protected: void sendRefreshContainer(); void sendRequestOutfit(); void sendChangeOutfit(const Outfit& outfit); - void sendMount(bool mount); + void sendMountStatus(bool mount); void sendAddVip(const std::string& name); void sendRemoveVip(uint playerId); void sendBugReport(const std::string& comment); diff --git a/src/otclient/protocolgameparse.cpp b/src/otclient/protocolgameparse.cpp index c8e27e9d..92fe2a08 100644 --- a/src/otclient/protocolgameparse.cpp +++ b/src/otclient/protocolgameparse.cpp @@ -920,7 +920,6 @@ void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg) g_game.processAttackCancel(); } - void ProtocolGame::parseSpellDelay(const InputMessagePtr& msg) { msg->getU16(); // spell id @@ -935,7 +934,6 @@ void ProtocolGame::parseSpellGroupDelay(const InputMessagePtr& msg) msg->getU8(); // unknown } - void ProtocolGame::parseMultiUseDelay(const InputMessagePtr& msg) { //TODO @@ -991,7 +989,7 @@ void ProtocolGame::parseCreatureSpeak(const InputMessagePtr& msg) void ProtocolGame::parseChannelList(const InputMessagePtr& msg) { int count = msg->getU8(); - std::vector> channelList; + std::vector > channelList; for(int i = 0; i < count; i++) { int id = msg->getU16(); std::string name = msg->getString(); @@ -1130,7 +1128,8 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg) { Outfit currentOutfit = getOutfit(msg); - std::vector> outfitList; + std::vector > outfitList; + std::vector > mountList; int outfitCount = msg->getU8(); for(int i = 0; i < outfitCount; i++) { int outfitId = msg->getU16(); @@ -1142,13 +1141,15 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg) if(g_game.getFeature(Otc::GamePlayerMounts)) { int mountCount = msg->getU8(); - for(int i=0;igetU16(); // mount type - msg->getString(); // mount name + for(int i = 0; i < mountCount; ++i) { + int mountId = msg->getU16(); // mount type + std::string mountName = msg->getString(); // mount name + + mountList.push_back(std::make_tuple(mountId, mountName)); } } - g_game.processOpenOutfitWindow(currentOutfit, outfitList); + g_game.processOpenOutfitWindow(currentOutfit, outfitList, mountList); } void ProtocolGame::parseVipAdd(const InputMessagePtr& msg) @@ -1188,7 +1189,7 @@ void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg) void ProtocolGame::parseQuestLog(const InputMessagePtr& msg) { - std::vector> questList; + std::vector > questList; int questsCount = msg->getU16(); for(int i = 0; i < questsCount; i++) { int id = msg->getU16(); @@ -1344,8 +1345,10 @@ Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg) } } - if(g_game.getFeature(Otc::GamePlayerMounts)) - msg->getU16(); // mount + if(g_game.getFeature(Otc::GamePlayerMounts)) { + int mount = msg->getU16(); // mount + outfit.setMount(mount); + } return outfit; } diff --git a/src/otclient/protocolgamesend.cpp b/src/otclient/protocolgamesend.cpp index dc5b5a70..45beebeb 100644 --- a/src/otclient/protocolgamesend.cpp +++ b/src/otclient/protocolgamesend.cpp @@ -630,15 +630,21 @@ void ProtocolGame::sendChangeOutfit(const Outfit& outfit) msg->addU8(outfit.getLegs()); msg->addU8(outfit.getFeet()); msg->addU8(outfit.getAddons()); + if(g_game.getFeature(Otc::GamePlayerMounts)) + msg->addU16(outfit.getMount()); send(msg); } -void ProtocolGame::sendMount(bool mount) +void ProtocolGame::sendMountStatus(bool mount) { - OutputMessagePtr msg(new OutputMessage); - msg->addU8(Proto::ClientMount); - msg->addU8(mount); - send(msg); + if(g_game.getFeature(Otc::GamePlayerMounts)) { + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientMount); + msg->addU8(mount); + send(msg); + } else { + g_logger.error("ProtocolGame::sendMountStatus does not support the current protocol."); + } } void ProtocolGame::sendAddVip(const std::string& name) diff --git a/src/otclient/uimap.cpp b/src/otclient/uimap.cpp index f2efde01..48598f63 100644 --- a/src/otclient/uimap.cpp +++ b/src/otclient/uimap.cpp @@ -120,7 +120,7 @@ TilePtr UIMap::getTile(const Point& mousePos) { /* * Known Issue: If you move a container widget into the map rect - * if you move an item onto itself it will allow this to execute + * and you move an item onto itself it will allow this to execute * still dropping the item on the ground. */ if(!m_mapRect.contains(mousePos))