mirror of
https://github.com/mehah/otclient
synced 2026-08-15 16:29:06 -04:00
New Features: - Native macOS app with Cocoa windowing, OpenGL view, improved input, clipboard and cursor handling. - Platform-aware keyboard and shortcut behavior with clearer primary/meta/control semantics and normalized key combos. Bug Fixes: - Expanded detection for "connection refused" network errors. Chores: - macOS build/bundle and packaging improvements; new dependency overlay added; CI now runs macOS build when relevant. Tests: - AddressSanitizer support added for test builds.
391 lines
10 KiB
Lua
391 lines
10 KiB
Lua
function UIMinimap:onCreate()
|
|
self.autowalk = true
|
|
end
|
|
|
|
function UIMinimap:onSetup()
|
|
self.flagWindow = nil
|
|
self.floorUpWidget = self:getChildById('floorUpButton')
|
|
self.floorDownWidget = self:getChildById('floorDownButton')
|
|
self.zoomInWidget = self:getChildById('zoomInButton')
|
|
self.zoomOutWidget = self:getChildById('zoomOutButton')
|
|
self.flags = {}
|
|
self.fullMapView = false
|
|
self.zoomMinimap = 0
|
|
self.zoomFullmap = 0
|
|
self.alternatives = {}
|
|
self.onAddAutomapFlag = function(pos, icon, description)
|
|
self:addFlag(pos, icon, description)
|
|
end
|
|
self.onRemoveAutomapFlag = function(pos, icon, description)
|
|
self:removeFlag(pos, icon, description)
|
|
end
|
|
connect(g_game, {
|
|
onAddAutomapFlag = self.onAddAutomapFlag,
|
|
onRemoveAutomapFlag = self.onRemoveAutomapFlag
|
|
})
|
|
end
|
|
|
|
function UIMinimap:onDestroy()
|
|
for _, widget in pairs(self.alternatives) do
|
|
widget:destroy()
|
|
end
|
|
self.alternatives = {}
|
|
disconnect(g_game, {
|
|
onAddAutomapFlag = self.onAddAutomapFlag,
|
|
onRemoveAutomapFlag = self.onRemoveAutomapFlag
|
|
})
|
|
self:destroyFlagWindow()
|
|
self.flags = {}
|
|
end
|
|
|
|
function UIMinimap:onVisibilityChange()
|
|
if not self:isVisible() then
|
|
self:destroyFlagWindow()
|
|
end
|
|
end
|
|
|
|
function UIMinimap:onCameraPositionChange(cameraPos)
|
|
if self.cross then
|
|
self:setCrossPosition(self.cross.pos)
|
|
end
|
|
end
|
|
|
|
function UIMinimap:hideFloor()
|
|
self.floorUpWidget:hide()
|
|
self.floorDownWidget:hide()
|
|
end
|
|
|
|
function UIMinimap:hideZoom()
|
|
self.zoomInWidget:hide()
|
|
self.zoomOutWidget:hide()
|
|
end
|
|
|
|
function UIMinimap:disableAutoWalk()
|
|
self.autowalk = false
|
|
end
|
|
|
|
function UIMinimap:load()
|
|
local settings = g_settings.getNode('Minimap')
|
|
if settings then
|
|
if settings.flags then
|
|
for _, flag in pairs(settings.flags) do
|
|
self:addFlag(flag.position, flag.icon, flag.description)
|
|
end
|
|
end
|
|
self.zoomMinimap = settings.zoom
|
|
self.zoomFullmap = settings.zoomFull or settings.zoom
|
|
self:setZoom(self.zoomMinimap)
|
|
|
|
end
|
|
end
|
|
|
|
function UIMinimap:save()
|
|
local settings = {
|
|
flags = {}
|
|
}
|
|
for _, flag in pairs(self.flags) do
|
|
if not flag.temporary then
|
|
table.insert(settings.flags, {
|
|
position = flag.pos,
|
|
icon = flag.icon,
|
|
description = flag.description
|
|
})
|
|
end
|
|
end
|
|
settings.zoom = self.zoomMinimap
|
|
settings.zoomFull = self.zoomFullmap
|
|
g_settings.setNode('Minimap', settings)
|
|
end
|
|
|
|
local function onFlagMouseRelease(widget, pos, button)
|
|
if button == MouseLeftButton then
|
|
local player = g_game.getLocalPlayer()
|
|
if Position.distance(player:getPosition(), widget.pos) > 250 then
|
|
modules.game_textmessage.displayStatusMessage(tr('Destination is out of range.'))
|
|
return false
|
|
end
|
|
|
|
if widget:getParent().autowalk then
|
|
player:autoWalk(widget.pos)
|
|
end
|
|
return true
|
|
|
|
elseif button == MouseRightButton then
|
|
local menu = g_ui.createWidget('PopupMenu')
|
|
menu:setGameMenu(true)
|
|
menu:addOption(tr('Delete mark'), function()
|
|
widget:destroy()
|
|
end)
|
|
menu:display(pos)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function UIMinimap:setCrossPosition(pos)
|
|
local cross = self.cross
|
|
if not self.cross then
|
|
cross = g_ui.createWidget('MinimapCross', self)
|
|
if self:getParent():getId() == "MapBase" then
|
|
cross:setIcon('/game_cyclopedia/images/icon-map-player')
|
|
else
|
|
cross:setIcon('/images/game/minimap/cross')
|
|
end
|
|
self.cross = cross
|
|
end
|
|
|
|
pos.z = self:getCameraPosition().z
|
|
cross.pos = pos
|
|
if pos then
|
|
self:centerInPosition(cross, pos)
|
|
else
|
|
cross:breakAnchors()
|
|
end
|
|
end
|
|
|
|
function UIMinimap:addFlag(pos, icon, description, temporary)
|
|
if not pos or not icon then
|
|
return
|
|
end
|
|
local flag = self:getFlag(pos, icon, description)
|
|
if flag or not icon then
|
|
return
|
|
end
|
|
temporary = temporary or false
|
|
|
|
flag = g_ui.createWidget('MinimapFlag')
|
|
self:insertChild(1, flag)
|
|
flag.pos = pos
|
|
flag.description = description
|
|
flag.icon = icon
|
|
flag.temporary = temporary
|
|
if type(tonumber(icon)) == 'number' then
|
|
flag:setIcon('/images/game/minimap/flag' .. icon)
|
|
else
|
|
flag:setIcon(resolvepath(icon, 1))
|
|
end
|
|
flag:setTooltip(description)
|
|
flag.onMouseRelease = onFlagMouseRelease
|
|
flag.onDestroy = function()
|
|
table.removevalue(self.flags, flag)
|
|
end
|
|
table.insert(self.flags, flag)
|
|
self:centerInPosition(flag, pos)
|
|
end
|
|
|
|
function UIMinimap:addAlternativeWidget(widget, pos, maxZoom)
|
|
widget.pos = pos
|
|
widget.maxZoom = maxZoom or 0
|
|
widget.minZoom = minZoom
|
|
table.insert(self.alternatives, widget)
|
|
end
|
|
|
|
function UIMinimap:setAlternativeWidgetsVisible(show)
|
|
local layout = self:getLayout()
|
|
layout:disableUpdates()
|
|
for _, widget in pairs(self.alternatives) do
|
|
if show then
|
|
self:insertChild(1, widget)
|
|
self:centerInPosition(widget, widget.pos)
|
|
else
|
|
self:removeChild(widget)
|
|
end
|
|
end
|
|
layout:enableUpdates()
|
|
layout:update()
|
|
end
|
|
|
|
function UIMinimap:onZoomChange(zoom)
|
|
if self.fullMapView then
|
|
self.zoomFullmap = zoom
|
|
else
|
|
self.zoomMinimap = zoom
|
|
end
|
|
|
|
for _, widget in pairs(self.alternatives) do
|
|
if (not widget.minZoom or widget.minZoom >= zoom) and widget.maxZoom <= zoom then
|
|
widget:show()
|
|
else
|
|
widget:hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
function UIMinimap:getFlag(pos)
|
|
for _, flag in pairs(self.flags) do
|
|
if flag.pos.x == pos.x and flag.pos.y == pos.y and flag.pos.z == pos.z then
|
|
return flag
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function UIMinimap:removeFlag(pos, icon, description)
|
|
local flag = self:getFlag(pos)
|
|
if flag then
|
|
flag:destroy()
|
|
end
|
|
end
|
|
|
|
function UIMinimap:reset()
|
|
local player = g_game.getLocalPlayer()
|
|
if player then
|
|
self:setCameraPosition(player:getPosition())
|
|
end
|
|
end
|
|
|
|
function UIMinimap:move(x, y)
|
|
local cameraPos = self:getCameraPosition()
|
|
local scale = self:getScale()
|
|
if scale > 1 then
|
|
scale = 1
|
|
end
|
|
local dx = x / scale
|
|
local dy = y / scale
|
|
local pos = {
|
|
x = cameraPos.x - dx,
|
|
y = cameraPos.y - dy,
|
|
z = cameraPos.z
|
|
}
|
|
self:setCameraPosition(pos)
|
|
end
|
|
|
|
function UIMinimap:onMouseWheel(mousePos, direction)
|
|
local keyboardModifiers = g_keyboard.getModifiers()
|
|
if direction == MouseWheelUp and keyboardModifiers == KeyboardNoModifier then
|
|
self:zoomIn()
|
|
elseif direction == MouseWheelDown and keyboardModifiers == KeyboardNoModifier then
|
|
self:zoomOut()
|
|
elseif direction == MouseWheelDown and g_keyboard.isPrimaryModifierOnly(keyboardModifiers) then
|
|
self:floorUp(1)
|
|
elseif direction == MouseWheelUp and g_keyboard.isPrimaryModifierOnly(keyboardModifiers) then
|
|
self:floorDown(1)
|
|
end
|
|
end
|
|
|
|
function UIMinimap:onMousePress(pos, button)
|
|
if not self:isDragging() then
|
|
self.allowNextRelease = true
|
|
end
|
|
end
|
|
|
|
function UIMinimap:onMouseRelease(pos, button)
|
|
if not self.allowNextRelease then
|
|
return true
|
|
end
|
|
self.allowNextRelease = false
|
|
|
|
local mapPos = self:getTilePosition(pos)
|
|
if not mapPos then
|
|
return false
|
|
end
|
|
|
|
if button == MouseLeftButton then
|
|
local player = g_game.getLocalPlayer()
|
|
if g_game.getClientVersion() > 1288 and g_keyboard.isCtrlPressed() and g_keyboard.isShiftPressed() then
|
|
return g_game.sendGmTeleport(mapPos)
|
|
end
|
|
if Position.distance(player:getPosition(), mapPos) > 250 then
|
|
modules.game_textmessage.displayStatusMessage(tr('Destination is out of range.'))
|
|
return false
|
|
end
|
|
|
|
if self.autowalk then
|
|
player:autoWalk(mapPos)
|
|
end
|
|
return true
|
|
elseif button == MouseRightButton then
|
|
local menu = g_ui.createWidget('PopupMenu')
|
|
menu:setGameMenu(true)
|
|
menu:addOption(tr('Create mark'), function()
|
|
self:createFlagWindow(mapPos)
|
|
end)
|
|
menu:display(pos)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function UIMinimap:onDragEnter(pos)
|
|
self.dragReference = pos
|
|
self.dragCameraReference = self:getCameraPosition()
|
|
return true
|
|
end
|
|
|
|
function UIMinimap:onDragMove(pos, moved)
|
|
local scale = self:getScale()
|
|
local dx = (self.dragReference.x - pos.x) / scale
|
|
local dy = (self.dragReference.y - pos.y) / scale
|
|
local pos = {
|
|
x = self.dragCameraReference.x + dx,
|
|
y = self.dragCameraReference.y + dy,
|
|
z = self.dragCameraReference.z
|
|
}
|
|
self:setCameraPosition(pos)
|
|
return true
|
|
end
|
|
|
|
function UIMinimap:onDragLeave(widget, pos)
|
|
return true
|
|
end
|
|
|
|
function UIMinimap:onStyleApply(styleName, styleNode)
|
|
for name, value in pairs(styleNode) do
|
|
if name == 'autowalk' then
|
|
self.autowalk = value
|
|
end
|
|
end
|
|
end
|
|
|
|
function UIMinimap:createFlagWindow(pos)
|
|
if self.flagWindow then
|
|
return
|
|
end
|
|
if not pos then
|
|
return
|
|
end
|
|
|
|
self.flagWindow = g_ui.createWidget('MinimapFlagWindow', rootWidget)
|
|
|
|
local positionLabel = self.flagWindow:getChildById('position')
|
|
local description = self.flagWindow:getChildById('description')
|
|
local okButton = self.flagWindow:getChildById('okButton')
|
|
local cancelButton = self.flagWindow:getChildById('cancelButton')
|
|
|
|
positionLabel:setText(string.format('%i, %i, %i', pos.x, pos.y, pos.z))
|
|
|
|
local flagRadioGroup = UIRadioGroup.create()
|
|
for i = 0, 19 do
|
|
local checkbox = self.flagWindow:getChildById('flag' .. i)
|
|
checkbox.icon = i
|
|
flagRadioGroup:addWidget(checkbox)
|
|
end
|
|
|
|
flagRadioGroup:selectWidget(flagRadioGroup:getFirstWidget())
|
|
|
|
local successFunc = function()
|
|
self:addFlag(pos, flagRadioGroup:getSelectedWidget().icon, description:getText())
|
|
self:destroyFlagWindow()
|
|
end
|
|
|
|
local cancelFunc = function()
|
|
self:destroyFlagWindow()
|
|
end
|
|
|
|
okButton.onClick = successFunc
|
|
cancelButton.onClick = cancelFunc
|
|
|
|
self.flagWindow.onEnter = successFunc
|
|
self.flagWindow.onEscape = cancelFunc
|
|
|
|
self.flagWindow.onDestroy = function()
|
|
flagRadioGroup:destroy()
|
|
end
|
|
end
|
|
|
|
function UIMinimap:destroyFlagWindow()
|
|
if self.flagWindow then
|
|
self.flagWindow:destroy()
|
|
self.flagWindow = nil
|
|
end
|
|
end
|