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 00000000..c808639a Binary files /dev/null and b/modules/client_skins/skins/default/images/arrow_down.png differ 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 00000000..87e99664 Binary files /dev/null and b/modules/client_skins/skins/default/images/arrow_left.png differ 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 00000000..e8f6b430 Binary files /dev/null and b/modules/client_skins/skins/default/images/arrow_right.png differ diff --git a/modules/client_skins/skins/default/images/arrow_up.png b/modules/client_skins/skins/default/images/arrow_up.png new file mode 100644 index 00000000..8fef8c79 Binary files /dev/null and b/modules/client_skins/skins/default/images/arrow_up.png differ diff --git a/modules/client_skins/skins/default/images/vertical_separator.png b/modules/client_skins/skins/default/images/vertical_separator.png new file mode 100644 index 00000000..85238b53 Binary files /dev/null and b/modules/client_skins/skins/default/images/vertical_separator.png differ diff --git a/modules/client_skins/skins/default/styles/buttons.otui b/modules/client_skins/skins/default/styles/buttons.otui index ec6fe756..51a5a8aa 100644 --- a/modules/client_skins/skins/default/styles/buttons.otui +++ b/modules/client_skins/skins/default/styles/buttons.otui @@ -38,4 +38,4 @@ TabButton < UIButton $on: image-clip: 0 40 20 20 - color: #80c7f8 \ No newline at end of file + color: #80c7f8 diff --git a/modules/client_skins/skins/default/styles/separators.otui b/modules/client_skins/skins/default/styles/separators.otui index 0e8132c9..c86d309f 100644 --- a/modules/client_skins/skins/default/styles/separators.otui +++ b/modules/client_skins/skins/default/styles/separators.otui @@ -6,7 +6,7 @@ HorizontalSeparator < UIWidget focusable: false VerticalSeparator < UIWidget - image-source: /images/horizontal_separator.png + image-source: /images/vertical_separator.png image-border-left: 2 width: 2 phantom: true diff --git a/modules/corelib/mouse.lua b/modules/corelib/mouse.lua index 0d3848dc..12ea4589 100644 --- a/modules/corelib/mouse.lua +++ b/modules/corelib/mouse.lua @@ -35,7 +35,7 @@ end function g_mouse.bindAutoPress(widget, callback, delay, button) local button = button or MouseLeftButton connect(widget, { onMousePress = function(widget, mousePos, mouseButton) - if(mouseButton ~= button) then + if mouseButton ~= button then return false end local startTime = g_clock.millis() diff --git a/modules/game/game.otmod b/modules/game/game.otmod index 5e556f35..365aad19 100644 --- a/modules/game/game.otmod +++ b/modules/game/game.otmod @@ -31,6 +31,7 @@ Module - game_bugreport - game_shaders - game_playerdeath + - game_playermount @onLoad: | dofile 'const' diff --git a/modules/game_battle/battle.lua b/modules/game_battle/battle.lua index 225eb859..2bcd68d1 100644 --- a/modules/game_battle/battle.lua +++ b/modules/game_battle/battle.lua @@ -84,10 +84,10 @@ function Battle.terminate() mouseWidget:destroy() mouseWidget = nil - disconnect(Creature, { onSkullChange = Battle.checkCreatureSkull, + disconnect(Creature, { onSkullChange = Battle.checkCreatureSkull, onEmblemChange = Battle.checkCreatureEmblem } ) - disconnect(g_game, { onAttackingCreatureChange = Battle.onAttack } ) + disconnect(g_game, { onAttackingCreatureChange = Battle.onAttack } ) Battle = nil end @@ -191,7 +191,7 @@ function Battle.addCreature(creature) local creatureId = creature:getId() if battleButtonsByCreaturesList[creatureId] == nil then - local battleButton = g_ui.loadUI('battleButton.otui', battlePanel) + local battleButton = g_ui.loadUI('battlebutton.otui', battlePanel) local creatureWidget = battleButton:getChildById('creature') local labelWidget = battleButton:getChildById('label') local lifeBarWidget = battleButton:getChildById('lifeBar') diff --git a/modules/game_battle/battle.otui b/modules/game_battle/battle.otui index aeaac4fa..60f5b1ab 100644 --- a/modules/game_battle/battle.otui +++ b/modules/game_battle/battle.otui @@ -22,19 +22,19 @@ BattleIcon < UICheckBox image-color: #ffffff88 BattlePlayers < BattleIcon - image-source: /game_battle/battle_players.png + image-source: /game_battle/images/battle_players.png BattleNPCs < BattleIcon - image-source: /game_battle/battle_npcs.png + image-source: /game_battle/images/battle_npcs.png BattleMonsters < BattleIcon - image-source: /game_battle/battle_monsters.png + image-source: /game_battle/images/battle_monsters.png BattleSkulls < BattleIcon - image-source: /game_battle/battle_skulls.png + image-source: /game_battle/images/battle_skulls.png BattleParty < BattleIcon - image-source: /game_battle/battle_party.png + image-source: /game_battle/images/battle_party.png MiniWindow id: battleWindow diff --git a/modules/game_battle/battle_monsters.png b/modules/game_battle/images/battle_monsters.png similarity index 100% rename from modules/game_battle/battle_monsters.png rename to modules/game_battle/images/battle_monsters.png diff --git a/modules/game_battle/battle_npcs.png b/modules/game_battle/images/battle_npcs.png similarity index 100% rename from modules/game_battle/battle_npcs.png rename to modules/game_battle/images/battle_npcs.png diff --git a/modules/game_battle/battle_party.png b/modules/game_battle/images/battle_party.png similarity index 100% rename from modules/game_battle/battle_party.png rename to modules/game_battle/images/battle_party.png diff --git a/modules/game_battle/battle_players.png b/modules/game_battle/images/battle_players.png similarity index 100% rename from modules/game_battle/battle_players.png rename to modules/game_battle/images/battle_players.png diff --git a/modules/game_battle/battle_skulls.png b/modules/game_battle/images/battle_skulls.png similarity index 100% rename from modules/game_battle/battle_skulls.png rename to modules/game_battle/images/battle_skulls.png diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index 8bcd501d..b640482e 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -117,15 +117,15 @@ function GameInterface.show() end function GameInterface.hide() - if(logoutWindow) then + if logoutWindow then logoutWindow:destroy() logoutWindow = nil end - if(exitWindow) then + if exitWindow then exitWindow:destroy() exitWindow = nil end - if(countWindow) then + if countWindow then countWindow:destroy() countWindow = nil end @@ -144,7 +144,7 @@ function GameInterface.exit() end function GameInterface.tryExit() - if(exitWindow) then + if exitWindow then return true end exitWindow = g_ui.createWidget('ExitWindow', rootWidget) @@ -183,7 +183,7 @@ function GameInterface.logout() end function GameInterface.tryLogout() - if(logoutWindow) then + if logoutWindow then return end logoutWindow = g_ui.createWidget('LogoutWindow', rootWidget) diff --git a/modules/game_minimap/minimap.lua b/modules/game_minimap/minimap.lua index 3998c8ee..012bbdd1 100644 --- a/modules/game_minimap/minimap.lua +++ b/modules/game_minimap/minimap.lua @@ -1,5 +1,8 @@ Minimap = {} +-- public variables +minimapFirstLoad = true + -- private variables local minimapWidget local minimapButton @@ -8,7 +11,6 @@ local DEFAULT_ZOOM = 60 local MAX_FLOOR_UP = 0 local MAX_FLOOR_DOWN = 15 local navigating = false -minimapFirstLoad = true -- private functions function onMinimapMouseRelease(self, mousePosition, mouseButton) @@ -54,9 +56,9 @@ function Minimap.init() minimapWindow = g_ui.loadUI('minimap.otui', GameInterface.getRightPanel()) - minimapWidget = minimapWindow:recursiveGetChildById('minimap') g_mouse.bindAutoPress(minimapWidget, Minimap.compassClick, nil, MouseRightButton) + g_mouse.bindAutoPress(minimapWidget, Minimap.compassClick, nil, MouseLeftButton) minimapWidget:setAutoViewMode(false) minimapWidget:setViewMode(1) -- mid view minimapWidget:setDrawMinimapColors(true) @@ -150,13 +152,13 @@ function Minimap.onButtonClick(id) elseif id == "floorUp" then local pos = minimapWidget:getCameraPosition() pos.z = pos.z - 1 - if(pos.z > 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))