Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b941829
feat: mapgen in otcr
kokekanon Jan 6, 2026
8b5ac83
Update mapio.cpp
kokekanon Jan 6, 2026
4b19da5
Update terminal.lua
kokekanon Jan 6, 2026
f438842
satellite
kokekanon Mar 15, 2026
4205efc
asd
kokekanon Mar 15, 2026
fbfbc25
asd
kokekanon Mar 16, 2026
bd6984a
Update mapio.cpp
kokekanon Mar 16, 2026
b7aa5c1
Update image.cpp
kokekanon Mar 16, 2026
b9b8efd
asd
kokekanon Mar 16, 2026
c94183d
asd
kokekanon Mar 16, 2026
cc92552
asd
kokekanon Mar 16, 2026
75e02d9
asd
kokekanon Mar 16, 2026
fae6c88
asd
kokekanon Mar 16, 2026
06428c7
asd
kokekanon Mar 16, 2026
baba7e8
asd
kokekanon Mar 16, 2026
751affb
asd
kokekanon Mar 16, 2026
35d03a0
asd
kokekanon Mar 16, 2026
1271bed
asd
kokekanon Mar 16, 2026
788b982
Merge remote-tracking branch 'upstream/main' into Mapgen
kokekanon Mar 16, 2026
31ca945
asd
kokekanon Mar 16, 2026
1371bd6
Revert "asd"
kokekanon Mar 16, 2026
af98d97
asd
kokekanon Mar 16, 2026
f7b42d5
Update mapio.cpp
kokekanon Mar 16, 2026
d87c209
asd
kokekanon Mar 17, 2026
cfd40b7
focus
kokekanon Mar 17, 2026
f91e014
asd
kokekanon Mar 17, 2026
5d2e881
asd
kokekanon Mar 17, 2026
453e997
asdasd
kokekanon Mar 17, 2026
e3aefdc
asd
kokekanon Mar 17, 2026
ace1216
Update mapio.cpp
kokekanon Mar 17, 2026
006433d
asd
kokekanon Mar 17, 2026
2a99263
asd
kokekanon Mar 17, 2026
8e5df19
asd
kokekanon Mar 17, 2026
3758d54
asd
kokekanon Mar 17, 2026
d91913e
asd
kokekanon Mar 17, 2026
feb3115
I don't care enough to do a squash
kokekanon Mar 17, 2026
36a4112
I don't care enough to do a squash
kokekanon Mar 17, 2026
c1fafe1
I don't care enough to do a squash
kokekanon Mar 17, 2026
e4e46f7
I don't care enough to do a squash
kokekanon Mar 17, 2026
bea3774
diff
kokekanon Mar 17, 2026
dd28a87
I don't care enough to do a squash
kokekanon Mar 18, 2026
fbc5d79
test quality of life
kokekanon Mar 18, 2026
be020d2
fix: u16 -> u32
kokekanon Mar 19, 2026
7302610
rollback just in case
kokekanon Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 8 additions & 21 deletions data/styles/10-comboboxes.otui
Original file line number Diff line number Diff line change
Expand Up @@ -107,27 +107,6 @@ ComboBoxRounded < ComboBox
image-source: /images/ui/combobox_rounded
image-border: 3

QtComboBoxPopupScrollMenuButton < UIButton
height: 23
font: verdana-11px-antialised
text-align: left
text-offset: 4 0
color: #dfdfdf
background-color: alpha
margin: 1

$hover !disabled:
color: #dfdfdf
background-color: #355d89

$disabled:
color: #dfdfdf88

QtComboBoxPopupScrollMenu < UIPopupScrollMenu
image-source: /images/ui/combobox_square
image-clip: 0 69 91 23
image-border: 1

QtComboBoxPopupMenuButton < UIButton
height: 20
text-align: left
Expand All @@ -152,6 +131,14 @@ QtComboBoxPopupMenu < UIPopupMenu
image-clip: 0 60 91 20
image-border: 2

QtComboBoxPopupScrollMenuButton < QtComboBoxPopupMenuButton

QtComboBoxPopupScrollMenu < UIPopupScrollMenu
image-source: /images/ui/combobox_new
image-clip: 0 60 91 20
image-border: 2


QtComboBox < UIComboBox
color: #c0c0c0ff
size: 91 20
Expand Down
1 change: 1 addition & 0 deletions modules/client_terminal/terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ function init()
addLine(line.text, line.color)
end
end
toggle()
end

function terminate()
Expand Down
11 changes: 1 addition & 10 deletions modules/corelib/ui/uispinbox.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ function UISpinBox.create()
spinbox.maximum = 1
spinbox.value = 0
spinbox.step = 1
spinbox.firstchange = true
spinbox.mouseScroll = true
spinbox:setText('1')
spinbox:setValue(1)
Expand Down Expand Up @@ -38,14 +37,6 @@ function UISpinBox:onMouseWheel(mousePos, direction)
return true
end

function UISpinBox:onKeyPress()
if self.firstchange then
self.firstchange = false
self:setText('')
end
return false
end

function UISpinBox:onTextChange(text, oldText)
if self.formattedMode then
local cursorPos = self:getCursorPos()
Expand Down Expand Up @@ -287,4 +278,4 @@ function UISpinBox:setFormattedMode(enabled)
else
self:setValidCharacters('0123456789')
end
end
end
231 changes: 205 additions & 26 deletions modules/game_cyclopedia/tab/map/map.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,79 @@
local UI = nil
local virtualFloor = 7
local viewRadioGroup = nil
local loadedAssetsDir = nil
local loadedFloorSet = {} -- floors already indexed for loadedAssetsDir

-- Forward declaration — defined later in the file.
local refreshVirtualFloors

-- Surface View is only available for floors 0-7 (surface and above).
-- Underground floors (8-15) always use Map View.
local SEA_FLOOR = 7

local function ensureViewFloorsLoaded()
local assetsDir = string.format("/data/things/%d", g_game.getClientVersion())

-- Reset when switching game versions
if assetsDir ~= loadedAssetsDir then
g_satelliteMap.clear()
loadedFloorSet = {}
loadedAssetsDir = assetsDir
end

-- For surface floors: composite view needs [virtualFloor, SEA_FLOOR].
-- For underground: only the current floor is needed (static minimap, map view only).
local floorMax = (virtualFloor <= SEA_FLOOR) and SEA_FLOOR or virtualFloor

local minNeeded, maxNeeded
for f = virtualFloor, floorMax do
if not loadedFloorSet[f] then
if not minNeeded then
minNeeded = f
end
maxNeeded = f
end
end

if minNeeded then
g_satelliteMap.loadFloors(assetsDir, minNeeded, maxNeeded)
for f = minNeeded, maxNeeded do
loadedFloorSet[f] = true
end
end
end

local function isSurfaceFloor(floor)
return floor <= SEA_FLOOR
end

local function updateViewMode()
if not UI or not viewRadioGroup then
return
end

local minimapWidget = UI.MapBase.minimap
local viewBase = UI.InformationBase.InternalBase.DisplayBase.ViewBase1
local surfaceCheck = viewBase.SurfaceCheck
local separatorScroll = viewBase.SeparatorScroll
local separatorLabel = viewBase.SeparatorLabel

local canUseSurface = isSurfaceFloor(virtualFloor) and g_satelliteMap.hasChunksForView(virtualFloor)

-- Underground: force Map View and lock the Surface option.
-- selectWidget must come BEFORE setEnabled: UIRadioGroup calls setChecked(false)
-- on the deselected widget, which does not work correctly on a disabled widget.
if not canUseSurface then
viewRadioGroup:selectWidget(viewBase.MapCheck)
end
surfaceCheck:setEnabled(canUseSurface)

-- Level separator scroll is only meaningful in Surface View on floors above z7 (z < 7).
-- At z7 itself the composite has no lower floor to blend with, so the scroll is unused.
local inSurfaceMode = canUseSurface and surfaceCheck:isChecked() and virtualFloor < SEA_FLOOR
separatorScroll:setEnabled(inSurfaceMode)
separatorLabel:setEnabled(inSurfaceMode)
end

function showMap()
g_minimap.saveOtmm('/minimap.otmm')
Expand All @@ -9,7 +83,6 @@ function showMap()
onPositionChange = Cyclopedia.onUpdateCameraPosition
}):execute()

Cyclopedia.prevFloor = 7
Cyclopedia.loadMap()

controllerCyclopedia.ui.CharmsBase:setVisible(false)
Expand All @@ -24,6 +97,15 @@ function Cyclopedia.loadMap()
local clientVersion = g_game.getClientVersion()
local minimapWidget = UI.MapBase.minimap

-- Prime virtualFloor from current player position before any floor-dependent logic
local player = g_game.getLocalPlayer()
if player then
local pos = player:getPosition()
if pos then
virtualFloor = pos.z
end
end

g_minimap.clean()

local loaded = false
Expand All @@ -47,36 +129,105 @@ function Cyclopedia.loadMap()
print("Minimap couldn't be loaded, file missing?")
end

-- Preserve the zoom declared in the OTUI style — load() overwrites it with the
-- HUD minimap's saved settings zoom, which we don't want for Cyclopedia.
local initialZoom = minimapWidget:getZoom()
minimapWidget:load()
-- minimapWidget:hideFlags()
end
minimapWidget:setZoom(initialZoom)
minimapWidget:setUseStaticMinimap(true)

-- Load satellite chunks for the floors needed by the current view only.
-- Additional floors are indexed on demand when the user navigates deeper.
ensureViewFloorsLoaded()
local chunkCount = g_satelliteMap.hasChunksForView(virtualFloor) and 1 or 0

-- Views panel is always visible; satellite chunks determine whether Surface View is enabled.
local viewBase = UI.InformationBase.InternalBase.DisplayBase.ViewBase1
local surfaceCheck = viewBase.SurfaceCheck
local mapCheck = viewBase.MapCheck

-- Clean up previous radio group if the map tab was reopened
if viewRadioGroup then
viewRadioGroup:destroy()
viewRadioGroup = nil
end

viewRadioGroup = UIRadioGroup.create()
viewRadioGroup:addWidget(surfaceCheck)
viewRadioGroup:addWidget(mapCheck)

function Cyclopedia.CreateMarkItem(Data)
local MarkItem = g_ui.createWidget("MarkListItem", UI.InformationBase.InternalBase.DisplayBase.MarkList)
MarkItem:setIcon("/images/game/minimap/flag" .. Data.flagId)
viewRadioGroup.onSelectionChange = function(self, selected)
local inSurface = selected == surfaceCheck and isSurfaceFloor(virtualFloor) and
g_satelliteMap.hasChunksForView(virtualFloor)
minimapWidget:setSatelliteMode(inSurface)

-- Sync separator scroll enabled state (only for floors above z7)
local separatorScroll = viewBase.SeparatorScroll
local separatorLabel = viewBase.SeparatorLabel
local canUseSeparator = inSurface and virtualFloor < SEA_FLOOR
separatorScroll:setEnabled(canUseSeparator)
separatorLabel:setEnabled(canUseSeparator)
end

-- Default: Surface View when satellite data exists and on a surface floor, else Map View
viewRadioGroup:selectWidget((chunkCount > 0 and isSurfaceFloor(virtualFloor)) and surfaceCheck or mapCheck)

-- Hook separator scroll: adjusts floor compositing opacity (1.0 = all visible, 0.0 = target only)
local separatorScroll = viewBase.SeparatorScroll
separatorScroll.onValueChange = function(self, value)
minimapWidget:setFloorSeparatorOpacity(value / 100.0)
end
-- Reset opacity on (re-)open
minimapWidget:setFloorSeparatorOpacity(separatorScroll:getValue() / 100.0)

updateViewMode()

-- Sync flags from main minimap's live table (avoids stale g_settings on first open).
local mainMinimap = modules.game_minimap and modules.game_minimap.getMiniMapUi and
modules.game_minimap.getMiniMapUi()
if mainMinimap then
for _, flag in pairs(mainMinimap.flags) do
if not minimapWidget:getFlag(flag.pos) then
minimapWidget:addFlag(flag.pos, flag.icon, flag.description)
end
end
end

-- Apply initial filter state: hide flags whose filter checkbox is unchecked.
local markList = UI.InformationBase.InternalBase.DisplayBase.MarkList
for _, flag in pairs(minimapWidget.flags) do
local btn = markList:getChildById(tostring(flag.icon))
flag:setVisible(btn ~= nil and btn:isChecked())
end

refreshVirtualFloors()
end

function Cyclopedia.toggleMapFlag(widget, checked)
-- UI.MapBase.minimap:filterFlag(widget:getId(), checked)
local flagType = tonumber(widget:getId())
if not flagType then
return
end
local minimapWidget = UI.MapBase.minimap
for _, flag in pairs(minimapWidget.flags) do
if flag.icon == flagType then
flag:setVisible(checked)
end
end
end

function Cyclopedia.showAllFlags(checked)
local size = UI.InformationBase.InternalBase.DisplayBase.MarkList:getChildCount()
if checked then
for i = 0, size do
local flag = UI.InformationBase.InternalBase.DisplayBase.MarkList[i]
if flag then
flag:setChecked(true)
end
end
else
for i = 0, size do
local flag = UI.InformationBase.InternalBase.DisplayBase.MarkList[i]
if flag then
flag:setChecked(false)
end
local list = UI.InformationBase.InternalBase.DisplayBase.MarkList
for i = 0, list:getChildCount() - 1 do
local btn = list:getChildByIndex(i)
if btn then
btn:setChecked(checked)
end
end
local minimapWidget = UI.MapBase.minimap
for _, flag in pairs(minimapWidget.flags) do
flag:setVisible(checked)
end
end

function Cyclopedia.moveMap(widget)
Expand Down Expand Up @@ -127,6 +278,26 @@ function ConvertLayer(Value)
end
end

refreshVirtualFloors = function()
local mark = UI.InformationBase.InternalBase.NavigationBase.layersMark
mark:setMarginTop(((virtualFloor + 1) * 4) - 3)
UI.InformationBase.InternalBase.NavigationBase.automapLayers:setImageClip((virtualFloor * 14) .. ' 0 14 67')

-- Update player marker (cross) visibility on the minimap
local cross = UI.MapBase.minimap.cross
if cross then
if virtualFloor > SEA_FLOOR then
cross:setVisible(false)
elseif virtualFloor < SEA_FLOOR then
cross:setVisible(true)
cross:setIconColor("#ffffff80")
else
cross:setVisible(true)
cross:setIconColor("#ffffffff")
end
end
end

function Cyclopedia.onUpdateCameraPosition()
local player = g_game.getLocalPlayer()
if not player then
Expand All @@ -147,7 +318,16 @@ function Cyclopedia.onUpdateCameraPosition()
minimapWidget:setCrossPosition(player:getPosition(), true)
end

local prevFloor = virtualFloor
virtualFloor = pos.z

-- When the player changes floor, sync the visual floor indicator and
-- satellite/map view toggle (e.g. walking underground disables Surface View).
if virtualFloor ~= prevFloor then
ensureViewFloorsLoaded()
refreshVirtualFloors()
updateViewMode()
end
end

function Cyclopedia.onClickRoseButton(dir)
Expand Down Expand Up @@ -178,19 +358,16 @@ function Cyclopedia.setZooom(zoom)
end
end

local function refreshVirtualFloors()
UI.InformationBase.InternalBase.NavigationBase.layersMark:setMarginTop(((virtualFloor + 1) * 4) - 3)
UI.InformationBase.InternalBase.NavigationBase.automapLayers:setImageClip((virtualFloor * 14) .. ' 0 14 67')
end

function Cyclopedia.downLayer()
if virtualFloor == 15 then
return
end

UI.MapBase.minimap:floorDown(1)
virtualFloor = virtualFloor + 1
ensureViewFloorsLoaded()
refreshVirtualFloors()
updateViewMode()
end

function Cyclopedia.upLayer()
Expand All @@ -200,5 +377,7 @@ function Cyclopedia.upLayer()

UI.MapBase.minimap:floorUp(1)
virtualFloor = virtualFloor - 1
ensureViewFloorsLoaded()
refreshVirtualFloors()
updateViewMode()
end
Loading
Loading