Initial commit
This commit is contained in:
commit
560768bc61
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
6
src/aliases/galaxy-map/aliases.json
Normal file
6
src/aliases/galaxy-map/aliases.json
Normal file
@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"name": "gmap-refresh",
|
||||
"regex": "^gmap refresh$"
|
||||
}
|
||||
]
|
5
src/aliases/galaxy-map/gmap-refresh.lua
Normal file
5
src/aliases/galaxy-map/gmap-refresh.lua
Normal file
@ -0,0 +1,5 @@
|
||||
lotj.galaxyMap.resetData()
|
||||
|
||||
enableTrigger("galaxy-map-refresh")
|
||||
send("starsystems", false)
|
||||
send("planets", false)
|
7
src/aliases/mapper/aliases.json
Normal file
7
src/aliases/mapper/aliases.json
Normal file
@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"name": "map",
|
||||
"regex": "^map( ?.*)$",
|
||||
"script": "lotj.mapper.mapCommand(matches[2])"
|
||||
}
|
||||
]
|
6
src/aliases/system-map/aliases.json
Normal file
6
src/aliases/system-map/aliases.json
Normal file
@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"name": "radar",
|
||||
"regex": "^r(a(d(a(r)?)?)?)?$"
|
||||
}
|
||||
]
|
4
src/aliases/system-map/radar.lua
Normal file
4
src/aliases/system-map/radar.lua
Normal file
@ -0,0 +1,4 @@
|
||||
-- Intercept the radar command to enable our radar scraping triggers.
|
||||
-- We don't want them to potentially fire on unrelated lines.
|
||||
enableTrigger("system-map-radar")
|
||||
send("radar", false)
|
BIN
src/resources/space.jpg
Normal file
BIN
src/resources/space.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 90 KiB |
34
src/scripts/chat/chat.lua
Normal file
34
src/scripts/chat/chat.lua
Normal file
@ -0,0 +1,34 @@
|
||||
lotj = lotj or {}
|
||||
lotj.chat = lotj.chat or {}
|
||||
|
||||
registerAnonymousEventHandler("lotjUICreated", function()
|
||||
for keyword, contentsContainer in pairs(lotj.layout.lowerRightTabData.contents) do
|
||||
lotj.chat[keyword] = Geyser.MiniConsole:new({
|
||||
x = "1%", y = "1%",
|
||||
width = "98%",
|
||||
height = "98%",
|
||||
autoWrap = false,
|
||||
color = "black",
|
||||
scrollBar = true,
|
||||
fontSize = 14,
|
||||
}, contentsContainer)
|
||||
|
||||
-- Set the wrap at a few characters short of the full width to avoid the scroll bar showing over text
|
||||
local charsPerLine = lotj.chat[keyword]:getColumnCount()-3
|
||||
lotj.chat[keyword]:setWrap(charsPerLine)
|
||||
registerAnonymousEventHandler("sysWindowResizeEvent", function()
|
||||
local charsPerLine = lotj.chat[keyword]:getColumnCount()-3
|
||||
lotj.chat[keyword]:setWrap(charsPerLine)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
function lotj.chat.routeMessage(type)
|
||||
selectCurrentLine()
|
||||
copy()
|
||||
lotj.chat[type]:cecho("<reset>"..getTime(true, "hh:mm:ss").." ")
|
||||
lotj.chat[type]:appendBuffer()
|
||||
|
||||
lotj.chat.all:cecho("<reset>"..getTime(true, "hh:mm:ss").." ")
|
||||
lotj.chat.all:appendBuffer()
|
||||
end
|
5
src/scripts/chat/scripts.json
Normal file
5
src/scripts/chat/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "chat"
|
||||
}
|
||||
]
|
319
src/scripts/galaxy-map/galaxy-map.lua
Normal file
319
src/scripts/galaxy-map/galaxy-map.lua
Normal file
@ -0,0 +1,319 @@
|
||||
lotj = lotj or {}
|
||||
lotj.galaxyMap = lotj.galaxyMap or {
|
||||
data = {
|
||||
labelAsPlanets = true,
|
||||
systems = {},
|
||||
planets = {},
|
||||
govToColor = {
|
||||
["Neutral Government"] = "#AAAAAA",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
local dataFileName = getMudletHomeDir().."/galaxyMap"
|
||||
registerAnonymousEventHandler("lotjUICreated", function()
|
||||
lotj.galaxyMap.container = Geyser.Label:new({
|
||||
name = "galaxy",
|
||||
x = 0, y = 0,
|
||||
width = "100%",
|
||||
height = "100%",
|
||||
}, lotj.layout.upperRightTabData.contents["galaxy"])
|
||||
lotj.galaxyMap.container:setBackgroundImage(getMudletHomeDir().."/@PKGNAME@/space.jpg")
|
||||
|
||||
lotj.galaxyMap.refreshButton = Geyser.Label:new({
|
||||
name = "galaxyMapRefresh",
|
||||
x = "20%", y = "35%",
|
||||
width = "60%", height = 40,
|
||||
}, lotj.galaxyMap.container)
|
||||
lotj.galaxyMap.refreshButton:setStyleSheet([[
|
||||
background-color: grey;
|
||||
border: 1px solid white;
|
||||
]])
|
||||
lotj.galaxyMap.refreshButton:echo("Click here to populate this map.", "white", "c14")
|
||||
lotj.galaxyMap.refreshButton:setClickCallback(function()
|
||||
expandAlias("gmap refresh", false)
|
||||
end)
|
||||
|
||||
disableTrigger("galaxy-map-refresh")
|
||||
if io.exists(dataFileName) then
|
||||
table.load(dataFileName, lotj.galaxyMap.data)
|
||||
lotj.galaxyMap.log("Loaded map data.")
|
||||
lotj.galaxyMap.drawSystems()
|
||||
end
|
||||
|
||||
registerAnonymousEventHandler("msdp.SHIPGALY", lotj.galaxyMap.setShipGalCoords)
|
||||
end)
|
||||
|
||||
|
||||
function lotj.galaxyMap.log(text)
|
||||
cecho("[<cyan>LOTJ Galaxy Map<reset>] "..text.."\n")
|
||||
end
|
||||
|
||||
function lotj.galaxyMap.setShipGalCoords()
|
||||
-- Assume "0" in both values means we don't have valid coordinates and leave them what they were.
|
||||
-- TODO: Find a way to support a system actually located at 0, 0
|
||||
if msdp.SHIPGALX ~= "0" or msdp.SHIPGALY ~= "0" then
|
||||
lotj.galaxyMap.currentX = tonumber(msdp.SHIPGALX)
|
||||
lotj.galaxyMap.currentY = tonumber(msdp.SHIPGALY)
|
||||
lotj.galaxyMap.drawSystems()
|
||||
end
|
||||
end
|
||||
|
||||
local function container()
|
||||
return lotj.galaxyMap.container
|
||||
end
|
||||
|
||||
-- Fire off any showplanet commands we still need to run to load data for all known planets
|
||||
function lotj.galaxyMap.enqueuePendingRefreshCommands()
|
||||
for planet in pairs(gatherPlanetsState.pendingBasic) do
|
||||
send("showplanet \""..planet.."\"", false)
|
||||
gatherPlanetsState.pendingCommands = gatherPlanetsState.pendingCommands + 1
|
||||
end
|
||||
for planet in pairs(gatherPlanetsState.pendingResources) do
|
||||
send("showplanet \""..planet.."\" resources", false)
|
||||
gatherPlanetsState.pendingCommands = gatherPlanetsState.pendingCommands + 1
|
||||
end
|
||||
|
||||
-- We didn't have to retry any, so we're done getting info.
|
||||
if gatherPlanetsState.pendingCommands == 0 then
|
||||
disableTrigger("galaxy-map-refresh")
|
||||
return
|
||||
end
|
||||
|
||||
echo("\n")
|
||||
lotj.galaxyMap.log("Enqueueing "..gatherPlanetsState.pendingCommands.." showplanet commands.")
|
||||
end
|
||||
|
||||
function lotj.galaxyMap.resetData()
|
||||
lotj.galaxyMap.data.planets = {}
|
||||
lotj.galaxyMap.data.systems = {}
|
||||
end
|
||||
|
||||
local govColorIdx = 1
|
||||
local govColorList = {}
|
||||
table.insert(govColorList, "#E69F00")
|
||||
table.insert(govColorList, "#56B4E9")
|
||||
table.insert(govColorList, "#009E73")
|
||||
table.insert(govColorList, "#F0E442")
|
||||
table.insert(govColorList, "#D55E00")
|
||||
table.insert(govColorList, "#CC79A7")
|
||||
|
||||
function lotj.galaxyMap.recordSystem(name, x, y)
|
||||
lotj.galaxyMap.data.systems = lotj.galaxyMap.data.systems or {}
|
||||
lotj.galaxyMap.data.systems[name] = {
|
||||
name = name,
|
||||
planets = {},
|
||||
gov = "Neutral Government",
|
||||
x = x,
|
||||
y = y,
|
||||
}
|
||||
table.save(dataFileName, lotj.galaxyMap.data)
|
||||
|
||||
lotj.galaxyMap.drawSystems()
|
||||
end
|
||||
|
||||
function lotj.galaxyMap.recordPlanet(planetData)
|
||||
if not lotj.galaxyMap.data.planets[planetData.name] then
|
||||
lotj.galaxyMap.data.planets[planetData.name] = {
|
||||
name = planetData.name,
|
||||
gov = planetData.gov,
|
||||
system = planetData.system,
|
||||
}
|
||||
|
||||
local system = lotj.galaxyMap.data.systems[planetData.system]
|
||||
if system ~= nil then
|
||||
system.gov = planetData.gov
|
||||
table.insert(system.planets, planetData.name)
|
||||
else
|
||||
lotj.galaxyMap.log("Unable to find system "..planetData.system.." for planet "..planetData.name)
|
||||
end
|
||||
|
||||
if lotj.galaxyMap.data.govToColor[planetData.gov] == nil then
|
||||
govColorIdx = govColorIdx+1
|
||||
lotj.galaxyMap.data.govToColor[planetData.gov] = govColorList[govColorIdx]
|
||||
end
|
||||
end
|
||||
|
||||
if planetData.coords ~= nil then
|
||||
lotj.galaxyMap.data.planets[planetData.name].coords = planetData.coords
|
||||
end
|
||||
if planetData.freeport ~= nil then
|
||||
lotj.galaxyMap.data.planets[planetData.name].freeport = planetData.freeport
|
||||
end
|
||||
if planetData.taxRate ~= nil then
|
||||
lotj.galaxyMap.data.planets[planetData.name].taxRate = planetData.taxRate
|
||||
end
|
||||
if planetData.resources ~= nil then
|
||||
lotj.galaxyMap.data.planets[planetData.name].resources = planetData.resources
|
||||
end
|
||||
|
||||
table.save(dataFileName, lotj.galaxyMap.data)
|
||||
|
||||
lotj.galaxyMap.drawSystems()
|
||||
end
|
||||
|
||||
local systemPointSize = 14
|
||||
local function stylePoint(point, gov, currentSystem)
|
||||
local backgroundColor = lotj.galaxyMap.data.govToColor[gov] or "#AAAAAA"
|
||||
local borderStyle = ""
|
||||
if currentSystem then
|
||||
borderStyle = "border: 2px solid red;"
|
||||
end
|
||||
point:setStyleSheet([[
|
||||
border-radius: ]]..math.floor(systemPointSize/2)..[[px;
|
||||
background-color: ]]..backgroundColor..[[;
|
||||
]]..borderStyle..[[
|
||||
]])
|
||||
end
|
||||
|
||||
local function systemDisplayName(system)
|
||||
if lotj.galaxyMap.data.labelAsPlanets and #(system.planets or {}) > 0 then
|
||||
local labelString = ""
|
||||
for _, planet in ipairs(system.planets) do
|
||||
if #labelString > 0 then
|
||||
labelString = labelString..", "
|
||||
end
|
||||
labelString = labelString..planet
|
||||
end
|
||||
return labelString
|
||||
else
|
||||
-- Cut off common extra words from the system name to keep labels short
|
||||
local labelString = system.name
|
||||
labelString = string.gsub(labelString, " System$", "")
|
||||
labelString = string.gsub(labelString, " Sector$", "")
|
||||
return labelString
|
||||
end
|
||||
end
|
||||
|
||||
function lotj.galaxyMap.drawSystems()
|
||||
local minX, _, _, maxY = lotj.galaxyMap.coordRange()
|
||||
local xOffset, yOffset, pxPerCoord = lotj.galaxyMap.calculateSizing()
|
||||
|
||||
lotj.galaxyMap.systemPoints = lotj.galaxyMap.systemPoints or {}
|
||||
for _, point in pairs(lotj.galaxyMap.systemPoints) do
|
||||
point:hide()
|
||||
end
|
||||
|
||||
lotj.galaxyMap.systemLabels = lotj.galaxyMap.systemLabels or {}
|
||||
for _, label in pairs(lotj.galaxyMap.systemLabels) do
|
||||
label:hide()
|
||||
end
|
||||
|
||||
|
||||
local foundCurrentLocation = false
|
||||
local systemsToDraw = {}
|
||||
for _, system in pairs(lotj.galaxyMap.data.systems) do
|
||||
table.insert(systemsToDraw, system)
|
||||
if system.x == lotj.galaxyMap.currentX and system.y == lotj.galaxyMap.currentY then
|
||||
foundCurrentLocation = true
|
||||
end
|
||||
end
|
||||
if not foundCurrentLocation and lotj.galaxyMap.currentX and lotj.galaxyMap.currentY then
|
||||
table.insert(systemsToDraw, {
|
||||
name = "Current",
|
||||
x = lotj.galaxyMap.currentX,
|
||||
y = lotj.galaxyMap.currentY
|
||||
})
|
||||
end
|
||||
|
||||
-- Hide or show the refresh button accordingly, based on whether we have any data.
|
||||
if #systemsToDraw > 0 then
|
||||
lotj.galaxyMap.refreshButton:hide()
|
||||
else
|
||||
lotj.galaxyMap.refreshButton:show()
|
||||
end
|
||||
|
||||
for _, system in ipairs(systemsToDraw) do
|
||||
local point = lotj.galaxyMap.systemPoints[system.name]
|
||||
if point == nil then
|
||||
point = Geyser.Label:new({width=systemPointSize, height=systemPointSize}, container())
|
||||
stylePoint(point, system.gov, false)
|
||||
lotj.galaxyMap.systemPoints[system.name] = point
|
||||
else
|
||||
point:show()
|
||||
end
|
||||
|
||||
local label = lotj.galaxyMap.systemLabels[system.name]
|
||||
if label == nil then
|
||||
label = Geyser.Label:new({
|
||||
height = 16, width = 100,
|
||||
fillBg = 0,
|
||||
}, container())
|
||||
|
||||
lotj.galaxyMap.systemLabels[system.name] = label
|
||||
else
|
||||
label:show()
|
||||
end
|
||||
label:echo(systemDisplayName(system), "white", "12c")
|
||||
|
||||
local sysX = math.floor(xOffset + (system.x-minX)*pxPerCoord - systemPointSize/2 + 0.5)
|
||||
local sysY = math.floor(yOffset + (maxY-system.y)*pxPerCoord - systemPointSize/2 + 0.5)
|
||||
point:move(sysX, sysY)
|
||||
if system.x == lotj.galaxyMap.currentX and system.y == lotj.galaxyMap.currentY then
|
||||
stylePoint(point, system.gov, true)
|
||||
else
|
||||
stylePoint(point, system.gov, false)
|
||||
end
|
||||
|
||||
label:move(math.max(sysX-45, 0), sysY+systemPointSize)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns X starting point, Y starting point, and pixels per coordinate
|
||||
function lotj.galaxyMap.calculateSizing()
|
||||
local minX, maxX, minY, maxY = lotj.galaxyMap.coordRange()
|
||||
local xRange = maxX-minX
|
||||
local yRange = maxY-minY
|
||||
local contWidth = container():get_width()
|
||||
local contHeight = container():get_height()
|
||||
|
||||
-- Determine whether the map would be limited by height or width first.
|
||||
local mapWidth = nil
|
||||
local mapHeight = nil
|
||||
local pxPerCoord = nil
|
||||
local pxHeightIfLimitedByWidth = (contWidth/xRange)*yRange
|
||||
local pxWidthIfLimitedByHeight = (contHeight/yRange)*xRange
|
||||
if pxHeightIfLimitedByWidth <= contHeight then
|
||||
-- Width was the limiting factor, so use it to determine sizing
|
||||
mapWidth = contWidth
|
||||
mapHeight = pxHeightIfLimitedByWidth
|
||||
pxPerCoord = contWidth/xRange
|
||||
elseif pxWidthIfLimitedByHeight <= contWidth then
|
||||
-- Width was the limiting factor, so use it to determine sizing
|
||||
mapWidth = pxWidthIfLimitedByHeight
|
||||
mapHeight = contHeight
|
||||
pxPerCoord = contHeight/yRange
|
||||
else
|
||||
echo("Unable to determine appropriate galaxy map dimensions. This is a script bug.\n")
|
||||
end
|
||||
|
||||
local mapAnchorX = (contWidth-mapWidth)/2
|
||||
local mapAnchorY = (contHeight-mapHeight)/2
|
||||
|
||||
return mapAnchorX, mapAnchorY, pxPerCoord
|
||||
end
|
||||
|
||||
function lotj.galaxyMap.coordRange()
|
||||
local minX = 0
|
||||
local maxX = 0
|
||||
local minY = 0
|
||||
local maxY = 0
|
||||
|
||||
for _, system in pairs(lotj.galaxyMap.data.systems) do
|
||||
if minX > system.x then
|
||||
minX = system.x
|
||||
end
|
||||
if maxX < system.x then
|
||||
maxX = system.x
|
||||
end
|
||||
if minY > system.y then
|
||||
minY = system.y
|
||||
end
|
||||
if maxY < system.y then
|
||||
maxY = system.y
|
||||
end
|
||||
end
|
||||
|
||||
-- Pad all values by 10 to ensure points are displayed reasonably.
|
||||
return minX-10, maxX+10, minY-10, maxY+10
|
||||
end
|
5
src/scripts/galaxy-map/scripts.json
Normal file
5
src/scripts/galaxy-map/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "galaxy-map"
|
||||
}
|
||||
]
|
369
src/scripts/info-panel/info-panel.lua
Normal file
369
src/scripts/info-panel/info-panel.lua
Normal file
@ -0,0 +1,369 @@
|
||||
lotj = lotj or {}
|
||||
lotj.infoPanel = lotj.infoPanel or {}
|
||||
|
||||
|
||||
registerAnonymousEventHandler("lotjUICreated", function()
|
||||
local basicStatsContainer = Geyser.Label:new({
|
||||
h_stretch_factor = 0.9
|
||||
}, lotj.layout.lowerInfoPanel)
|
||||
local combatContainer = Geyser.Label:new({
|
||||
h_stretch_factor = 0.9
|
||||
}, lotj.layout.lowerInfoPanel)
|
||||
local chatContainer = Geyser.Label:new({
|
||||
h_stretch_factor = 1
|
||||
}, lotj.layout.lowerInfoPanel)
|
||||
local spaceContainer = Geyser.Label:new({
|
||||
h_stretch_factor = 2.2
|
||||
}, lotj.layout.lowerInfoPanel)
|
||||
|
||||
lotj.infoPanel.createBasicStats(basicStatsContainer)
|
||||
lotj.infoPanel.createOpponentStats(combatContainer)
|
||||
lotj.infoPanel.createChatInfo(chatContainer)
|
||||
lotj.infoPanel.createSpaceStats(spaceContainer)
|
||||
end)
|
||||
|
||||
|
||||
-- Utility functions
|
||||
local function gaugeFrontStyle(step1, step2, step3, step4, step5)
|
||||
return [[
|
||||
background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 ]]..step1..[[, stop: 0.1 ]]..step2..[[, stop: 0.49 ]]..step3..[[, stop: 0.5 ]]..step4..[[, stop: 1 ]]..step5..[[);
|
||||
border-top: 1px black solid;
|
||||
border-left: 1px black solid;
|
||||
border-bottom: 1px black solid;
|
||||
padding: 3px;
|
||||
]]
|
||||
end
|
||||
|
||||
local function gaugeBackStyle(step1, step2, step3, step4, step5)
|
||||
return [[
|
||||
background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 ]]..step1..[[, stop: 0.1 ]]..step2..[[, stop: 0.49 ]]..step3..[[, stop: 0.5 ]]..step4..[[, stop: 1 ]]..step5..[[);
|
||||
border-width: 1px;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
padding: 3px;
|
||||
]]
|
||||
end
|
||||
|
||||
local function styleGaugeText(gauge, fontSize)
|
||||
gauge.text:setStyleSheet([[
|
||||
padding-right: 10px;
|
||||
]])
|
||||
gauge:setAlignment("r")
|
||||
gauge:setFontSize(fontSize)
|
||||
end
|
||||
|
||||
-- Wires up MSDP subscriptions for a gauge.
|
||||
-- statName is the short version of the stat name to show after the value (mv, hp, etc)
|
||||
local function wireGaugeUpdate(gauge, valueVarName, maxVarName, statName)
|
||||
local function doUpdate()
|
||||
local current = tonumber(msdp[valueVarName] or "0")
|
||||
local max = tonumber(msdp[maxVarName] or "0")
|
||||
if max > 0 then
|
||||
gauge:setValue(current, max, current.."/"..max.." "..statName)
|
||||
else
|
||||
gauge:setValue(0, 1, "")
|
||||
end
|
||||
end
|
||||
registerAnonymousEventHandler("msdp."..valueVarName, doUpdate)
|
||||
registerAnonymousEventHandler("msdp."..maxVarName, doUpdate)
|
||||
end
|
||||
|
||||
|
||||
function lotj.infoPanel.createBasicStats(container)
|
||||
-- Health gauge
|
||||
local healthGauge = Geyser.Gauge:new({
|
||||
x="5%", y=4,
|
||||
width="90%", height=16,
|
||||
}, container)
|
||||
healthGauge.front:setStyleSheet(gaugeFrontStyle("#f04141", "#ef2929", "#cc0000", "#a40000", "#cc0000"))
|
||||
healthGauge.back:setStyleSheet(gaugeBackStyle("#3f1111", "#3f0707", "#330000", "#220000", "#330000"))
|
||||
styleGaugeText(healthGauge, 12)
|
||||
wireGaugeUpdate(healthGauge, "HEALTH", "HEALTHMAX", "hp")
|
||||
|
||||
local wimpyBar = Geyser.Label:new({
|
||||
x=0, y=0,
|
||||
width=2, height="100%",
|
||||
}, healthGauge.front)
|
||||
wimpyBar:setStyleSheet([[
|
||||
background-color: yellow;
|
||||
]])
|
||||
|
||||
registerAnonymousEventHandler("msdp.WIMPY", function()
|
||||
local health = tonumber(msdp.HEALTH or 0)
|
||||
local healthMax = tonumber(msdp.HEALTHMAX or 0)
|
||||
local wimpy = tonumber(msdp.WIMPY or 0)
|
||||
if healthMax > 0 then
|
||||
if wimpy > 0 and health > 0 and wimpy < health then
|
||||
wimpyBar:show()
|
||||
wimpyBar:move(math.floor(wimpy*100/health).."%", nil)
|
||||
else
|
||||
wimpyBar:hide()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Movement gauge
|
||||
local movementGauge = Geyser.Gauge:new({
|
||||
x="5%", y=23,
|
||||
width="90%", height=16,
|
||||
}, container)
|
||||
movementGauge.front:setStyleSheet(gaugeFrontStyle("#41f041", "#29ef29", "#00cc00", "#00a400", "#00cc00"))
|
||||
movementGauge.back:setStyleSheet(gaugeBackStyle("#113f11", "#073f07", "#003300", "#002200", "#003300"))
|
||||
styleGaugeText(movementGauge, 12)
|
||||
wireGaugeUpdate(movementGauge, "MOVEMENT", "MOVEMENTMAX", "mv")
|
||||
|
||||
-- Mana gauge (will be hidden later if we do not have mana)
|
||||
local manaGauge = Geyser.Gauge:new({
|
||||
x="5%", y=42,
|
||||
width="90%", height=16,
|
||||
}, container)
|
||||
manaGauge.front:setStyleSheet(gaugeFrontStyle("#4141f0", "#2929ef", "#0000cc", "#0000a4", "#0000cc"))
|
||||
manaGauge.back:setStyleSheet(gaugeBackStyle("#11113f", "#07073f", "#000033", "#000022", "#000011"))
|
||||
styleGaugeText(manaGauge, 12)
|
||||
wireGaugeUpdate(manaGauge, "MANA", "MANAMAX", "mn")
|
||||
|
||||
registerAnonymousEventHandler("msdp.MANAMAX", function()
|
||||
local manaMax = tonumber(msdp.MANAMAX or 0)
|
||||
if manaMax > 0 then
|
||||
healthGauge:move(nil, 4)
|
||||
healthGauge:resize(nil, 16)
|
||||
healthGauge:setFontSize("12")
|
||||
|
||||
movementGauge:move(nil, 23)
|
||||
movementGauge:resize(nil, 16)
|
||||
movementGauge:setFontSize("12")
|
||||
|
||||
manaGauge:show()
|
||||
manaGauge:move(nil, 42)
|
||||
manaGauge:resize(nil, 16)
|
||||
manaGauge:setFontSize("12")
|
||||
else
|
||||
healthGauge:move(nil, 6)
|
||||
healthGauge:resize(nil, 22)
|
||||
healthGauge:setFontSize("13")
|
||||
|
||||
movementGauge:move(nil, 32)
|
||||
movementGauge:resize(nil, 22)
|
||||
movementGauge:setFontSize("13")
|
||||
|
||||
manaGauge:hide()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
function lotj.infoPanel.createOpponentStats(container)
|
||||
-- Opponent health gauge
|
||||
local opponentGauge = Geyser.Gauge:new({
|
||||
x="5%", y=6,
|
||||
width="90%", height=48,
|
||||
}, container)
|
||||
opponentGauge.front:setStyleSheet(gaugeFrontStyle("#bd7833", "#bd6e20", "#994c00", "#703800", "#994c00"))
|
||||
opponentGauge.back:setStyleSheet(gaugeBackStyle("#442511", "#441d08", "#331100", "#200900", "#331100"))
|
||||
opponentGauge.text:setStyleSheet("padding: 10px;")
|
||||
opponentGauge:setAlignment("c")
|
||||
opponentGauge:setFontSize("12")
|
||||
|
||||
local function update()
|
||||
local opponentName = string.gsub(msdp.OPPONENTNAME or "", "&.", "")
|
||||
-- Opponent name seems to always be empty string even when fighting, so fall back to something reasonable
|
||||
if opponentName == "" then
|
||||
opponentName = "Current target"
|
||||
end
|
||||
local opponentHealth = tonumber(msdp.OPPONENTHEALTH or "0")
|
||||
local opponentHealthMax = tonumber(msdp.OPPONENTHEALTHMAX or "0")
|
||||
if opponentHealth > 0 then
|
||||
opponentGauge:setValue(opponentHealth, opponentHealthMax, opponentName.."<br>"..opponentHealth.."%")
|
||||
else
|
||||
opponentGauge:setValue(0, 1, "Not fighting")
|
||||
end
|
||||
end
|
||||
registerAnonymousEventHandler("msdp.OPPONENTNAME", update)
|
||||
registerAnonymousEventHandler("msdp.OPPONENTHEALTH", update)
|
||||
registerAnonymousEventHandler("msdp.OPPONENTHEALTHMAX", update)
|
||||
end
|
||||
|
||||
|
||||
function lotj.infoPanel.createChatInfo(container)
|
||||
-- Commnet channel/code
|
||||
local commnetLabel = Geyser.Label:new({
|
||||
x="3%", y=6,
|
||||
width="20%", height=24,
|
||||
}, container)
|
||||
commnetLabel:echo("Comm:", nil, "rb13")
|
||||
local commnetInfo = Geyser.Label:new({
|
||||
x = "25%", y = 6,
|
||||
width = "75%", height = 24
|
||||
}, container)
|
||||
|
||||
local function updateCommnet()
|
||||
local commChannel = msdp.COMMCHANNEL or "0"
|
||||
local commEncrypt = msdp.COMMENCRYPT or "0"
|
||||
if commEncrypt == "0" then
|
||||
commnetInfo:echo(commChannel, nil, "l13")
|
||||
else
|
||||
commnetInfo:echo(commChannel.." (E "..commEncrypt..")", nil, "l13")
|
||||
end
|
||||
end
|
||||
registerAnonymousEventHandler("msdp.COMMCHANNEL", updateCommnet)
|
||||
registerAnonymousEventHandler("msdp.COMMENCRYPT", updateCommnet)
|
||||
|
||||
-- OOC meter
|
||||
local oocLabel = Geyser.Label:new({
|
||||
x="3%", y=32,
|
||||
width="20%", height=24,
|
||||
}, container)
|
||||
oocLabel:echo("OOC:", nil, "rb13")
|
||||
local oocGauge = Geyser.Gauge:new({
|
||||
x="25%", y=32,
|
||||
width="40%", height=20,
|
||||
}, container)
|
||||
oocGauge.front:setStyleSheet(gaugeFrontStyle("#31d0d0", "#22cfcf", "#00b2b2", "#009494", "#00b2b2"))
|
||||
oocGauge.back:setStyleSheet(gaugeBackStyle("#113f3f", "#073f3f", "#003333", "#002222", "#001111"))
|
||||
|
||||
registerAnonymousEventHandler("msdp.OOCLIMIT", function()
|
||||
local oocLeft = tonumber(msdp.OOCLIMIT or 0)
|
||||
local oocMax = 6
|
||||
oocGauge:setValue(oocLeft, oocMax)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
function lotj.infoPanel.createSpaceStats(container)
|
||||
local energyGauge = Geyser.Gauge:new({
|
||||
x="3%", y=4,
|
||||
width="30%", height=16,
|
||||
}, container)
|
||||
energyGauge.front:setStyleSheet(gaugeFrontStyle("#7a7a7a", "#777777", "#656565", "#505050", "#656565"))
|
||||
energyGauge.back:setStyleSheet(gaugeBackStyle("#383838", "#303030", "#222222", "#151515", "#222222"))
|
||||
styleGaugeText(energyGauge, 12)
|
||||
wireGaugeUpdate(energyGauge, "SHIPENERGY", "SHIPMAXENERGY", "en")
|
||||
|
||||
local hullGauge = Geyser.Gauge:new({
|
||||
x="3%", y=23,
|
||||
width="30%", height=16,
|
||||
}, container)
|
||||
hullGauge.front:setStyleSheet(gaugeFrontStyle("#bd7833", "#bd6e20", "#994c00", "#703800", "#994c00"))
|
||||
hullGauge.back:setStyleSheet(gaugeBackStyle("#442511", "#441d08", "#331100", "#200900", "#331100"))
|
||||
styleGaugeText(hullGauge, 12)
|
||||
wireGaugeUpdate(hullGauge, "SHIPHULL", "SHIPMAXHULL", "hl")
|
||||
|
||||
local shieldGauge = Geyser.Gauge:new({
|
||||
x="3%", y=42,
|
||||
width="30%", height=16,
|
||||
}, container)
|
||||
shieldGauge.front:setStyleSheet(gaugeFrontStyle("#31d0d0", "#22cfcf", "#00b2b2", "#009494", "#00b2b2"))
|
||||
shieldGauge.back:setStyleSheet(gaugeBackStyle("#113f3f", "#073f3f", "#003333", "#002222", "#001111"))
|
||||
styleGaugeText(shieldGauge, 12)
|
||||
wireGaugeUpdate(shieldGauge, "SHIPSHIELD", "SHIPMAXSHIELD", "sh")
|
||||
|
||||
|
||||
-- Piloting indicator
|
||||
local pilotLabel = Geyser.Label:new({
|
||||
x="35%", y=6,
|
||||
width="13%", height=24
|
||||
}, container)
|
||||
pilotLabel:echo("Pilot:", nil, "lb12")
|
||||
|
||||
local pilotBoxCont = Geyser.Label:new({
|
||||
x="48%", y=10,
|
||||
width="8%", height=16
|
||||
}, container)
|
||||
local pilotBox = Geyser.Label:new({
|
||||
x=2, y=0,
|
||||
width=16, height=16
|
||||
}, pilotBoxCont)
|
||||
|
||||
registerAnonymousEventHandler("msdp.PILOTING", function()
|
||||
local piloting = tonumber(msdp.PILOTING or "0")
|
||||
if piloting == 1 then
|
||||
pilotBox:setStyleSheet("background-color: #29efef; border: 2px solid #eeeeee;")
|
||||
else
|
||||
pilotBox:setStyleSheet("background-color: #073f3f; border: 2px solid #eeeeee;")
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
local speedGauge = Geyser.Label:new({
|
||||
x="56%", y=6,
|
||||
width="19%", height=24,
|
||||
}, container)
|
||||
|
||||
local function updateSpeed()
|
||||
local speed = tonumber(msdp.SHIPSPEED or "0")
|
||||
local maxSpeed = tonumber(msdp.SHIPMAXSPEED or "0")
|
||||
speedGauge:echo("<b>Sp:</b> "..speed.."<b>/</b>"..maxSpeed, nil, "l12")
|
||||
end
|
||||
registerAnonymousEventHandler("msdp.SHIPSPEED", updateSpeed)
|
||||
registerAnonymousEventHandler("msdp.SHIPMAXSPEED", updateSpeed)
|
||||
|
||||
|
||||
local coordsInfo = Geyser.Label:new({
|
||||
x="35%", y=32,
|
||||
width="40%", height=24,
|
||||
}, container)
|
||||
|
||||
local function updateCoords()
|
||||
local shipX = tonumber(msdp.SHIPSYSX or "0")
|
||||
local shipY = tonumber(msdp.SHIPSYSY or "0")
|
||||
local shipZ = tonumber(msdp.SHIPSYSZ or "0")
|
||||
coordsInfo:echo("<b>Coords:</b> "..shipX.." "..shipY.." "..shipZ, nil, "l12")
|
||||
end
|
||||
registerAnonymousEventHandler("msdp.SHIPSYSX", updateCoords)
|
||||
registerAnonymousEventHandler("msdp.SHIPSYSY", updateCoords)
|
||||
registerAnonymousEventHandler("msdp.SHIPSYSZ", updateCoords)
|
||||
|
||||
lotj.infoPanel.spaceTickCounter = Geyser.Label:new({
|
||||
x="77%", y=6,
|
||||
width="20%", height=24,
|
||||
}, container)
|
||||
|
||||
lotj.infoPanel.chaffIndicator = Geyser.Label:new({
|
||||
x="77%", y=32,
|
||||
width="20%", height=24,
|
||||
}, container)
|
||||
lotj.infoPanel.chaffIndicator:echo("[Chaff]", "yellow", "c13b")
|
||||
lotj.infoPanel.chaffIndicator:hide()
|
||||
end
|
||||
|
||||
-- Sets up timers to refresh the space tick counter
|
||||
function lotj.infoPanel.markSpaceTick()
|
||||
for _, timerId in ipairs(lotj.infoPanel.spaceTickTimers or {}) do
|
||||
killTimer(timerId)
|
||||
end
|
||||
|
||||
lotj.infoPanel.spaceTickCounter:show()
|
||||
lotj.infoPanel.spaceTickTimers = {}
|
||||
for i = 0,20,1 do
|
||||
local timerId = tempTimer(i, function()
|
||||
lotj.infoPanel.spaceTickCounter:echo("<b>Tick:</b> "..20-i, nil, "c13")
|
||||
end)
|
||||
table.insert(lotj.infoPanel.spaceTickTimers, timerId)
|
||||
end
|
||||
|
||||
-- A few seconds after the next tick should happen, hide the counter.
|
||||
-- This will be canceled if we see another tick before then.
|
||||
local timerId = tempTimer(23, function()
|
||||
lotj.infoPanel.spaceTickCounter:hide()
|
||||
end)
|
||||
table.insert(lotj.infoPanel.spaceTickTimers, timerId)
|
||||
end
|
||||
|
||||
function lotj.infoPanel.markChaff()
|
||||
lotj.infoPanel.clearChaff()
|
||||
lotj.infoPanel.chaffIndicator:show()
|
||||
|
||||
-- In case we miss the "chaff cleared" message somehow, set a 20 second timer to get rid of this
|
||||
lotj.infoPanel.chaffTimer = tempTimer(20, function()
|
||||
lotj.infoPanel.clearChaff()
|
||||
end)
|
||||
end
|
||||
|
||||
function lotj.infoPanel.clearChaff()
|
||||
if lotj.infoPanel.chaffTimer ~= nil then
|
||||
killTimer(lotj.infoPanel.chaffTimer)
|
||||
lotj.infoPanel.chaffTimer = nil
|
||||
end
|
||||
|
||||
lotj.infoPanel.chaffIndicator:hide()
|
||||
end
|
5
src/scripts/info-panel/scripts.json
Normal file
5
src/scripts/info-panel/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "info-panel"
|
||||
}
|
||||
]
|
140
src/scripts/layout/layout.lua
Normal file
140
src/scripts/layout/layout.lua
Normal file
@ -0,0 +1,140 @@
|
||||
lotj = lotj or {}
|
||||
lotj.layout = lotj.layout or {}
|
||||
|
||||
local rightPanelWidthPct = 40
|
||||
local upperRightHeightPct = 50
|
||||
|
||||
local inactiveTabStyle = [[
|
||||
background-color: #333333;
|
||||
border: 1px solid #00aaaa;
|
||||
margin: 3px 3px 0px 3px;
|
||||
font-family: "Bitstream Vera Sans Mono";
|
||||
]]
|
||||
|
||||
local activeTabStyle = [[
|
||||
background-color: #336666;
|
||||
border: 1px solid #00aaaa;
|
||||
border-bottom: none;
|
||||
margin: 3px 3px 0px 3px;
|
||||
font-family: "Bitstream Vera Sans Mono";
|
||||
]]
|
||||
|
||||
|
||||
local function createTabbedPanel(tabData, container, tabList)
|
||||
tabData.tabs = {}
|
||||
tabData.contents = {}
|
||||
|
||||
local tabContainer = Geyser.HBox:new({
|
||||
x = "2%", y = 0,
|
||||
width = "96%", height = 30,
|
||||
}, container)
|
||||
|
||||
local contentsContainer = Geyser.Label:new({
|
||||
x = 0, y = 30,
|
||||
width = "100%",
|
||||
}, container)
|
||||
|
||||
lotj.layout.resizeTabContents(container, tabContainer, contentsContainer)
|
||||
registerAnonymousEventHandler("sysWindowResizeEvent", function()
|
||||
lotj.layout.resizeTabContents(container, tabContainer, contentsContainer)
|
||||
end)
|
||||
|
||||
for _, tabInfo in ipairs(tabList) do
|
||||
local keyword = tabInfo.keyword
|
||||
local label = tabInfo.label
|
||||
|
||||
tabData.tabs[keyword] = Geyser.Label:new({}, tabContainer)
|
||||
tabData.tabs[keyword]:setClickCallback("lotj.layout.selectTab", tabData, keyword)
|
||||
tabData.tabs[keyword]:setFontSize(12)
|
||||
tabData.tabs[keyword]:echo("<center>"..label)
|
||||
|
||||
tabData.contents[keyword] = Geyser.Label:new({
|
||||
x = 0, y = 0,
|
||||
width = "100%",
|
||||
height = "100%",
|
||||
}, contentsContainer)
|
||||
end
|
||||
end
|
||||
|
||||
function lotj.layout.selectTab(tabData, tabName)
|
||||
for _, tab in pairs(tabData.tabs) do
|
||||
tab:setStyleSheet(inactiveTabStyle)
|
||||
tab:setBold(false)
|
||||
end
|
||||
for _, contents in pairs(tabData.contents) do
|
||||
contents:hide()
|
||||
end
|
||||
|
||||
tabData.tabs[tabName]:setStyleSheet(activeTabStyle)
|
||||
tabData.tabs[tabName]:setBold(true)
|
||||
tabData.contents[tabName]:show()
|
||||
end
|
||||
|
||||
function lotj.layout.resizeTabContents(parentContainer, tabContainer, contentsContainer)
|
||||
local newHeight = parentContainer:get_height()-tabContainer:get_height()
|
||||
contentsContainer:resize(nil, newHeight)
|
||||
end
|
||||
|
||||
|
||||
registerAnonymousEventHandler("sysLoadEvent", function()
|
||||
local rightPanel = Geyser.Container:new({
|
||||
width = rightPanelWidthPct.."%",
|
||||
x = (100-rightPanelWidthPct).."%",
|
||||
y = 0, height = "100%",
|
||||
})
|
||||
registerAnonymousEventHandler("sysWindowResizeEvent", function()
|
||||
local newBorder = math.floor(rightPanel:get_width())
|
||||
if getBorderRight() ~= newBorder then
|
||||
setBorderRight(newBorder)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-- Upper-right pane, for maps
|
||||
local upperContainer = Geyser.Container:new({
|
||||
x = 0, y = 0,
|
||||
width = "100%",
|
||||
height = upperRightHeightPct.."%",
|
||||
}, rightPanel)
|
||||
|
||||
local upperTabList = {}
|
||||
table.insert(upperTabList, {keyword = "map", label = "Map"})
|
||||
table.insert(upperTabList, {keyword = "system", label = "System"})
|
||||
table.insert(upperTabList, {keyword = "galaxy", label = "Galaxy"})
|
||||
|
||||
lotj.layout.upperRightTabData = {}
|
||||
createTabbedPanel(lotj.layout.upperRightTabData, upperContainer, upperTabList)
|
||||
|
||||
|
||||
-- Lower-right panel, for chat history
|
||||
local lowerContainer = Geyser.Container:new({
|
||||
x = 0, y = upperRightHeightPct.."%",
|
||||
width = "100%",
|
||||
height = (100-upperRightHeightPct).."%",
|
||||
}, rightPanel)
|
||||
|
||||
local lowerTabList = {}
|
||||
table.insert(lowerTabList, {keyword = "all", label = "All"})
|
||||
table.insert(lowerTabList, {keyword = "commnet", label = "CommNet"})
|
||||
table.insert(lowerTabList, {keyword = "clan", label = "Clan"})
|
||||
table.insert(lowerTabList, {keyword = "ooc", label = "OOC"})
|
||||
table.insert(lowerTabList, {keyword = "tell", label = "Tell"})
|
||||
table.insert(lowerTabList, {keyword = "imm", label = "Imm"})
|
||||
|
||||
lotj.layout.lowerRightTabData = {}
|
||||
createTabbedPanel(lotj.layout.lowerRightTabData, lowerContainer, lowerTabList)
|
||||
|
||||
|
||||
-- Lower info panel, for prompt hp/move gauges and other basic status
|
||||
lotj.layout.lowerInfoPanel = Geyser.HBox:new({
|
||||
x = 0, y = -60,
|
||||
width = (100-rightPanelWidthPct).."%",
|
||||
height = 60,
|
||||
})
|
||||
setBorderBottom(60)
|
||||
|
||||
raiseEvent("lotjUICreated")
|
||||
|
||||
lotj.layout.selectTab(lotj.layout.upperRightTabData, "map")
|
||||
lotj.layout.selectTab(lotj.layout.lowerRightTabData, "all")
|
||||
end)
|
5
src/scripts/layout/scripts.json
Normal file
5
src/scripts/layout/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "layout"
|
||||
}
|
||||
]
|
527
src/scripts/mapper/mapper.lua
Normal file
527
src/scripts/mapper/mapper.lua
Normal file
@ -0,0 +1,527 @@
|
||||
mudlet = mudlet or {}; mudlet.mapper_script = true
|
||||
lotj = lotj or {}
|
||||
lotj.mapper = lotj.mapper or {}
|
||||
|
||||
|
||||
local dirs = {}
|
||||
-- The order of these is important. The indices of the directions must match
|
||||
-- https://github.com/Mudlet/Mudlet/blob/9c13f8f946f5b82c0c2e817dab5f42588cee17e0/src/TRoom.h#L38
|
||||
table.insert(dirs, {short="n", long="north", rev="s", xyzDiff = { 0, 1, 0}})
|
||||
table.insert(dirs, {short="ne", long="northeast", rev="sw", xyzDiff = { 1, 1, 0}})
|
||||
table.insert(dirs, {short="nw", long="northwest", rev="se", xyzDiff = {-1, 1, 0}})
|
||||
table.insert(dirs, {short="e", long="east", rev="w", xyzDiff = { 1, 0, 0}})
|
||||
table.insert(dirs, {short="w", long="west", rev="e", xyzDiff = {-1, 0, 0}})
|
||||
table.insert(dirs, {short="s", long="south", rev="n", xyzDiff = { 0,-1, 0}})
|
||||
table.insert(dirs, {short="se", long="southeast", rev="nw", xyzDiff = { 1,-1, 0}})
|
||||
table.insert(dirs, {short="sw", long="southwest", rev="ne", xyzDiff = {-1,-1, 0}})
|
||||
table.insert(dirs, {short="u", long="up", rev="d", xyzDiff = { 0, 0, 1}})
|
||||
table.insert(dirs, {short="d", long="down", rev="u", xyzDiff = { 0, 0,-1}})
|
||||
|
||||
-- Given a direction short or long name, or a direction number, return an object representing it.
|
||||
local function dirObj(arg)
|
||||
if dirs[arg] ~= nil then
|
||||
return dirs[arg]
|
||||
end
|
||||
|
||||
for _, dir in ipairs(dirs) do
|
||||
if arg == dir.short or arg == dir.long then
|
||||
return dir
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Given a direction short or long name, or a direction number, return an object representing its opposite
|
||||
local function revDirObj(arg)
|
||||
local dir = dirObj(arg)
|
||||
if dir ~= nil then
|
||||
return dirObj(dir.rev)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Configuration of an amenity name to the environment code to use on rooms with it
|
||||
local amenityEnvCodes = {
|
||||
bacta = 269,
|
||||
bank = 267,
|
||||
broadcast = 270,
|
||||
hotel = 265,
|
||||
library = 261,
|
||||
locker = 263,
|
||||
package = 262,
|
||||
workshop = 266,
|
||||
}
|
||||
|
||||
local function trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Command Handlers
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Main "map" command handler
|
||||
function lotj.mapper.mapCommand(input)
|
||||
input = trim(input)
|
||||
if #input == 0 then
|
||||
lotj.mapper.printMainMenu()
|
||||
return
|
||||
end
|
||||
|
||||
_, _, cmd, args = string.find(input, "([^%s]+)%s*(.*)")
|
||||
cmd = string.lower(cmd)
|
||||
|
||||
if cmd == "help" then
|
||||
lotj.mapper.printHelp()
|
||||
elseif cmd == "start" then
|
||||
lotj.mapper.startMapping(args)
|
||||
elseif cmd == "stop" then
|
||||
lotj.mapper.stopMapping()
|
||||
elseif cmd == "deletearea" then
|
||||
lotj.mapper.deleteArea(args)
|
||||
elseif cmd == "shift" then
|
||||
lotj.mapper.shiftCurrentRoom(args)
|
||||
elseif cmd == "save" then
|
||||
lotj.mapper.saveMap()
|
||||
else
|
||||
lotj.mapper.logError("Unknown map command. Try <yellow>map help<reset>.")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.printMainMenu()
|
||||
lotj.mapper.log("Mapper Introduction and Status")
|
||||
cecho([[
|
||||
|
||||
The LOTJ Mapper plugin tracks movement using MSDP variables. To begin, try <yellow>map start <current area><reset>.
|
||||
Once mapping is started, move <red>slowly<reset> between rooms to map them. Moving too quickly will cause the
|
||||
mapper to skip rooms. You should wait for the map to reflect your movements before moving again
|
||||
whenever you are in mapping mode.
|
||||
|
||||
When you are finished mapping, use <yellow>map stop<reset> to stop recording your movements, and be sure to
|
||||
<yellow>map save<reset>! Map data will not be saved automatically.
|
||||
|
||||
Other commands are available to adjust mapping as you go. <yellow>map shift <direction><reset>, for example,
|
||||
will move your current room. See <yellow>map help<reset> for a full list of available commands.
|
||||
|
||||
The map GUI also offers editing functionality and is ideal for moving groups of rooms, deleting
|
||||
or coloring rooms, etc.
|
||||
|
||||
]])
|
||||
|
||||
if lotj.mapper.mappingArea ~= nil then
|
||||
cecho("Mapper status: <green>Mapping<reset> in area <yellow>"..lotj.mapper.mappingArea.."<reset>\n")
|
||||
else
|
||||
cecho("Mapper status: <red>Off<reset>\n")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.printHelp()
|
||||
lotj.mapper.log("Mapper Command List")
|
||||
cecho([[
|
||||
|
||||
<yellow>map start <area name><reset>
|
||||
|
||||
Begin mapping. Any new rooms you enter while mapping will be added to this area name, so you
|
||||
should be sure to stop mapping before entering a ship or moving to a different zone.
|
||||
|
||||
Some tips to remember:
|
||||
- <white>Move slowly<reset>, and wait for the map to reflect your movements before going to the next room.
|
||||
The MUD sends data about your current room after some delay, so moving too fast will make the
|
||||
mapper skip rooms or draw exits which aren't there.
|
||||
- Use a light while mapping. Entering a dark room where you can't see will not update the map.
|
||||
- Use <yellow>map shift<reset> to adjust room positioning, especially after going through turbolifts or
|
||||
voice-activated doors. It's faster to click-and-drag with the GUI to move large blocks of
|
||||
rooms, though.
|
||||
- Rooms in ships are all unique, even if they are the same model. In practice, mapping ships
|
||||
really isn't supported yet, although platforms or ships you use frequently may be worth it.
|
||||
|
||||
<yellow>map stop<reset>
|
||||
|
||||
Stop editing the map based on your movements.
|
||||
|
||||
<yellow>map save<reset>
|
||||
|
||||
Save the map to the map.dat file in your Mudlet profile's directory.
|
||||
|
||||
<yellow>map deletearea <area name><reset>
|
||||
|
||||
Deletes all data for an area. There's no confirmation and no undo!
|
||||
|
||||
<yellow>map shift <direction><reset>
|
||||
|
||||
Moves the current room in whichever direction you enter. Useful for adjusting placement of
|
||||
rooms when you need to space them out.
|
||||
]])
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.startMapping(areaName)
|
||||
areaName = trim(areaName)
|
||||
if #areaName == 0 then
|
||||
lotj.mapper.log("Syntax: map start <yellow><area name><reset>")
|
||||
return
|
||||
end
|
||||
|
||||
if lotj.mapper.mappingArea ~= nil then
|
||||
lotj.mapper.logError("Mapper already running in <yellow>"..lotj.mapper.mappingArea.."<reset>.")
|
||||
return
|
||||
end
|
||||
|
||||
local areaTable = getAreaTable()
|
||||
if areaTable[areaName] == nil then
|
||||
addAreaName(areaName)
|
||||
lotj.mapper.log("Mapping in new area <yellow>"..areaName.."<reset>.")
|
||||
|
||||
if lotj.mapper.noAreasPrompt ~= nil then
|
||||
lotj.mapper.noAreasPrompt:hide()
|
||||
lotj.mapper.noAreasPrompt = nil
|
||||
lotj.mapper.mapperInstance:show()
|
||||
end
|
||||
else
|
||||
lotj.mapper.log("Mapping in existing area <yellow>"..areaName.."<reset>.")
|
||||
end
|
||||
|
||||
lotj.mapper.mappingArea = areaName
|
||||
lotj.mapper.processCurrentRoom()
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.stopMapping()
|
||||
if lotj.mapper.mappingArea == nil then
|
||||
lotj.mapper.logError("Mapper not running.")
|
||||
return
|
||||
end
|
||||
lotj.mapper.mappingArea = nil
|
||||
lotj.mapper.log("Mapping <red>stopped<reset>. Don't forget to <yellow>map save<reset>!")
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.deleteArea(areaName)
|
||||
areaName = trim(areaName)
|
||||
if #areaName == 0 then
|
||||
lotj.mapper.log("Syntax: map deletearea <yellow><area name><reset>")
|
||||
return
|
||||
end
|
||||
|
||||
local areaTable = getAreaTable()
|
||||
if areaTable[areaName] == nil then
|
||||
lotj.mapper.logError("Area <yellow>"..areaName.."<reset> does not exist.")
|
||||
return
|
||||
end
|
||||
|
||||
if areaName == lotj.mapper.mappingArea then
|
||||
lotj.mapper.stopMapping()
|
||||
end
|
||||
|
||||
deleteArea(areaName)
|
||||
lotj.mapper.log("Area <yellow>"..areaName.."<reset> deleted.")
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.shiftCurrentRoom(direction)
|
||||
direction = trim(direction)
|
||||
if #direction == 0 then
|
||||
lotj.mapper.log("Syntax: map shift <yellow><direction><reset>")
|
||||
return
|
||||
end
|
||||
|
||||
local dir = dirObj(direction)
|
||||
if dir == nil then
|
||||
lotj.mapper.logError("Direction unknown: <yellow>"..direction.."<reset>")
|
||||
return
|
||||
end
|
||||
|
||||
local vnum = lotj.mapper.current.vnum
|
||||
local room = lotj.mapper.getRoomByVnum(vnum)
|
||||
if room ~= nil then
|
||||
currentX, currentY, currentZ = getRoomCoordinates(vnum)
|
||||
dx, dy, dz = unpack(dir.xyzDiff)
|
||||
setRoomCoordinates(vnum, currentX+dx, currentY+dy, currentZ+dz)
|
||||
updateMap()
|
||||
centerview(vnum)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.saveMap()
|
||||
saveMap(getMudletHomeDir() .. "/map.dat")
|
||||
lotj.mapper.log("Map saved.")
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Event Handlers
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
registerAnonymousEventHandler("lotjUICreated", function()
|
||||
lotj.mapper.mapperInstance = Geyser.Mapper:new({
|
||||
x = 0, y = 0,
|
||||
width = "100%",
|
||||
height = "100%",
|
||||
}, lotj.layout.upperRightTabData.contents["map"])
|
||||
setMapZoom(15)
|
||||
|
||||
local hasAnyAreas = false
|
||||
for name, id in pairs(getAreaTable()) do
|
||||
if name ~= "Default Area" then
|
||||
hasAnyAreas = true
|
||||
end
|
||||
end
|
||||
if not hasAnyAreas then
|
||||
lotj.mapper.mapperInstance:hide()
|
||||
lotj.mapper.noAreasPrompt = Geyser.Label:new({
|
||||
x = 0, y = 0,
|
||||
width = "100%",
|
||||
height = "100%"
|
||||
}, lotj.layout.upperRightTabData.contents["map"])
|
||||
lotj.mapper.noAreasPrompt:echo("No map data.<br><br>Use <b>map help</b> to get started.", nil, "c14")
|
||||
end
|
||||
|
||||
registerAnonymousEventHandler("sysDataSendRequest", "lotj.mapper.handleSentCommand")
|
||||
registerAnonymousEventHandler("msdp.ROOMVNUM", "lotj.mapper.onEnterRoom")
|
||||
end)
|
||||
|
||||
|
||||
-- Track the most recent movement command so we know which direction we moved when automapping
|
||||
function lotj.mapper.handleSentCommand(event, cmd)
|
||||
-- If we're not mapping, don't bother
|
||||
if lotj.mapper.mappingArea == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local dir = dirObj(trim(cmd))
|
||||
if dir ~= nil then
|
||||
lotj.mapper.lastMoveDir = dir
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Function used to handle a room that we've moved into. This will use the data on
|
||||
-- lotj.mapper.current, compared with lotj.mapper.last, to potentially create a new room and
|
||||
-- link it with an exit on the previous room.
|
||||
function lotj.mapper.processCurrentRoom()
|
||||
local vnum = lotj.mapper.current.vnum
|
||||
local moveDir = lotj.mapper.lastMoveDir
|
||||
local room = lotj.mapper.getRoomByVnum(vnum)
|
||||
|
||||
if lotj.mapper.mappingArea == nil and room == nil then
|
||||
lotj.mapper.logDebug("Room not found, but mapper not running.")
|
||||
return
|
||||
end
|
||||
|
||||
local lastRoom = nil
|
||||
if lotj.mapper.last ~= nil then
|
||||
lastRoom = lotj.mapper.getRoomByVnum(lotj.mapper.last.vnum)
|
||||
end
|
||||
|
||||
-- Create the room if we don't have it yet
|
||||
if room == nil then
|
||||
lotj.mapper.log("Added new room: <yellow>"..lotj.mapper.current.name.."<reset>")
|
||||
addRoom(vnum)
|
||||
setRoomArea(vnum, lotj.mapper.mappingArea)
|
||||
setRoomCoordinates(vnum, 0, 0, 0)
|
||||
setRoomName(vnum, lotj.mapper.current.name)
|
||||
room = lotj.mapper.getRoomByVnum(vnum)
|
||||
|
||||
-- Create stub exits in any known direction we see
|
||||
for dir, state in pairs(lotj.mapper.current.exits) do
|
||||
local exitDir = dirObj(dir)
|
||||
if exitDir ~= nil then
|
||||
setExitStub(vnum, exitDir.short, true)
|
||||
if state == "C" then
|
||||
setDoor(vnum, exitDir.short, 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Position the room relative to the room we came from
|
||||
if lastRoom ~= nil then
|
||||
local lastX, lastY, lastZ = getRoomCoordinates(lotj.mapper.last.vnum)
|
||||
|
||||
-- If we recorded a valid movement command, use that direction to position this room
|
||||
if moveDir ~= nil then
|
||||
local dx, dy, dz = unpack(moveDir.xyzDiff)
|
||||
setRoomCoordinates(vnum, lastX+dx, lastY+dy, lastZ+dz)
|
||||
else
|
||||
-- We didn't have a valid movement command but we still changed rooms, so try to guess
|
||||
-- where this room should be relative to the last.
|
||||
|
||||
-- Find a stub with a door on the last room which matches a stub with a door on this room
|
||||
-- This aims to handle cases where you've used a voice-activated locked door
|
||||
local lastDoors = getDoors(lotj.mapper.last.vnum)
|
||||
local currentDoors = getDoors(vnum)
|
||||
local matchingStubDir = nil
|
||||
for _, lastRoomStubDirNum in ipairs(getExitStubs1(lotj.mapper.last.vnum) or {}) do
|
||||
local lastRoomStubDir = dirObj(lastRoomStubDirNum)
|
||||
|
||||
for _, currentRoomStubDirNum in ipairs(getExitStubs1(vnum) or {}) do
|
||||
local currentRoomStubDir = dirObj(currentRoomStubDirNum)
|
||||
if lastRoomStubDir.short == currentRoomStubDir.rev
|
||||
and lastDoors[lastRoomStubDir.short] == 2
|
||||
and currentDoors[currentRoomStubDir.short] == 2 then
|
||||
|
||||
matchingStubDir = lastRoomStubDir
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if matchingStubDir ~= nil then
|
||||
local dx, dy, dz = unpack(matchingStubDir.xyzDiff)
|
||||
setRoomCoordinates(vnum, lastX+dx, lastY+dy, lastZ+dz)
|
||||
lotj.mapper.log("Positioning new room "..matchingStubDir.long.." of the previous room based on matching closed doors.")
|
||||
else
|
||||
-- If no matching stubs were found, just find a nearby location which isn't taken by either a stub or a real room.
|
||||
for dir in pairs({"n", "e", "w", "s", "ne", "nw", "se", "sw", "u", "d"}) do
|
||||
local dx, dy, dz = unpack(dirObj(dir).xyzDiff)
|
||||
local overlappingRoomId = lotj.mapper.getRoomByCoords(lotj.mapper.mappingArea, lastX+dx, lastY+dy, lastZ+dz)
|
||||
|
||||
local hasOverlappingStub = false
|
||||
for _, stubDirNum in ipairs(getExitStubs1(lotj.mapper.last.vnum) or {}) do
|
||||
if dirObj(stubDirNum) == dirObj(dir) then
|
||||
hasOverlappingStub = true
|
||||
end
|
||||
end
|
||||
|
||||
if overlappingRoomId == nil and not hasOverlappingStub then
|
||||
lotj.mapper.log("Exit unknown. Positioning new room "..dirObj(dir).long.." of the previous room.")
|
||||
setRoomCoordinates(vnum, lastX+dx, lastY+dy, lastZ+dz)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Link this room with the previous one if they have a matching set of exit stubs
|
||||
if lastRoom ~= nil and moveDir ~= nil then
|
||||
-- Always set the exit we took even if it wasn't a stub. The direction we just moved is our best
|
||||
-- evidence of how rooms are connected, overriding any reverse-created exits made earlier if they
|
||||
-- are different.
|
||||
setExit(lotj.mapper.last.vnum, vnum, moveDir.short)
|
||||
|
||||
-- Only set the reverse exit (from current room back to where we came from) if it's a stub.
|
||||
-- In the case of mazes or asymmetrical exits, this may be wrong but will be fixed on moving back
|
||||
-- out through this exit.
|
||||
for _, currentRoomStubDirNum in ipairs(getExitStubs1(vnum) or {}) do
|
||||
local currentRoomStubDir = dirObj(currentRoomStubDirNum)
|
||||
if moveDir.rev == currentRoomStubDir.short then
|
||||
setExit(vnum, lotj.mapper.last.vnum, moveDir.rev)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
centerview(vnum)
|
||||
end
|
||||
|
||||
|
||||
function lotj.mapper.checkAmenityLine(roomName, amenityName, wasPending)
|
||||
if lotj.mapper.mappingArea == nil then
|
||||
return
|
||||
end
|
||||
|
||||
envCode = amenityEnvCodes[string.lower(amenityName)]
|
||||
if envCode == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local addAmenityRoom = nil
|
||||
if lotj.mapper.current.name == roomName then
|
||||
addAmenityRoom = lotj.mapper.current
|
||||
elseif lotj.mapper.last.name == roomName then
|
||||
addAmenityRoom = lotj.mapper.last
|
||||
end
|
||||
|
||||
-- If this wasn't stored for later use, we need a newline since this is being invoked on
|
||||
-- seeing a room name and we don't want it mushed into that line.
|
||||
if not wasPending then
|
||||
echo("\n")
|
||||
end
|
||||
|
||||
if addAmenityRoom == nil then
|
||||
-- The room name we're triggering on might be the room we just entered but we haven't
|
||||
-- received the MSDP event yet, so we'll store this for the next time we do.
|
||||
lotj.mapper.pendingAmenity = {
|
||||
roomName = roomName,
|
||||
amenityName = amenityName,
|
||||
}
|
||||
else
|
||||
lotj.mapper.log("Set amenity <yellow>"..amenityName.."<reset> on room <yellow>"..addAmenityRoom.name.."<reset>")
|
||||
setRoomEnv(addAmenityRoom.vnum, envCode)
|
||||
updateMap()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- The vnum is always sent after the name and exits, so we can use it as a trigger for
|
||||
-- handling movement to a new room
|
||||
function lotj.mapper.onEnterRoom()
|
||||
if lotj.mapper.current ~= nil then
|
||||
lotj.mapper.last = lotj.mapper.current
|
||||
end
|
||||
local exits = {}
|
||||
if msdp.ROOMEXITS ~= "" then
|
||||
exits = msdp.ROOMEXITS
|
||||
end
|
||||
lotj.mapper.current = {
|
||||
vnum = tonumber(msdp.ROOMVNUM),
|
||||
name = string.gsub(msdp.ROOMNAME, "&.", ""),
|
||||
exits = exits,
|
||||
}
|
||||
|
||||
lotj.mapper.processCurrentRoom()
|
||||
|
||||
-- Since we've handled the move, we don't want the last move command to get
|
||||
-- used by anything else.
|
||||
lotj.mapper.lastMoveDir = nil
|
||||
|
||||
local pendingAmenity = lotj.mapper.pendingAmenity
|
||||
if pendingAmenity ~= nil then
|
||||
lotj.mapper.checkAmenityLine(pendingAmenity.roomName, pendingAmenity.amenityName, true)
|
||||
lotj.mapper.pendingAmenity = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Utility Functions
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function lotj.mapper.log(text)
|
||||
cecho("[<cyan>LOTJ Mapper<reset>] "..text.."\n")
|
||||
end
|
||||
|
||||
function lotj.mapper.logDebug(text)
|
||||
if lotj.mapper.debug then
|
||||
lotj.mapper.log("<green>Debug:<reset> "..text)
|
||||
end
|
||||
end
|
||||
|
||||
function lotj.mapper.logError(text)
|
||||
lotj.mapper.log("<red>Error:<reset> "..text)
|
||||
end
|
||||
|
||||
function lotj.mapper.getRoomByVnum(vnum)
|
||||
return getRooms()[vnum]
|
||||
end
|
||||
|
||||
function lotj.mapper.getRoomByCoords(areaName, x, y, z)
|
||||
local areaRooms = getAreaRooms(getAreaTable()[areaName]) or {}
|
||||
for _, roomId in pairs(areaRooms) do
|
||||
local roomX, roomY, roomZ = getRoomCoordinates(roomId)
|
||||
if roomX == x and roomY == y and roomZ == z then
|
||||
return roomId
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function doSpeedWalk()
|
||||
echo("Path we need to take: " .. table.concat(speedWalkDir, ", ") .. "\n")
|
||||
echo("A future version of the mapper script might actually execute these commands.\n")
|
||||
end
|
5
src/scripts/mapper/scripts.json
Normal file
5
src/scripts/mapper/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "mapper"
|
||||
}
|
||||
]
|
45
src/scripts/msdp/msdp.lua
Normal file
45
src/scripts/msdp/msdp.lua
Normal file
@ -0,0 +1,45 @@
|
||||
registerAnonymousEventHandler("sysLoadEvent", function()
|
||||
registerAnonymousEventHandler("msdp.COMMANDS", function()
|
||||
local msdpVars = {}
|
||||
|
||||
table.insert(msdpVars, "HEALTH")
|
||||
table.insert(msdpVars, "HEALTHMAX")
|
||||
table.insert(msdpVars, "WIMPY")
|
||||
table.insert(msdpVars, "MOVEMENT")
|
||||
table.insert(msdpVars, "MOVEMENTMAX")
|
||||
table.insert(msdpVars, "MANA")
|
||||
table.insert(msdpVars, "MANAMAX")
|
||||
|
||||
table.insert(msdpVars, "OPPONENTNAME")
|
||||
table.insert(msdpVars, "OPPONENTHEALTH")
|
||||
table.insert(msdpVars, "OPPONENTHEALTHMAX")
|
||||
|
||||
table.insert(msdpVars, "COMMCHANNEL")
|
||||
table.insert(msdpVars, "COMMENCRYPT")
|
||||
table.insert(msdpVars, "OOCLIMIT")
|
||||
|
||||
table.insert(msdpVars, "ROOMNAME")
|
||||
table.insert(msdpVars, "ROOMEXITS")
|
||||
table.insert(msdpVars, "ROOMVNUM")
|
||||
|
||||
table.insert(msdpVars, "PILOTING")
|
||||
table.insert(msdpVars, "SHIPSPEED")
|
||||
table.insert(msdpVars, "SHIPMAXSPEED")
|
||||
table.insert(msdpVars, "SHIPHULL")
|
||||
table.insert(msdpVars, "SHIPMAXHULL")
|
||||
table.insert(msdpVars, "SHIPSHIELD")
|
||||
table.insert(msdpVars, "SHIPMAXSHIELD")
|
||||
table.insert(msdpVars, "SHIPENERGY")
|
||||
table.insert(msdpVars, "SHIPMAXENERGY")
|
||||
table.insert(msdpVars, "SHIPSYSX")
|
||||
table.insert(msdpVars, "SHIPSYSY")
|
||||
table.insert(msdpVars, "SHIPSYSZ")
|
||||
table.insert(msdpVars, "SHIPGALX")
|
||||
table.insert(msdpVars, "SHIPGALY")
|
||||
table.insert(msdpVars, "SHIPSYSNAME")
|
||||
|
||||
for _, varName in ipairs(msdpVars) do
|
||||
sendMSDP("REPORT", varName)
|
||||
end
|
||||
end)
|
||||
end)
|
5
src/scripts/msdp/scripts.json
Normal file
5
src/scripts/msdp/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "msdp"
|
||||
}
|
||||
]
|
5
src/scripts/system-map/scripts.json
Normal file
5
src/scripts/system-map/scripts.json
Normal file
@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"name": "system-map"
|
||||
}
|
||||
]
|
326
src/scripts/system-map/system-map.lua
Normal file
326
src/scripts/system-map/system-map.lua
Normal file
@ -0,0 +1,326 @@
|
||||
lotj = lotj or {}
|
||||
lotj.systemMap = lotj.systemMap or {
|
||||
mapRange = 2000,
|
||||
radarItems = {},
|
||||
genPoints = {},
|
||||
genLabels = {}
|
||||
}
|
||||
local pointSize = 12
|
||||
local labelWidth = 200
|
||||
local labelHeight = 16
|
||||
|
||||
local controlButtonStyle = [[
|
||||
background-color: grey;
|
||||
border: 2px solid white;
|
||||
]]
|
||||
|
||||
registerAnonymousEventHandler("lotjUICreated", function()
|
||||
disableTrigger("system-map-radar")
|
||||
|
||||
local tabContents = lotj.layout.upperRightTabData.contents["system"]
|
||||
lotj.systemMap.container = Geyser.Label:new({}, tabContents)
|
||||
lotj.systemMap.container:setStyleSheet([[
|
||||
background-color: black;
|
||||
]])
|
||||
lotj.systemMap.resizeToSquare()
|
||||
registerAnonymousEventHandler("sysWindowResizeEvent", lotj.systemMap.resizeToSquare)
|
||||
|
||||
local zoomInButton = Geyser.Label:new({
|
||||
x = "2%", y = 10,
|
||||
width = 28, height = 28,
|
||||
}, tabContents)
|
||||
zoomInButton:setStyleSheet(controlButtonStyle)
|
||||
zoomInButton:echo("+", "white", "c16b")
|
||||
zoomInButton:setClickCallback(function()
|
||||
if lotj.systemMap.mapRange > 1000 then
|
||||
lotj.systemMap.mapRange = lotj.systemMap.mapRange - 1000
|
||||
elseif lotj.systemMap.mapRange == 1000 then
|
||||
lotj.systemMap.mapRange = 500
|
||||
else
|
||||
return
|
||||
end
|
||||
lotj.systemMap.drawMap()
|
||||
end)
|
||||
|
||||
local zoomOutButton = Geyser.Label:new({
|
||||
x = "2%", y = 44,
|
||||
width = 28, height = 28,
|
||||
}, tabContents)
|
||||
zoomOutButton:setStyleSheet(controlButtonStyle)
|
||||
zoomOutButton:echo("-", "white", "c16b")
|
||||
zoomOutButton:setClickCallback(function()
|
||||
if lotj.systemMap.mapRange >= 1000 then
|
||||
lotj.systemMap.mapRange = lotj.systemMap.mapRange + 1000
|
||||
elseif lotj.systemMap.mapRange == 500 then
|
||||
lotj.systemMap.mapRange = 1000
|
||||
else
|
||||
return
|
||||
end
|
||||
lotj.systemMap.drawMap()
|
||||
end)
|
||||
|
||||
local refreshButton = Geyser.Label:new({
|
||||
x = "2%", y = 78,
|
||||
width = 28, height = 28,
|
||||
}, tabContents)
|
||||
refreshButton:setStyleSheet(controlButtonStyle)
|
||||
refreshButton:echo("R", "white", "c16b")
|
||||
refreshButton:setClickCallback(function()
|
||||
lotj.systemMap.maskNextRadarOutput = true
|
||||
expandAlias("radar", false)
|
||||
end)
|
||||
|
||||
|
||||
local rangeCircle = rangeCircle or Geyser.Label:new({fillBg = 0}, lotj.systemMap.container)
|
||||
rangeCircle:move(0, 0)
|
||||
|
||||
lotj.systemMap.rangeLabel = lotj.systemMap.rangeLabel or Geyser.Label:new({fillBg = 0}, lotj.systemMap.container)
|
||||
lotj.systemMap.rangeLabel:resize(50, 20)
|
||||
lotj.systemMap.rangeLabel:echo(lotj.systemMap.mapRange, "green", "10c")
|
||||
|
||||
local function positionRangeCircle()
|
||||
local containerSize = lotj.systemMap.container:get_height()
|
||||
lotj.systemMap.rangeLabel:move(containerSize-math.ceil(containerSize/10)-25, math.ceil(containerSize/10))
|
||||
rangeCircle:resize(containerSize, containerSize)
|
||||
rangeCircle:setStyleSheet([[
|
||||
border: 1px dashed green;
|
||||
border-radius: ]]..math.floor(containerSize/2)..[[px;
|
||||
]])
|
||||
end
|
||||
positionRangeCircle()
|
||||
registerAnonymousEventHandler("sysWindowResizeEvent", positionRangeCircle)
|
||||
|
||||
registerAnonymousEventHandler("msdp.SHIPSYSX", "lotj.systemMap.drawMap")
|
||||
registerAnonymousEventHandler("msdp.SHIPSYSY", "lotj.systemMap.drawMap")
|
||||
registerAnonymousEventHandler("msdp.SHIPSYSZ", "lotj.systemMap.drawMap")
|
||||
end)
|
||||
|
||||
function lotj.systemMap.resetItems()
|
||||
lotj.systemMap.radarItems = {}
|
||||
end
|
||||
|
||||
function lotj.systemMap.addItem(item)
|
||||
table.insert(lotj.systemMap.radarItems, item)
|
||||
end
|
||||
|
||||
function lotj.systemMap.drawMap()
|
||||
lotj.systemMap.rangeLabel:echo(lotj.systemMap.mapRange, "green", "10c")
|
||||
|
||||
-- Hide any previously generated elements which we may be displaying
|
||||
for _, elem in ipairs(lotj.systemMap.genPoints) do
|
||||
elem:hide()
|
||||
end
|
||||
for _, elem in ipairs(lotj.systemMap.genLabels) do
|
||||
elem:hide()
|
||||
end
|
||||
|
||||
-- We use ship max speed as a proxy for "do we have ship data at all"
|
||||
if tonumber(msdp.SHIPMAXSPEED or "0") == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local shipX = tonumber(msdp.SHIPSYSX or "0")
|
||||
local shipY = tonumber(msdp.SHIPSYSY or "0")
|
||||
local shipZ = tonumber(msdp.SHIPSYSZ or "0")
|
||||
local selfData = {name="You", x=shipX, y=shipY, z=shipZ}
|
||||
|
||||
local itemsToDraw = {}
|
||||
table.insert(itemsToDraw, selfData)
|
||||
for _, item in ipairs(lotj.systemMap.radarItems) do
|
||||
if lotj.systemMap.dist(selfData, item) <= lotj.systemMap.mapRange then
|
||||
table.insert(itemsToDraw, item)
|
||||
end
|
||||
end
|
||||
|
||||
local drawnItems = {}
|
||||
for i, item in ipairs(itemsToDraw) do
|
||||
local point, label = lotj.systemMap.pointAndLabel(i)
|
||||
|
||||
local color = "yellow"
|
||||
if item.class and string.match(item.class, "Pirated") then
|
||||
color = "red"
|
||||
elseif item == selfData then
|
||||
color = "white"
|
||||
end
|
||||
|
||||
point:resize(pointSize, pointSize)
|
||||
point:setStyleSheet([[
|
||||
border-radius: ]]..math.floor(pointSize/2)..[[px;
|
||||
background-color: ]]..color..[[;
|
||||
]])
|
||||
|
||||
local x, y = lotj.systemMap.computeXY(selfData, item)
|
||||
point:show()
|
||||
point:move(x, y)
|
||||
|
||||
local labelXOffset, labelYOffset = lotj.systemMap.computeLabelPos(drawnItems, x, y)
|
||||
local labelX = x+labelXOffset
|
||||
local labelY = y+labelYOffset
|
||||
label:show()
|
||||
label:move(labelX, labelY)
|
||||
lotj.systemMap.printLabels(point, label, color, labelXOffset, item, selfData)
|
||||
|
||||
table.insert(drawnItems, {x = x, y = y, labelX = labelX, labelY = labelY, labelXOffset = labelXOffset, labelYOffset = labelYOffset})
|
||||
end
|
||||
end
|
||||
|
||||
-- Add appropriate text to the point and label
|
||||
function lotj.systemMap.printLabels(point, label, color, labelXOffset, item, selfData)
|
||||
local labelStr = item.name
|
||||
|
||||
-- Prepend an up/down arrow to show Z diff
|
||||
local zDiff = item.z - selfData.z
|
||||
if zDiff ~= 0 then
|
||||
local arrowFontSize = 3 + math.floor(11 * math.abs(zDiff) / lotj.systemMap.mapRange + 0.5)
|
||||
local arrowChar = "▲" -- Up arrow
|
||||
if zDiff < 0 then
|
||||
arrowChar = "▼" -- Down arrow
|
||||
end
|
||||
point:echo(arrowChar, "black", arrowFontSize.."c")
|
||||
else
|
||||
point:echo("")
|
||||
end
|
||||
|
||||
-- Append proximity and class
|
||||
if item ~= selfData then
|
||||
labelStr = labelStr.." ("..math.floor(lotj.systemMap.dist(item, selfData) + 0.5)
|
||||
if item.class ~= nil then
|
||||
labelStr = labelStr..", "..item.class
|
||||
end
|
||||
labelStr = labelStr..")"
|
||||
end
|
||||
|
||||
-- Set alignment based on whether the label is to the right or left of the point
|
||||
if labelXOffset > 0 then
|
||||
label:echo(labelStr, color, "11l")
|
||||
else
|
||||
label:echo(labelStr, color, "11r")
|
||||
end
|
||||
end
|
||||
|
||||
-- Based on the position, size of map, and zoom level, determine the X and Y placement for the given item
|
||||
function lotj.systemMap.computeXY(selfData, item)
|
||||
local mapMinX = selfData.x-lotj.systemMap.mapRange
|
||||
local mapMinY = selfData.y-lotj.systemMap.mapRange
|
||||
local containerSize = lotj.systemMap.container:get_height()
|
||||
|
||||
local x = math.floor(containerSize * ((item.x - mapMinX) / (lotj.systemMap.mapRange*2)) + 0.5)
|
||||
local y = math.floor(containerSize * (1 - (item.y - mapMinY) / (lotj.systemMap.mapRange*2)) + 0.5)
|
||||
|
||||
return x-pointSize/2, y-pointSize/2
|
||||
end
|
||||
|
||||
-- Return true if the first rectancle overlaps with any part of the second rectangle
|
||||
local function overlaps(x1, y1, w1, h1, x2, y2, w2, h2)
|
||||
local xOverlap = (x1 >= x2 and x1 <= x2+w2) or (x1+w1 >= x2 and x1+w1 <= x2+w2)
|
||||
local yOverlap = (y1 >= y2 and y1 <= y2+h2) or (y1+h1 >= y2 and y1+h1 <= y2+h2)
|
||||
return xOverlap and yOverlap
|
||||
end
|
||||
|
||||
-- Determine whether a given rectangle overlaps with the points or labels in the given array of items
|
||||
local function anyOverlaps(x, y, w, h, items)
|
||||
for _, item in ipairs(items) do
|
||||
-- Overlap with this item's point?
|
||||
if overlaps(x, y, w, h, item.x, item.y, pointSize, pointSize) then
|
||||
return true
|
||||
end
|
||||
-- Overlap with this item's label?
|
||||
if overlaps(x, y, w, h, item.labelX, item.labelY, labelWidth, labelHeight) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Find a suitable label X and Y offset for a new label, attempting to avoid overlap with anything previously drawn
|
||||
function lotj.systemMap.computeLabelPos(drawnItems, itemX, itemY)
|
||||
local labelXOffset = pointSize
|
||||
local labelYOffset = pointSize
|
||||
|
||||
-- If we find an item at the same coords, simply put the label below the last one for those coords
|
||||
local foundSameCoords = false
|
||||
for _, item in ipairs(drawnItems) do
|
||||
if item.x == itemX and item.y == itemY then
|
||||
foundSameCoords = true
|
||||
if item.labelY > item.y then
|
||||
labelYOffset = item.labelYOffset + labelHeight
|
||||
else
|
||||
labelYOffset = item.labelYOffset - labelHeight
|
||||
end
|
||||
end
|
||||
end
|
||||
if foundSameCoords then
|
||||
return labelXOffset, labelYOffset
|
||||
end
|
||||
|
||||
-- Try four different label positions to find one without any overlap
|
||||
local offsetsToTry = {}
|
||||
table.insert(offsetsToTry, {x = pointSize, y = pointSize})
|
||||
table.insert(offsetsToTry, {x = pointSize, y = labelHeight * -1})
|
||||
table.insert(offsetsToTry, {x = labelWidth * -1, y = labelHeight * -1})
|
||||
table.insert(offsetsToTry, {x = labelWidth * -1, y = pointSize})
|
||||
for _, offsets in ipairs(offsetsToTry) do
|
||||
if not anyOverlaps(itemX+offsets.x, itemY+offsets.y, labelWidth, labelHeight, drawnItems) then
|
||||
return offsets.x, offsets.y
|
||||
end
|
||||
end
|
||||
|
||||
-- We couldn't find a non-overlapping position, so just put it to the lower right
|
||||
return labelXOffset, labelYOffset
|
||||
end
|
||||
|
||||
-- Return existing (or create new) Geyser labels for a given point and label
|
||||
-- We store and reuse these so that we don't accumulate infinite label objects, since Geyser doesn't give us a way to delete elements, only hide them
|
||||
function lotj.systemMap.pointAndLabel(idx)
|
||||
lotj.systemMap.genPoints[idx] = lotj.systemMap.genPoints[idx] or Geyser.Label:new({}, lotj.systemMap.container)
|
||||
lotj.systemMap.genLabels[idx] = lotj.systemMap.genLabels[idx] or Geyser.Label:new({fillBg = 0, width = labelWidth, height = labelHeight}, lotj.systemMap.container)
|
||||
return lotj.systemMap.genPoints[idx], lotj.systemMap.genLabels[idx]
|
||||
end
|
||||
|
||||
-- Compute distance between one X/Y/Z coord and another
|
||||
function lotj.systemMap.dist(coordsA, coordsB)
|
||||
local xDiff = math.abs(coordsA.x-coordsB.x)
|
||||
local yDiff = math.abs(coordsA.y-coordsB.y)
|
||||
local zDiff = math.abs(coordsA.z-coordsB.z)
|
||||
|
||||
local xyDiff = math.sqrt(xDiff*xDiff + yDiff*yDiff)
|
||||
local totalDiff = math.sqrt(xyDiff*xyDiff + zDiff*zDiff)
|
||||
return totalDiff
|
||||
end
|
||||
|
||||
-- Resize the map to the largest possible square when the window dimensions change
|
||||
function lotj.systemMap.resizeToSquare()
|
||||
local tabContents = lotj.layout.upperRightTabData.contents["system"]
|
||||
local contH = tabContents:get_height()
|
||||
local contW = tabContents:get_width()
|
||||
|
||||
local x = 0
|
||||
local y = 0
|
||||
local width = "100%"
|
||||
local height = "100%"
|
||||
if contW >= contH then
|
||||
width = contH
|
||||
x = (contW-contH)/2
|
||||
else
|
||||
height = contW
|
||||
y = (contH-contW)/2
|
||||
end
|
||||
|
||||
lotj.systemMap.container:move(x, y)
|
||||
lotj.systemMap.container:resize(width, height)
|
||||
end
|
||||
|
||||
function lotj.systemMap.findTarget(targetName)
|
||||
targetName = targetName:lower()
|
||||
local target = nil
|
||||
for _, item in ipairs(lotj.systemMap.radarItems) do
|
||||
if item.name:lower():sub(1, #targetName) == targetName then
|
||||
target = item
|
||||
end
|
||||
end
|
||||
return target
|
||||
end
|
||||
|
||||
function lotj.systemMap.log(text)
|
||||
cecho("[<cyan>System Map<reset>] "..text.."\n")
|
||||
end
|
6
src/triggers/chat/commnet-translated.lua
Normal file
6
src/triggers/chat/commnet-translated.lua
Normal file
@ -0,0 +1,6 @@
|
||||
if lotj.chat.commnetLastChannel == matches[2] and lotj.chat.commnetLastMessage == matches[3] then
|
||||
deleteLine()
|
||||
echo(" (Translated)")
|
||||
else
|
||||
lotj.chat.routeMessage("commnet")
|
||||
end
|
6
src/triggers/chat/commnet.lua
Normal file
6
src/triggers/chat/commnet.lua
Normal file
@ -0,0 +1,6 @@
|
||||
lotj.chat.routeMessage("commnet")
|
||||
|
||||
-- Track commnet messages to potentially squash a redundant translation
|
||||
-- message on the next line
|
||||
lotj.chat.commnetLastChannel = matches[2]
|
||||
lotj.chat.commnetLastMessage = matches[3]
|
76
src/triggers/chat/triggers.json
Normal file
76
src/triggers/chat/triggers.json
Normal file
@ -0,0 +1,76 @@
|
||||
[
|
||||
{
|
||||
"name": "commnet",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^CommNet ([0-9]+) \\[.*\\][()a-zA-Z<> ]*: (.*)",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "commnet-translated",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^.* buzzes '\\(Translating channel ([0-9]+)\\) (.*)'$",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "clan",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "{.*}<.*>\\[[a-zA-Z ]+\\][()<>A-Za-z ]*: ",
|
||||
"type": "regex"
|
||||
},
|
||||
{
|
||||
"pattern": "[Incoming Transmission from",
|
||||
"type": "substring"
|
||||
},
|
||||
{
|
||||
"pattern": "[Outgoing Transmission to",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"script": "lotj.chat.routeMessage(\"clan\")"
|
||||
},
|
||||
{
|
||||
"name": "ooc",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^\\((OOC|IMM|RPC|NEWBIE)\\) [*]?[A-Za-z]+: .*$",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "lotj.chat.routeMessage(\"ooc\")"
|
||||
},
|
||||
{
|
||||
"name": "immchat",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^\\( IMM \\| CHAT \\) .* mortchats to you '.*'$",
|
||||
"type": "regex"
|
||||
},
|
||||
{
|
||||
"pattern": "^\\( IMM \\| CHAT \\)\\[.*\\]: '.*'$",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "lotj.chat.routeMessage(\"imm\")"
|
||||
},
|
||||
{
|
||||
"name": "tell",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^\\(OOC\\) .* tells you '.*'$",
|
||||
"type": "regex"
|
||||
},
|
||||
{
|
||||
"pattern": "^\\(OOC\\) You tell .* '.*'$",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "lotj.chat.routeMessage(\"tell\")"
|
||||
}
|
||||
]
|
5
src/triggers/galaxy-map/any-planet-line.lua
Normal file
5
src/triggers/galaxy-map/any-planet-line.lua
Normal file
@ -0,0 +1,5 @@
|
||||
-- Swallow lines and extend the triggers as long as we haven't found the end of the planet yet
|
||||
if gatherPlanetState ~= nil then
|
||||
setTriggerStayOpen("gather-planet", 1)
|
||||
end
|
||||
deleteLine()
|
7
src/triggers/galaxy-map/gather-planet.lua
Normal file
7
src/triggers/galaxy-map/gather-planet.lua
Normal file
@ -0,0 +1,7 @@
|
||||
gatherPlanetState = {
|
||||
section = "basics"
|
||||
}
|
||||
|
||||
deleteLine()
|
||||
moveCursor(0,getLineNumber()-1)
|
||||
deleteLine()
|
7
src/triggers/galaxy-map/gather-planets.lua
Normal file
7
src/triggers/galaxy-map/gather-planets.lua
Normal file
@ -0,0 +1,7 @@
|
||||
deleteLine()
|
||||
|
||||
gatherPlanetsState = {
|
||||
pendingBasic = {},
|
||||
pendingResources = {},
|
||||
pendingCommands = 0,
|
||||
}
|
3
src/triggers/galaxy-map/no-datapad.lua
Normal file
3
src/triggers/galaxy-map/no-datapad.lua
Normal file
@ -0,0 +1,3 @@
|
||||
echo("\n")
|
||||
lotj.galaxyMap.log("Error gathering galaxy map data. Please fix the problem and try again.")
|
||||
disableTrigger("galaxy-map-refresh")
|
2
src/triggers/galaxy-map/no-resources.lua
Normal file
2
src/triggers/galaxy-map/no-resources.lua
Normal file
@ -0,0 +1,2 @@
|
||||
gatherPlanetState.section = "resources"
|
||||
gatherPlanetState.resources = {}
|
5
src/triggers/galaxy-map/planet-coords.lua
Normal file
5
src/triggers/galaxy-map/planet-coords.lua
Normal file
@ -0,0 +1,5 @@
|
||||
gatherPlanetState.coords = {
|
||||
x = tonumber(matches[2]),
|
||||
y = tonumber(matches[3]),
|
||||
z = tonumber(matches[4]),
|
||||
}
|
14
src/triggers/galaxy-map/planet-empty-line.lua
Normal file
14
src/triggers/galaxy-map/planet-empty-line.lua
Normal file
@ -0,0 +1,14 @@
|
||||
-- If we've gotten into the list of resources, an empty line means we're done
|
||||
if gatherPlanetState and gatherPlanetState.section == "resources" then
|
||||
echo("\n")
|
||||
lotj.galaxyMap.log("Collected resource data for "..gatherPlanetState.name)
|
||||
lotj.galaxyMap.recordPlanet(gatherPlanetState)
|
||||
|
||||
gatherPlanetsState.pendingResources[gatherPlanetState.name] = nil
|
||||
gatherPlanetsState.pendingCommands = gatherPlanetsState.pendingCommands - 1
|
||||
if gatherPlanetsState.pendingCommands == 0 then
|
||||
lotj.galaxyMap.enqueuePendingRefreshCommands()
|
||||
end
|
||||
|
||||
gatherPlanetState = nil
|
||||
end
|
11
src/triggers/galaxy-map/planet-end.lua
Normal file
11
src/triggers/galaxy-map/planet-end.lua
Normal file
@ -0,0 +1,11 @@
|
||||
echo("\n")
|
||||
lotj.galaxyMap.log("Collected basic data for "..gatherPlanetState.name)
|
||||
lotj.galaxyMap.recordPlanet(gatherPlanetState)
|
||||
|
||||
gatherPlanetsState.pendingBasic[gatherPlanetState.name] = nil
|
||||
gatherPlanetsState.pendingCommands = gatherPlanetsState.pendingCommands - 1
|
||||
if gatherPlanetsState.pendingCommands == 0 then
|
||||
lotj.galaxyMap.enqueuePendingRefreshCommands()
|
||||
end
|
||||
|
||||
gatherPlanetState = nil
|
29
src/triggers/galaxy-map/planets-line.lua
Normal file
29
src/triggers/galaxy-map/planets-line.lua
Normal file
@ -0,0 +1,29 @@
|
||||
deleteLine()
|
||||
|
||||
local line = matches[2]
|
||||
|
||||
local function starts_with(str, start)
|
||||
return str:sub(1, #start) == start
|
||||
end
|
||||
|
||||
if starts_with(line, "Use SHOWPLANET for more information.") then
|
||||
lotj.galaxyMap.enqueuePendingRefreshCommands()
|
||||
return
|
||||
end
|
||||
|
||||
line = line:gsub("%(UFG%)", "")
|
||||
line = line:gsub(" +", ";")
|
||||
local _, _, planet, system, gov, support = line:find("([^;]+);([^;]+);([^;]+);([^;]+)")
|
||||
|
||||
if planet ~= "Planet" then
|
||||
lotj.galaxyMap.recordPlanet({
|
||||
name = planet,
|
||||
system = system,
|
||||
gov = gov,
|
||||
})
|
||||
|
||||
gatherPlanetsState.pendingBasic[planet] = true
|
||||
gatherPlanetsState.pendingResources[planet] = true
|
||||
end
|
||||
|
||||
setTriggerStayOpen("gather-planets", 1)
|
7
src/triggers/galaxy-map/resource-price.lua
Normal file
7
src/triggers/galaxy-map/resource-price.lua
Normal file
@ -0,0 +1,7 @@
|
||||
gatherPlanetState.section = "resources"
|
||||
|
||||
local resource = matches[2]:match "^%s*(.-)%s*$"
|
||||
local price = tonumber(matches[3])
|
||||
|
||||
gatherPlanetState.resources = gatherPlanetState.resources or {}
|
||||
gatherPlanetState.resources[resource] = price
|
4
src/triggers/galaxy-map/showplanet-fail
Normal file
4
src/triggers/galaxy-map/showplanet-fail
Normal file
@ -0,0 +1,4 @@
|
||||
gatherPlanetsState.pendingCommands = gatherPlanetsState.pendingCommands - 1
|
||||
if gatherPlanetsState.pendingCommands == 0 then
|
||||
lotj.galaxyMap.enqueuePendingRefreshCommands()
|
||||
end
|
8
src/triggers/galaxy-map/system-line.lua
Normal file
8
src/triggers/galaxy-map/system-line.lua
Normal file
@ -0,0 +1,8 @@
|
||||
local systemName = matches[2]:match "^%s*(.-)%s*$"
|
||||
local xCoord = tonumber(matches[3])
|
||||
local yCoord = tonumber(matches[4])
|
||||
|
||||
lotj.galaxyMap.recordSystem(systemName, xCoord, yCoord)
|
||||
|
||||
setTriggerStayOpen("gather-starsystems", 1)
|
||||
deleteLine()
|
211
src/triggers/galaxy-map/triggers.json
Normal file
211
src/triggers/galaxy-map/triggers.json
Normal file
@ -0,0 +1,211 @@
|
||||
[
|
||||
{
|
||||
"name": "galaxy-map-refresh",
|
||||
"isActive": "no",
|
||||
"isFolder": "yes",
|
||||
"children": [
|
||||
{
|
||||
"name": "gather-planets",
|
||||
"fireLength": 1,
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Planet\\s+Starsystem\\s+Governed By\\s+Popular Support",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"name": "planets-line",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(.*)",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gather-planet",
|
||||
"multiline": "yes",
|
||||
"multilineDelta": 1,
|
||||
"fireLength": 4,
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "You use the datapad to lookup the information.",
|
||||
"type": "substring"
|
||||
},
|
||||
{
|
||||
"pattern": "--Planet Data: -------------------------------",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"name": "planet-name",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Planet: (.*)",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.name = matches[2]"
|
||||
},
|
||||
{
|
||||
"name": "planet-starsys",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Starsystem: (.*)",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.system = matches[2]"
|
||||
},
|
||||
{
|
||||
"name": "planet-coords",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Coordinates: ([0-9-]+) ([0-9-]+) ([0-9-]+)",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "planet-gov",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Governed By: (.*)",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.gov = matches[2]"
|
||||
},
|
||||
{
|
||||
"name": "planet-description-hdr",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "--Planetary Information: ---------------------",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.section = \"description\""
|
||||
},
|
||||
{
|
||||
"name": "planet-resources-hdr",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "--Planetary Resources: -----------------------",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.section = \"resources-basic\""
|
||||
},
|
||||
{
|
||||
"name": "resource-price",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^([\\w ]*)\\s+\\( Price per unit: ([0-9.]+)\\s*\\)",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "no-resources",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(No resources available on this planet)",
|
||||
"type": "substring"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "freeport",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(.*) is a freeport.",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.freeport = true"
|
||||
},
|
||||
{
|
||||
"name": "tax",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Tax Rate: ([0-9]+)%",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "gatherPlanetState.taxRate = tonumber(matches[2])"
|
||||
},
|
||||
{
|
||||
"name": "any-planet-line",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(.*)",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "planet-empty-line",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^$",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "planet-end",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Use 'SHOWPLANET <planet> RESOURCES' for current resources.",
|
||||
"type": "prefix"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gather-starsystems",
|
||||
"fireLength": 1,
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Listing publicly known starsystems:",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"name": "system-line",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^(.*) \\( ([0-9-]+), ([0-9-]+) \\)$",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "no-datapad",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "You must hold a datapad to do this.",
|
||||
"type": "substring"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "showplanet-fail",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^You fail.$",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
32
src/triggers/info-panel/triggers.json
Normal file
32
src/triggers/info-panel/triggers.json
Normal file
@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"name": "spacetick",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^Remaining jump time:",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "lotj.infoPanel.markSpaceTick()"
|
||||
},
|
||||
{
|
||||
"name": "chaff",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "A burst of chaff is released from the ship.",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"script": "lotj.infoPanel.markChaff()"
|
||||
},
|
||||
{
|
||||
"name": "chaff-cleared",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "The chaff has cleared, leaving the ship vulnerable again.",
|
||||
"type": "substring"
|
||||
}
|
||||
],
|
||||
"script": "lotj.infoPanel.clearChaff()"
|
||||
}
|
||||
]
|
1
src/triggers/layout/leave-ship.lua
Normal file
1
src/triggers/layout/leave-ship.lua
Normal file
@ -0,0 +1 @@
|
||||
lotj.layout.selectTab(lotj.layout.upperRightTabData, "map")
|
1
src/triggers/layout/ship-launched.lua
Normal file
1
src/triggers/layout/ship-launched.lua
Normal file
@ -0,0 +1 @@
|
||||
lotj.layout.selectTab(lotj.layout.upperRightTabData, "system")
|
20
src/triggers/layout/triggers.json
Normal file
20
src/triggers/layout/triggers.json
Normal file
@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"name": "leave-ship",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "You exit the ship.",
|
||||
"type": "substring"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ship-launched",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "The ship leaves the platform far behind as it flies into space",
|
||||
"type": "substring"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
12
src/triggers/mapper/triggers.json
Normal file
12
src/triggers/mapper/triggers.json
Normal file
@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "room-amenities",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^(.*) \\[([^]]+)\\]$",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"script": "lotj.mapper.checkAmenityLine(matches[2], matches[3])"
|
||||
}
|
||||
]
|
2
src/triggers/system-map/auto-radar.lua
Normal file
2
src/triggers/system-map/auto-radar.lua
Normal file
@ -0,0 +1,2 @@
|
||||
lotj.systemMap.maskNextRadarOutput = true
|
||||
expandAlias("radar", false)
|
5
src/triggers/system-map/radar-blank-line.lua
Normal file
5
src/triggers/system-map/radar-blank-line.lua
Normal file
@ -0,0 +1,5 @@
|
||||
if lotj.systemMap.maskNextRadarOutput then
|
||||
deleteLine()
|
||||
end
|
||||
|
||||
setTriggerStayOpen("system-map-radar", 1)
|
32
src/triggers/system-map/radar-item.lua
Normal file
32
src/triggers/system-map/radar-item.lua
Normal file
@ -0,0 +1,32 @@
|
||||
local trimName = matches[2]:gsub("^%s*(.-)%s*$", "%1")
|
||||
|
||||
if trimName == "Your Coordinates:" then
|
||||
setTriggerStayOpen("system-map-radar", 0)
|
||||
disableTrigger("system-map-radar")
|
||||
|
||||
echo("\n")
|
||||
lotj.systemMap.log("Radar data collected.")
|
||||
lotj.systemMap.maskNextRadarOutput = false
|
||||
lotj.systemMap.inRadarOutput = false
|
||||
lotj.systemMap.drawMap()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
_, _, class, name = trimName:find("(.*) '(.*)'")
|
||||
if name == nil then
|
||||
name = trimName
|
||||
end
|
||||
|
||||
lotj.systemMap.addItem({
|
||||
class = class,
|
||||
name = name,
|
||||
x = tonumber(matches[3]),
|
||||
y = tonumber(matches[4]),
|
||||
z = tonumber(matches[5]),
|
||||
})
|
||||
|
||||
if lotj.systemMap.maskNextRadarOutput then
|
||||
deleteLine()
|
||||
end
|
||||
setTriggerStayOpen("system-map-radar", 1)
|
22
src/triggers/system-map/system-map-radar.lua
Normal file
22
src/triggers/system-map/system-map-radar.lua
Normal file
@ -0,0 +1,22 @@
|
||||
-- Trigger groups seem to fire the parent trigger on child matches
|
||||
if not matches or #matches == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Occasionally we catch the space prompt here. We want to ignore that.
|
||||
if string.match(matches[2], "Fuel Level:") then
|
||||
return
|
||||
end
|
||||
|
||||
if lotj.systemMap.maskNextRadarOutput then
|
||||
deleteLine()
|
||||
end
|
||||
|
||||
-- If we're already in the block of radar output, don't do any top-level setup
|
||||
if lotj.systemMap.inRadarOutput then
|
||||
return
|
||||
end
|
||||
|
||||
setTriggerStayOpen("system-map-radar", 1)
|
||||
lotj.systemMap.resetItems()
|
||||
lotj.systemMap.inRadarOutput = true
|
45
src/triggers/system-map/triggers.json
Normal file
45
src/triggers/system-map/triggers.json
Normal file
@ -0,0 +1,45 @@
|
||||
[
|
||||
{
|
||||
"name": "system-map-radar",
|
||||
"isActive": "no",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^(.*)\\s+([-0-9]+) ([-0-9]+) ([-0-9]+)$",
|
||||
"type": "regex"
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"name": "radar-blank-line",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^$",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "radar-item",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "^(.*)\\s+([-0-9]+) ([-0-9]+) ([-0-9]+)$",
|
||||
"type": "regex"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "auto-radar",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "The ship leaves the platform far behind as it flies into space",
|
||||
"type": "substring"
|
||||
},
|
||||
{
|
||||
"pattern": "Hyperjump complete",
|
||||
"type": "substring"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user