uiminimap.lua

main 357 lines · 9.5 KB Raw
Alex Alex Commit Client Upload Part 2 19/10/2026 00:06
1-- Left-click teleport for gamemasters. The server tells us on login whether
2-- this character may use it (server: data/scripts/customs/admin_minimap_teleport.lua).
3local ADMIN_MINIMAP_TELEPORT_OPCODE = 215
4local adminMinimapTeleportEnabled = false
5local adminMinimapTeleportRegistered = false
6
7local function sendAdminMinimapTeleport(pos)
8 local protocolGame = g_game.getProtocolGame()
9 if not protocolGame or not pos then
10 return false
11 end
12
13 protocolGame:sendExtendedOpcode(ADMIN_MINIMAP_TELEPORT_OPCODE, json.encode({
14 action = 'teleport',
15 position = { x = pos.x, y = pos.y, z = pos.z }
16 }))
17 return true
18end
19
20local function onAdminMinimapTeleportOpcode(protocol, opcode, buffer)
21 local ok, status = pcall(json.decode, buffer)
22 if not ok or type(status) ~= 'table' or status.action ~= 'access' then
23 return
24 end
25
26 adminMinimapTeleportEnabled = status.enabled == true
27end
28
29function UIMinimap:onCreate()
30 self.autowalk = true
31end
32
33function UIMinimap:onSetup()
34 if not adminMinimapTeleportRegistered then
35 -- pcall: after a gamelib reload the opcode is still registered
36 adminMinimapTeleportRegistered = pcall(ProtocolGame.registerExtendedOpcode,
37 ADMIN_MINIMAP_TELEPORT_OPCODE, onAdminMinimapTeleportOpcode)
38 end
39
40 self.flagWindow = nil
41 self.flags = {}
42 self.alternatives = {}
43 self.onAddAutomapFlag = function(pos, icon, description) self:addFlag(pos, icon, description) end
44 self.onRemoveAutomapFlag = function(pos, icon, description) self:removeFlag(pos, icon, description) end
45 connect(g_game, {
46 onAddAutomapFlag = self.onAddAutomapFlag,
47 onRemoveAutomapFlag = self.onRemoveAutomapFlag,
48 })
49end
50
51function UIMinimap:onDestroy()
52 for _,widget in pairs(self.alternatives) do
53 widget:destroy()
54 end
55 self.alternatives = {}
56 disconnect(g_game, {
57 onAddAutomapFlag = self.onAddAutomapFlag,
58 onRemoveAutomapFlag = self.onRemoveAutomapFlag,
59 })
60 self:destroyFlagWindow()
61 self.flags = {}
62end
63
64function UIMinimap:onVisibilityChange()
65 if not self:isVisible() then
66 self:destroyFlagWindow()
67 end
68end
69
70function UIMinimap:onCameraPositionChange(cameraPos)
71 if self.cross then
72 self:setCrossPosition(self.cross.pos)
73 end
74end
75
76function UIMinimap:hideFloor()
77 self.floorUpWidget:hide()
78 self.floorDownWidget:hide()
79end
80
81function UIMinimap:hideZoom()
82 self.zoomInWidget:hide()
83 self.zoomOutWidget:hide()
84end
85
86function UIMinimap:disableAutoWalk()
87 self.autowalk = false
88end
89
90function UIMinimap:load()
91 local settings = g_settings.getNode('Minimap')
92 if settings then
93 if settings.flags then
94 for _,flag in pairs(settings.flags) do
95 self:addFlag(flag.position, flag.icon, flag.description)
96 end
97 end
98 self:setZoom(settings.zoom)
99 end
100end
101
102function UIMinimap:save()
103 local settings = { flags={} }
104 for _,flag in pairs(self.flags) do
105 if not flag.temporary then
106 table.insert(settings.flags, {
107 position = flag.pos,
108 icon = flag.icon,
109 description = flag.description,
110 })
111 end
112 end
113 settings.zoom = self:getZoom()
114 g_settings.setNode('Minimap', settings)
115end
116
117local function onFlagMouseRelease(widget, pos, button)
118 if button == MouseRightButton then
119 local menu = g_ui.createWidget('PopupMenu')
120 menu:setGameMenu(true)
121 menu:addOption(tr('Delete mark'), function() widget:destroy() end)
122 menu:display(pos)
123 return true
124 end
125 return false
126end
127
128function UIMinimap:setCrossPosition(pos)
129 local cross = self.cross
130 if not self.cross then
131 cross = g_ui.createWidget('MinimapCross', self)
132 cross:setIcon('/images/ui/windows/minimap/cross')
133 self.cross = cross
134 end
135
136 pos.z = self:getCameraPosition().z
137 cross.pos = pos
138 if pos then
139 self:centerInPosition(cross, pos)
140 else
141 cross:breakAnchors()
142 end
143end
144
145function UIMinimap:addFlag(pos, icon, description, temporary)
146 if not pos or not icon then return end
147 local flag = self:getFlag(pos, icon, description)
148 if flag or not icon then
149 return
150 end
151 temporary = temporary or false
152
153 flag = g_ui.createWidget('MinimapFlag')
154 self:insertChild(1, flag)
155 flag.pos = pos
156 flag.description = description
157 flag.icon = icon
158 flag.temporary = temporary
159 if type(tonumber(icon)) == 'number' then
160 flag:setIcon('/images/ui/windows/minimap/flag' .. icon)
161 else
162 flag:setIcon(resolvepath(icon, 1))
163 end
164 flag:setTooltip(description)
165 flag.onMouseRelease = onFlagMouseRelease
166 flag.onDestroy = function() table.removevalue(self.flags, flag) end
167 table.insert(self.flags, flag)
168 self:centerInPosition(flag, pos)
169end
170
171function UIMinimap:addAlternativeWidget(widget, pos, maxZoom)
172 widget.pos = pos
173 widget.maxZoom = maxZoom or 0
174 widget.minZoom = minZoom
175 table.insert(self.alternatives, widget)
176end
177
178function UIMinimap:setAlternativeWidgetsVisible(show)
179 local layout = self:getLayout()
180 layout:disableUpdates()
181 for _,widget in pairs(self.alternatives) do
182 if show then
183 self:insertChild(1, widget)
184 self:centerInPosition(widget, widget.pos)
185 else
186 self:removeChild(widget)
187 widget:destroy()
188 end
189 end
190 layout:enableUpdates()
191 layout:update()
192end
193
194function UIMinimap:onZoomChange(zoom)
195 for _,widget in pairs(self.alternatives) do
196 if (not widget.minZoom or widget.minZoom >= zoom) and widget.maxZoom <= zoom then
197 widget:show()
198 else
199 widget:hide()
200 end
201 end
202end
203
204function UIMinimap:getFlag(pos)
205 for _,flag in pairs(self.flags) do
206 if flag.pos.x == pos.x and flag.pos.y == pos.y and flag.pos.z == pos.z then
207 return flag
208 end
209 end
210 return nil
211end
212
213function UIMinimap:removeFlag(pos, icon, description)
214 local flag = self:getFlag(pos)
215 if flag then
216 flag:destroy()
217 end
218end
219
220function UIMinimap:reset()
221 self:setZoom(0)
222 if self.cross then
223 self:setCameraPosition(self.cross.pos)
224 end
225end
226
227function UIMinimap:move(x, y)
228 local cameraPos = self:getCameraPosition()
229 local scale = self:getScale()
230 if scale > 1 then scale = 1 end
231 local dx = x/scale
232 local dy = y/scale
233 local pos = {x = cameraPos.x - dx, y = cameraPos.y - dy, z = cameraPos.z}
234 self:setCameraPosition(pos)
235end
236
237function UIMinimap:onMouseWheel(mousePos, direction)
238 local keyboardModifiers = g_keyboard.getModifiers()
239 if direction == MouseWheelUp and keyboardModifiers == KeyboardNoModifier then
240 self:zoomIn()
241 elseif direction == MouseWheelDown and keyboardModifiers == KeyboardNoModifier then
242 self:zoomOut()
243 elseif direction == MouseWheelDown and keyboardModifiers == KeyboardCtrlModifier then
244 self:floorUp(1)
245 elseif direction == MouseWheelUp and keyboardModifiers == KeyboardCtrlModifier then
246 self:floorDown(1)
247 end
248end
249
250function UIMinimap:onMousePress(pos, button)
251 if not self:isDragging() then
252 self.allowNextRelease = true
253 end
254end
255
256function UIMinimap:onMouseRelease(pos, button)
257 if not self.allowNextRelease then return true end
258 self.allowNextRelease = false
259
260 local mapPos = self:getTilePosition(pos)
261 if not mapPos then return end
262
263 if button == MouseLeftButton then
264 local player = g_game.getLocalPlayer()
265 if adminMinimapTeleportEnabled and sendAdminMinimapTeleport(mapPos) then
266 return true
267 end
268 if self.autowalk then
269 player:autoWalk(mapPos)
270 end
271 return true
272 elseif button == MouseRightButton then
273 local menu = g_ui.createWidget('PopupMenu')
274 menu:setGameMenu(true)
275 menu:addOption(tr('Create mark'), function() self:createFlagWindow(mapPos) end)
276 menu:display(pos)
277 return true
278 end
279 return false
280end
281
282function UIMinimap:onDragEnter(pos)
283 self.dragReference = pos
284 self.dragCameraReference = self:getCameraPosition()
285 return true
286end
287
288function UIMinimap:onDragMove(pos, moved)
289 local scale = self:getScale()
290 local dx = (self.dragReference.x - pos.x)/scale
291 local dy = (self.dragReference.y - pos.y)/scale
292 local pos = {x = self.dragCameraReference.x + dx, y = self.dragCameraReference.y + dy, z = self.dragCameraReference.z}
293 self:setCameraPosition(pos)
294 return true
295end
296
297function UIMinimap:onDragLeave(widget, pos)
298 return true
299end
300
301function UIMinimap:onStyleApply(styleName, styleNode)
302 for name,value in pairs(styleNode) do
303 if name == 'autowalk' then
304 self.autowalk = value
305 end
306 end
307end
308
309function UIMinimap:createFlagWindow(pos)
310 if self.flagWindow then return end
311 if not pos then return end
312
313 self.flagWindow = g_ui.createWidget('MinimapFlagWindow', rootWidget)
314 self.flagWindow:setWidth(210) -- For some reason changing this in otui got ignored
315 self.flagWindow:setHeight(215)
316
317 local positionLabel = self.flagWindow:getChildById('position')
318 local description = self.flagWindow:getChildById('description')
319 local okButton = self.flagWindow:getChildById('okButton')
320 local cancelButton = self.flagWindow:getChildById('cancelButton')
321
322 positionLabel:setText(string.format('%i, %i, %i', pos.x, pos.y, pos.z))
323
324 local flagRadioGroup = UIRadioGroup.create()
325 for i=0,19 do
326 local checkbox = self.flagWindow:getChildById('flag' .. i)
327 checkbox.icon = i
328 flagRadioGroup:addWidget(checkbox)
329 end
330
331 flagRadioGroup:selectWidget(flagRadioGroup:getFirstWidget())
332
333 local successFunc = function()
334 self:addFlag(pos, flagRadioGroup:getSelectedWidget().icon, description:getText())
335 self:destroyFlagWindow()
336 end
337
338 local cancelFunc = function()
339 self:destroyFlagWindow()
340 end
341
342 okButton.onClick = successFunc
343 cancelButton.onClick = cancelFunc
344
345 self.flagWindow.onEnter = successFunc
346 self.flagWindow.onEscape = cancelFunc
347
348 self.flagWindow.onDestroy = function() flagRadioGroup:destroy() end
349end
350
351function UIMinimap:destroyFlagWindow()
352 if self.flagWindow then
353 self.flagWindow:destroy()
354 self.flagWindow = nil
355 end
356end
357
Top