diff --git a/layouts/retro/styles/10-comboboxes.otui b/layouts/retro/styles/10-comboboxes.otui index e1d4168..a94cbce 100644 --- a/layouts/retro/styles/10-comboboxes.otui +++ b/layouts/retro/styles/10-comboboxes.otui @@ -23,7 +23,7 @@ ComboBoxPopupMenuButton < UIButton height: 23 font: verdana-11px-antialised text-align: left - text-offset: 4 0 + text-offset: 5 2 color: #dfdfdf background-color: alpha margin: 1 @@ -44,7 +44,7 @@ ComboBox < UIComboBox font: verdana-11px-antialised color: #dfdfdf size: 91 23 - text-offset: 3 0 + text-offset: 5 2 text-align: left image-source: /images/ui/combobox_square image-border: 3 @@ -65,7 +65,7 @@ ComboBoxRoundedPopupScrollMenuButton < UIButton height: 23 font: verdana-11px-antialised text-align: left - text-offset: 4 0 + text-offset: 5 2 color: #dfdfdf background-color: alpha @@ -85,7 +85,7 @@ ComboBoxRoundedPopupMenuButton < UIButton height: 23 font: verdana-11px-antialised text-align: left - text-offset: 4 0 + text-offset: 5 2 color: #dfdfdf background-color: alpha diff --git a/layouts/retro/styles/10-windows.otui b/layouts/retro/styles/10-windows.otui index 0e47f3a..9d05389 100644 --- a/layouts/retro/styles/10-windows.otui +++ b/layouts/retro/styles/10-windows.otui @@ -2,7 +2,7 @@ Window < UIWindow font: verdana-11px-antialised size: 236 207 opacity: 1 - color: #8F8F8F + color: #AFAFAF text-offset: 0 2 text-align: top image-source: /images/ui/window diff --git a/layouts/retro/styles/30-miniwindow.otui b/layouts/retro/styles/30-miniwindow.otui index dc30804..3742701 100644 --- a/layouts/retro/styles/30-miniwindow.otui +++ b/layouts/retro/styles/30-miniwindow.otui @@ -2,7 +2,7 @@ MiniWindow < UIMiniWindow font: verdana-11px-antialised icon-rect: 4 2 13 13 icon-clip: 0 0 20 20 - color: #8F8F8F + color: #9F9F9F width: 190 height: 200 text-offset: 24 2 diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 72d75dc..bb5af60 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -392,6 +392,7 @@ function EnterGame.doLogin() g_game.setClientVersion(G.clientVersion) g_game.setProtocolVersion(g_game.getClientProtocolVersion(G.clientVersion)) g_game.setCustomProtocolVersion(0) + g_game.setCustomOs(-1) -- disable g_game.chooseRsa(G.host) if #server_params <= 3 and not g_game.getFeature(GameExtendedOpcode) then g_game.setCustomOs(2) -- set os to windows if opcodes are disabled diff --git a/modules/game_battle/battlebutton.otui b/modules/game_battle/battlebutton.otui index 193485f..508db25 100644 --- a/modules/game_battle/battlebutton.otui +++ b/modules/game_battle/battlebutton.otui @@ -1,2 +1,3 @@ BattleButton < CreatureButton - &isBattleButton: true \ No newline at end of file + &isBattleButton: true + optimized: true \ No newline at end of file diff --git a/modules/game_bot/bot.lua b/modules/game_bot/bot.lua index 357672d..415d56d 100644 --- a/modules/game_bot/bot.lua +++ b/modules/game_bot/bot.lua @@ -366,7 +366,8 @@ function initCallbacks() onAppear = botCreatureAppear, onDisappear = botCreatureDisappear, onPositionChange = botCreaturePositionChange, - onHealthPercentChange = botCraetureHealthPercentChange + onHealthPercentChange = botCraetureHealthPercentChange, + onTurn = botCreatureTurn }) connect(LocalPlayer, { @@ -414,7 +415,8 @@ function terminateCallbacks() onAppear = botCreatureAppear, onDisappear = botCreatureDisappear, onPositionChange = botCreaturePositionChange, - onHealthPercentChange = botCraetureHealthPercentChange + onHealthPercentChange = botCraetureHealthPercentChange, + onTurn = botCreatureTurn }) disconnect(LocalPlayer, { @@ -559,3 +561,8 @@ function botChannelEvent(channelId, name, event) if botExecutor == nil then return false end safeBotCall(function() botExecutor.callbacks.onChannelEvent(channelId, name, event) end) end + +function botCreatureTurn(creature, direction) + if botExecutor == nil then return false end + safeBotCall(function() botExecutor.callbacks.onTurn(creature, direction) end) +end \ No newline at end of file diff --git a/modules/game_bot/executor.lua b/modules/game_bot/executor.lua index 733e8c4..7492f14 100644 --- a/modules/game_bot/executor.lua +++ b/modules/game_bot/executor.lua @@ -59,7 +59,8 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo onChannelList = {}, onOpenChannel = {}, onCloseChannel = {}, - onChannelEvent = {} + onChannelEvent = {}, + onTurn = {} } -- basic functions & classes @@ -311,6 +312,11 @@ function executeBot(config, storage, tabs, msgCallback, saveConfigCallback, relo callback(channelId, name, event) end end, + onTurn = function(creature, direction) + for i, callback in ipairs(context._callbacks.onTurn) do + callback(creature, direction) + end + end, } } end \ No newline at end of file diff --git a/modules/game_bot/functions/callbacks.lua b/modules/game_bot/functions/callbacks.lua index 3ab5420..846d445 100644 --- a/modules/game_bot/functions/callbacks.lua +++ b/modules/game_bot/functions/callbacks.lua @@ -146,6 +146,10 @@ context.onChannelEvent = function(callback) return context.callback("onChannelEvent", callback) end +-- onTurn -- callback = function(creature, direction) +context.onTurn = function(callback) + return context.callback("onTurn", callback) +end -- CUSTOM CALLBACKS diff --git a/modules/game_bot/functions/config.lua b/modules/game_bot/functions/config.lua index f277ef6..2775dc7 100644 --- a/modules/game_bot/functions/config.lua +++ b/modules/game_bot/functions/config.lua @@ -166,7 +166,7 @@ Config.setup = function(dir, widget, configExtension, callback) end widget.add.onClick = function() - context.UI.SinglelineEditorWindow("config_name", function(name) + context.UI.SinglelineEditorWindow("config_name", {title="Enter config name"}, function(name) name = name:gsub("%s+", "_") if name:len() == 0 or name:len() >= 30 or name:find("/") or name:find("\\") then return context.error("Invalid config name") @@ -185,8 +185,7 @@ Config.setup = function(dir, widget, configExtension, callback) widget.edit.onClick = function() local name = context.storage._configs[dir].selected if not name then return end - context.UI.MultilineEditorWindow("Config editor - " .. name .. " in " .. dir, - Config.loadRaw(dir, name), function(newValue) + context.UI.MultilineEditorWindow(Config.loadRaw(dir, name), {title="Config editor - " .. name .. " in " .. dir}, function(newValue) local data = Config.parse(newValue) Config.save(dir, name, data, configExtension) refresh() diff --git a/modules/game_bot/functions/ui_windows.lua b/modules/game_bot/functions/ui_windows.lua index 04c9f8e..4795f4b 100644 --- a/modules/game_bot/functions/ui_windows.lua +++ b/modules/game_bot/functions/ui_windows.lua @@ -4,12 +4,31 @@ if type(context.UI) ~= "table" then end local UI = context.UI -UI.SinglelineEditorWindow = function(text, callback) - return modules.game_textedit.singlelineEditor(text, callback) +UI.EditorWindow = function(text, options, callback) + --[[ + Available options: + title = text + description = text + multiline = true / false + width = number + validation = text (regex) + examples = {{name, text}, {name, text}} + ]]-- + local window = modules.game_textedit.edit(text, options, callback) + window.botWidget = true + return window end -UI.MultilineEditorWindow = function(description, test, callback) - return modules.game_textedit.multilineEditor(description, test, callback) +UI.SinglelineEditorWindow = function(text, options, callback) + options = options or {} + options.multiline = false + return UI.EditorWindow(text, options, callback) +end + +UI.MultilineEditorWindow = function(text, options, callback) + options = options or {} + options.multiline = true + return UI.EditorWindow(text, options, callback) end UI.ConfirmationWindow = function(title, question, callback) diff --git a/modules/game_bot/ui/config.otui b/modules/game_bot/ui/config.otui index fc332a9..ab7fdca 100644 --- a/modules/game_bot/ui/config.otui +++ b/modules/game_bot/ui/config.otui @@ -29,7 +29,7 @@ BotConfig < Panel anchors.top: prev.bottom anchors.left: parent.left text: Add - width: 59 + width: 56 height: 20 Button @@ -37,7 +37,7 @@ BotConfig < Panel anchors.top: prev.top anchors.horizontalCenter: parent.horizontalCenter text: Edit - width: 59 + width: 56 height: 20 Button @@ -45,5 +45,5 @@ BotConfig < Panel anchors.top: prev.top anchors.right: parent.right text: Remove - width: 59 + width: 56 height: 20 \ No newline at end of file diff --git a/modules/game_bot/ui/icons.otui b/modules/game_bot/ui/icons.otui index 5de4524..d7e9954 100644 --- a/modules/game_bot/ui/icons.otui +++ b/modules/game_bot/ui/icons.otui @@ -22,6 +22,7 @@ BotIcon < UIWidget margin-top: 0 size: 48 48 phantom: true + optimized: true UIWidget id: status diff --git a/modules/game_market/market.lua b/modules/game_market/market.lua index eef86e9..ff9d7b5 100644 --- a/modules/game_market/market.lua +++ b/modules/game_market/market.lua @@ -78,6 +78,7 @@ currentItems = {} lastCreatedOffer = 0 fee = 0 averagePrice = 0 +tibiaCoins = 0 loaded = false @@ -198,8 +199,8 @@ local function addOffer(offer, offerType) if offer.var == MarketRequest.MyOffers then row = buyMyOfferTable:addRow({ {text = itemName}, - {text = price*amount}, - {text = price}, + {text = comma_value(price*amount), sortvalue = price*amount}, + {text = comma_value(price), sortvalue = price}, {text = amount}, {text = string.gsub(os.date('%c', timestamp), " ", " "), sortvalue = timestamp} }) @@ -207,8 +208,8 @@ local function addOffer(offer, offerType) row = buyOfferTable:addRow({ {text = player}, {text = amount}, - {text = price*amount}, - {text = price}, + {text = comma_value(price*amount), sortvalue = price*amount}, + {text = comma_value(price), sortvalue = price}, {text = string.gsub(os.date('%c', timestamp), " ", " ")} }) end @@ -227,8 +228,8 @@ local function addOffer(offer, offerType) if offer.var == MarketRequest.MyOffers then row = sellMyOfferTable:addRow({ {text = itemName}, - {text = price*amount}, - {text = price}, + {text = comma_value(price*amount), sortvalue = price*amount}, + {text = comma_value(price), sortvalue = price}, {text = amount}, {text = string.gsub(os.date('%c', timestamp), " ", " "), sortvalue = timestamp} }) @@ -236,8 +237,8 @@ local function addOffer(offer, offerType) row = sellOfferTable:addRow({ {text = player}, {text = amount}, - {text = price*amount}, - {text = price}, + {text = comma_value(price*amount), sortvalue = price*amount}, + {text = comma_value(price), sortvalue = price}, {text = string.gsub(os.date('%c', timestamp), " ", " "), sortvalue = timestamp} }) end @@ -462,7 +463,7 @@ local function updateBalance(balance) if balance < 0 then balance = 0 end information.balance = balance - balanceLabel:setText('Balance: '..balance..' gold') + balanceLabel:setText('Balance: '.. comma_value(balance) ..' gold') balanceLabel:resizeToText() end @@ -473,7 +474,7 @@ local function updateFee(price, amount) elseif fee > 1000 then fee = 1000 end - feeLabel:setText('Fee: '..fee) + feeLabel:setText('Fee: '.. comma_value(fee)) feeLabel:resizeToText() end @@ -521,11 +522,11 @@ local function openAmountWindow(callback, actionType, actionText) itembox:setItemId(item:getId()) local scrollbar = amountWindow:getChildById('amountScrollBar') - scrollbar:setText(offer:getPrice()..'gp') + scrollbar:setText(comma_value(offer:getPrice()) ..'gp') scrollbar.onValueChange = function(widget, value) - widget:setText((value*offer:getPrice())..'gp') - itembox:setText(value) + widget:setText(comma_value(value*offer:getPrice())..'gp') + itembox:setText(comma_value(value)) end scrollbar:setRange(1, maximum) scrollbar:setValue(1) @@ -743,7 +744,7 @@ local function initInterface() -- setup 'Market Offer' section tabs marketOffersPanel = g_ui.loadUI('ui/marketoffers') mainTabBar:addTab(tr('Market Offers'), marketOffersPanel) - + selectionTabBar = marketOffersPanel:getChildById('leftTabBar') selectionTabBar:setContentWidget(marketOffersPanel:getChildById('leftTabContent')) @@ -770,7 +771,7 @@ local function initInterface() -- setup 'My Offer' section tabs myOffersPanel = g_ui.loadUI('ui/myoffers') - mainTabBar:addTab(tr('My Offers'), myOffersPanel) + local myOffersTab = mainTabBar:addTab(tr('My Offers'), myOffersPanel) offersTabBar = myOffersPanel:getChildById('offersTabBar') offersTabBar:setContentWidget(myOffersPanel:getChildById('offersTabContent')) @@ -783,6 +784,12 @@ local function initInterface() balanceLabel = marketWindow:getChildById('balanceLabel') + mainTabBar.onTabChange = function(widget, tab) + if tab == myOffersTab then + Market.refreshMyOffers() + end + end + -- setup offers buyButton = itemOffersPanel:getChildById('buyButton') buyButton.onClick = function() openAmountWindow(Market.acceptMarketOffer, MarketAction.Buy, 'Buy') end @@ -889,6 +896,8 @@ function init() connect(g_game, { onGameEnd = Market.reset }) connect(g_game, { onGameEnd = Market.close }) connect(g_game, { onGameStart = Market.updateCategories }) + connect(g_game, { onCoinBalance = Market.onCoinBalance }) + marketWindow = g_ui.createWidget('MarketWindow', rootWidget) marketWindow:hide() @@ -904,6 +913,7 @@ function terminate() disconnect(g_game, { onGameEnd = Market.reset }) disconnect(g_game, { onGameEnd = Market.close }) disconnect(g_game, { onGameStart = Market.updateCategories }) + disconnect(g_game, { onCoinBalance = Market.onCoinBalance }) destroyAmountWindow() marketWindow:destroy() @@ -1076,7 +1086,7 @@ function Market.refreshItemsWidget(selectItem) local amount = Market.getDepotCount(item.marketData.tradeAs) if amount > 0 then - itemWidget:setText(amount) + itemWidget:setText(comma_value(amount)) itemBox:setTooltip('You have '.. amount ..' in your depot.') end @@ -1116,7 +1126,7 @@ function Market.loadMarketItems(category) end end - if not marketItems[category] then + if not marketItems[category] and category ~= MarketCategory.All then return end @@ -1253,6 +1263,11 @@ function Market.onMarketEnter(depotItems, offers, balance, vocation) -- set list of depot items information.depotItems = depotItems + for i = 1, #marketItems[MarketCategory.TibiaCoins] do + local item = marketItems[MarketCategory.TibiaCoins][i].displayItem + depotItems[item:getId()] = tibiaCoins + end + -- update the items widget to match depot items if Market.isItemSelected() then local spriteId = selectedItem.item.marketData.tradeAs @@ -1284,3 +1299,12 @@ end function Market.onMarketBrowse(offers) updateOffers(offers) end + +function Market.onCoinBalance(coins, transferableCoins) + tibiaCoins = coins + if not marketItems[MarketCategory.TibiaCoins] then return end + for i = 1, #marketItems[MarketCategory.TibiaCoins] do + local item = marketItems[MarketCategory.TibiaCoins][i].displayItem + depotItems[item:getId()] = tibiaCoins + end +end diff --git a/modules/game_textedit/textedit.lua b/modules/game_textedit/textedit.lua index b17e664..7e8cc25 100644 --- a/modules/game_textedit/textedit.lua +++ b/modules/game_textedit/textedit.lua @@ -19,96 +19,135 @@ function destroyWindow() end end -function show(widget) - if not widget then - return +-- also works as show(text, callback) +function show(text, options, callback) -- callback = function(newText) + --[[ + Available options: + title = text + description = text + multiline = true / false + width = number + validation = text (regex) + examples = {{name, text}, {name, text}} + ]]-- + if type(text) == 'userdata' then + local widget = text + callback = function(newText) + widget:setText(newText) + end + text = widget:getText() + elseif type(text) == 'number' then + text = tostring(text) + elseif type(text) == 'nil' then + text = '' + elseif type(text) ~= 'string' then + return error("Invalid text type for game_textedit: " .. type(text)) end + if type(options) == 'function' then + local tmp = callback + callback = options + options = callback + end + options = options or {} + if activeWindow then destroyWindow() end - local window = g_ui.createWidget('TextEditWindow', rootWidget) - + + local window + if options.multiline then + window = g_ui.createWidget('MultilineTextEditWindow', rootWidget) + window.text = window.textPanel.text + else + window = g_ui.createWidget('SinglelineTextEditWindow', rootWidget) + end + -- functions + local validate = function(text) + if type(options.validation) ~= 'string' or options.validation:len() == 0 then + return true + end + return #regexMatch(text, options.validation) == 1 + end local destroy = function() window:destroy() - if window == activeWindow then - activeWindow = nil - end end local doneFunc = function() - widget:setText(window.text:getText()) + local text = window.text:getText() + if not validate(text) then return end destroy() + if callback then + callback(text) + end + end + + window.buttons.ok.onClick = doneFunc + window.buttons.cancel.onClick = destroy + if not options.multiline then + window.onEnter = doneFunc end - - window.okButton.onClick = doneFunc - window.cancelButton.onClick = destroy - window.onEnter = doneFunc window.onEscape = destroy - - window.text:setText(widget:getText()) - - activeWindow = window - activeWindow:raise() - activeWindow:focus() -end - -function singlelineEditor(text, callback) - if activeWindow then - destroyWindow() - end - local window = g_ui.createWidget('TextEditWindow', rootWidget) - - local destroy = function() - window:destroy() + window.onDestroy = function() if window == activeWindow then activeWindow = nil end end - - window.okButton.onClick = function() - local text = window.text:getText() - destroy() - callback(text) - end - window.cancelButton.onClick = destroy - window.onEscape = destroy - window.onEnter = window.okButton.onClick - - window.text:setText(text) - - activeWindow = window - activeWindow:raise() - activeWindow:focus() -end - -function multilineEditor(description, text, callback) - if activeWindow then - destroyWindow() - end - local window = g_ui.createWidget('TextEditMultilineWindow', rootWidget) - local destroy = function() - window:destroy() - if window == activeWindow then - activeWindow = nil + if options.title then + window:setText(options.title) + end + if options.description then + window.description:show() + window.description:setText(options.description) + end + if type(options.examples) == 'table' and #options.examples > 0 then + window.examples:show() + for i, title_text in ipairs(options.examples) do + window.examples:addOption(title_text[1], title_text[2]) + end + window.examples.onOptionChange = function(widget, option, data) + window.text:setText(data) + window.text:setCursorPos(-1) + end + end + if type(options.validation) == 'string' and options.validation:len() > 0 then + window.buttons.ok:disable() + window.text.onTextChange = function(widget, text) + if validate(text) then + window.buttons.ok:enable() + else + window.buttons.ok:disable() + end end end - window.okButton.onClick = function() - local text = window.text:getText() - destroy() - callback(text) - end - window.cancelButton.onClick = destroy - window.onEscape = destroy - - window.description:setText(description) window.text:setText(text) - + window.text:setCursorPos(-1) + + if type(options.width) == 'number' then + window:setWidth(options.width) + end + activeWindow = window activeWindow:raise() activeWindow:focus() + return activeWindow end function hide() destroyWindow() end + +function edit(...) + return show(...) +end + +-- legacy +function singlelineEditor(text, callback) + return show(text, {}, callback) +end + +-- legacy +function multilineEditor(description, text, callback) + return show(text, {description=description, multiline=true}, callback) +end + diff --git a/modules/game_textedit/textedit.otui b/modules/game_textedit/textedit.otui index d4797e8..8267207 100644 --- a/modules/game_textedit/textedit.otui +++ b/modules/game_textedit/textedit.otui @@ -1,73 +1,72 @@ +TextEditButtons < Panel + id: buttons + height: 30 + + Button + id: ok + !text: tr('Ok') + anchors.bottom: parent.bottom + anchors.right: next.left + margin-right: 10 + width: 60 + + Button + id: cancel + !text: tr('Cancel') + anchors.bottom: parent.bottom + anchors.right: parent.right + width: 60 + TextEditWindow < MainWindow id: textedit - size: 260 105 !text: tr("Edit text") - - TextEdit - id: text - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - Button - id: okButton - !text: tr('Ok') - anchors.bottom: parent.bottom - anchors.right: next.left - margin-right: 10 - width: 60 - - Button - id: cancelButton - !text: tr('Cancel') - anchors.bottom: parent.bottom - anchors.right: parent.right - width: 60 - -TextEditMultilineWindow < MainWindow - id: texteditmultiline - size: 650 497 - !text: tr("Edit text") - + layout: + type: verticalBox + fit-children: true + Label id: description - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - text-auto-resize: true text-align: center + text: description + margin-bottom: 5 + visible: false text-wrap: true + text-auto-resize: true + + ComboBox + id: examples + margin-bottom: 5 + visible: false - MultilineTextEdit +SinglelineTextEditWindow < TextEditWindow + width: 250 + + TextEdit id: text - anchors.top: textScroll.top - anchors.left: parent.left - anchors.right: textScroll.left - anchors.bottom: textScroll.bottom - vertical-scrollbar: textScroll - text-wrap: true - VerticalScrollBar - id: textScroll - anchors.top: description.bottom - anchors.bottom: okButton.top - anchors.right: parent.right - margin-bottom: 10 - step: 16 - pixels-scroll: true + TextEditButtons - Button - id: okButton - !text: tr('Ok') - anchors.bottom: parent.bottom - anchors.right: next.left - margin-right: 10 - width: 60 +MultilineTextEditWindow < TextEditWindow + width: 600 - Button - id: cancelButton - !text: tr('Cancel') - anchors.bottom: parent.bottom - anchors.right: parent.right - width: 60 + Panel + id: textPanel + height: 400 + + MultilineTextEdit + id: text + anchors.fill: parent + margin-right: 12 + text-wrap: true + vertical-scrollbar: textScroll + + VerticalScrollBar + id: textScroll + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + pixels-scroll: true + step: 10 + + TextEditButtons diff --git a/modules/game_walking/walking.lua b/modules/game_walking/walking.lua index b6474e2..eabd547 100644 --- a/modules/game_walking/walking.lua +++ b/modules/game_walking/walking.lua @@ -350,7 +350,7 @@ function walk(dir, ticks) return end - if dash and lastWalkDir == dir and lastWalk + 30 > g_clock.millis() then + if dash and lastWalkDir == dir and lastWalk + 50 > g_clock.millis() then return end diff --git a/otclient_dx.exe b/otclient_dx.exe index c0f1ca0..8acb6fd 100644 Binary files a/otclient_dx.exe and b/otclient_dx.exe differ diff --git a/otclient_gl.exe b/otclient_gl.exe index 2154196..59cc173 100644 Binary files a/otclient_gl.exe and b/otclient_gl.exe differ diff --git a/otclient_linux b/otclient_linux index 90b8c68..5a9d8f1 100644 Binary files a/otclient_linux and b/otclient_linux differ diff --git a/pdb/pdb.7z b/pdb/pdb.7z index 5766dfb..40ff037 100644 Binary files a/pdb/pdb.7z and b/pdb/pdb.7z differ