[ADDED] Locating my units?

Take command of air and naval assets from post-WW2 to the near future in tactical and operational scale, complete with historical and hypothetical scenarios and an integrated scenario editor.

Moderator: MOD_Command

Rory Noonan
Posts: 2418
Joined: Thu Dec 18, 2014 1:53 am
Location: Brooklyn, NY

RE: Locating my units?

Post by Rory Noonan »

Just to expand on lumiere's excellent example above, here is a special action that will match partial names and allows retries if the unit name isn't correct or produces multiple results:
local function Round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end

local function ConvertDecimalPositionToDegrees(latitude,longitude)
local latitidePrefix, longitudePrefix
if latitude > 0 then
latitidePrefix = "N"
else
latitidePrefix = "S"
latitude = latitude*-1
end

local latitudeDegrees = math.floor(latitude)
local latitudeMinutes = math.floor((latitude - latitudeDegrees)*60)
local latitudeSeconds = (((latitude-latitudeDegrees)*60) - latitudeMinutes)*60
latitudeSeconds = Round(latitudeSeconds, 0)

if longitude > 0 then
longitudePrefix = "E"
else
longitudePrefix = "W"
longitude = longitude*-1
end

local longitudeDegrees = math.floor(longitude)
local longitudeMinutes = math.floor((longitude - longitudeDegrees)*60)
local longitudeSeconds = (((longitude-longitudeDegrees)*60) - longitudeMinutes)*60
longitudeSeconds = Round(longitudeSeconds, 0)

local result = (latitidePrefix..latitudeDegrees .. "°" .. latitudeMinutes .. "'" .. latitudeSeconds .. '", '..
longitudePrefix..longitudeDegrees .. "°" .. longitudeMinutes .. "'" .. longitudeSeconds .. '"')
return result
end

local function GeneratePlayerSideUnitDataTable()
local result, unitList = {}, VP_GetSide({side='playerside'}).units
for k,v in ipairs (unitList) do
local unit = ScenEdit_GetUnit({guid=v.guid})
table.insert(result, unit)
end
return result
end

::retry::

local sideUnits = GeneratePlayerSideUnitDataTable()

local userInput = ScenEdit_InputBox('Which unit do you want to locate? \n\nType any unique part of the unit name, e.g. 73, col or collins will match SSG 73 Collins; case insensitive.')
userInput = string.lower(userInput)
if userInput == '' then goto finish end

local matchCount, matchedUnit = 0, nil

for k,v in ipairs (sideUnits) do
match = string.find(string.lower(v.name),userInput)
if match ~= nil then
matchedUnit = ScenEdit_GetUnit({guid=v.guid})
matchCount = matchCount + 1
end
end

local choice, retry = nil, nil

if matchCount == 0 then

retry = ScenEdit_MsgBox('No matches found. \n\nTry typing a more specific part of the unit name. Case is not important, but at least some of the name needs to be a match! \n\nDo you want to try again?',4)

if retry == 'Yes' then goto retry end

elseif matchCount == 1 then

choice = ScenEdit_MsgBox("Is the "..matchedUnit.type..", "..matchedUnit.classname.." '"..matchedUnit.name.."' the unit you're looking for ?",4)

elseif matchCount > 1 then

retry = ScenEdit_MsgBox('Multiple matches found. \n\nTry typing a more specific part of the unit name. Case is not important, but at least some of the name needs to be a match! \n\nDo you want to try again?',4)

if retry == 'Yes' then goto retry end

end

if choice == 'Yes' then
local unit = ScenEdit_GetUnit({guid=matchedUnit.guid})
local unitPositionDescription = ConvertDecimalPositionToDegrees(unit.latitude,unit.longitude)
ScenEdit_SpecialMessage('playerside',unit.name..' is currently located at '..unitPositionDescription..'<BR><BR> Click "Jump to Location" to go to this position.',{latitude=unit.latitude,longitude=unit.longitude})
end

::finish::


Also attached is a demo .scen file and a separate .lua file with the above code nicely formatted.
Attachments
UnitFinder.zip
(14.11 KiB) Downloaded 17 times
Image
magi
Posts: 1533
Joined: Sat Feb 01, 2014 1:06 am

RE: Locating my units?

Post by magi »

there are some really smart guys here......
User avatar
lumiere
Posts: 270
Joined: Tue Mar 19, 2019 10:38 am

RE: Locating my units?

Post by lumiere »

ORIGINAL: apache85

Just to expand on lumiere's excellent example above, here is a special action that will match partial names and allows retries if the unit name isn't correct or produces multiple results:
local function Round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end

local function ConvertDecimalPositionToDegrees(latitude,longitude)
local latitidePrefix, longitudePrefix
if latitude > 0 then
latitidePrefix = "N"
else
latitidePrefix = "S"
latitude = latitude*-1
end

local latitudeDegrees = math.floor(latitude)
local latitudeMinutes = math.floor((latitude - latitudeDegrees)*60)
local latitudeSeconds = (((latitude-latitudeDegrees)*60) - latitudeMinutes)*60
latitudeSeconds = Round(latitudeSeconds, 0)

if longitude > 0 then
longitudePrefix = "E"
else
longitudePrefix = "W"
longitude = longitude*-1
end

local longitudeDegrees = math.floor(longitude)
local longitudeMinutes = math.floor((longitude - longitudeDegrees)*60)
local longitudeSeconds = (((longitude-longitudeDegrees)*60) - longitudeMinutes)*60
longitudeSeconds = Round(longitudeSeconds, 0)

local result = (latitidePrefix..latitudeDegrees .. "°" .. latitudeMinutes .. "'" .. latitudeSeconds .. '", '..
longitudePrefix..longitudeDegrees .. "°" .. longitudeMinutes .. "'" .. longitudeSeconds .. '"')
return result
end

local function GeneratePlayerSideUnitDataTable()
local result, unitList = {}, VP_GetSide({side='playerside'}).units
for k,v in ipairs (unitList) do
local unit = ScenEdit_GetUnit({guid=v.guid})
table.insert(result, unit)
end
return result
end

::retry::

local sideUnits = GeneratePlayerSideUnitDataTable()

local userInput = ScenEdit_InputBox('Which unit do you want to locate? \n\nType any unique part of the unit name, e.g. 73, col or collins will match SSG 73 Collins; case insensitive.')
userInput = string.lower(userInput)
if userInput == '' then goto finish end

local matchCount, matchedUnit = 0, nil

for k,v in ipairs (sideUnits) do
match = string.find(string.lower(v.name),userInput)
if match ~= nil then
matchedUnit = ScenEdit_GetUnit({guid=v.guid})
matchCount = matchCount + 1
end
end

local choice, retry = nil, nil

if matchCount == 0 then

retry = ScenEdit_MsgBox('No matches found. \n\nTry typing a more specific part of the unit name. Case is not important, but at least some of the name needs to be a match! \n\nDo you want to try again?',4)

if retry == 'Yes' then goto retry end

elseif matchCount == 1 then

choice = ScenEdit_MsgBox("Is the "..matchedUnit.type..", "..matchedUnit.classname.." '"..matchedUnit.name.."' the unit you're looking for ?",4)

elseif matchCount > 1 then

retry = ScenEdit_MsgBox('Multiple matches found. \n\nTry typing a more specific part of the unit name. Case is not important, but at least some of the name needs to be a match! \n\nDo you want to try again?',4)

if retry == 'Yes' then goto retry end

end

if choice == 'Yes' then
local unit = ScenEdit_GetUnit({guid=matchedUnit.guid})
local unitPositionDescription = ConvertDecimalPositionToDegrees(unit.latitude,unit.longitude)
ScenEdit_SpecialMessage('playerside',unit.name..' is currently located at '..unitPositionDescription..'<BR><BR> Click "Jump to Location" to go to this position.',{latitude=unit.latitude,longitude=unit.longitude})
end

::finish::


Also attached is a demo .scen file and a separate .lua file with the above code nicely formatted.

[X(] [:)]
"How Do You Stay Calm With A 7,000 Ton Nuclear Predator Listening For Your Heartbeat?"
User avatar
goldfinger35
Posts: 150
Joined: Thu Jan 01, 2009 4:59 pm

RE: Locating my units?

Post by goldfinger35 »

lumiere and apache [&o]
Phoenix100
Posts: 2946
Joined: Tue Sep 28, 2010 12:26 pm

RE: Locating my units?

Post by Phoenix100 »

I do remember asking for this - click unit in message log to centre in main map - around 4 years ago. Is it coming anytime soon, then, Dimitris? That would be a really cool addition.
Dimitris
Posts: 15328
Joined: Sun Jul 31, 2005 10:29 am
Contact:

RE: Locating my units?

Post by Dimitris »

ORIGINAL: Phoenix100
I do remember asking for this - click unit in message log to centre in main map - around 4 years ago. Is it coming anytime soon, then, Dimitris? That would be a really cool addition.

I wish I could say more right now.

Not long yet, though.
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: Locating my units?

Post by Whicker »

This works for contacts too - just change out lumiere's line 2 with:

local unit = ScenEdit_GetContact({side=ScenEdit_PlayerSide(), name=name})
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: Locating my units?

Post by Whicker »

modified to work with contacts - though the contact name must be an exact match - you can just copy it from the log (before running the action). Added trim function so if you copy a space at the end it will still match (only trimming on contacts). Can't do partial match on contacts I don't think since they all seem to start at #10 - so if you put in 13 there would likely be multiple #13s.
local function sanitize(str)
local s = string.gsub(str, "[%(%)%.%+%-%*%?%[%]%^%$%%]", "%%%1")
return s
end

local function trim(s)
-- from PiL2 20.4
return (s:gsub("^%s*(.-)%s*$", "%1"))
end

local function Round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end

local function ConvertDecimalPositionToDegrees(latitude,longitude)
local latitidePrefix, longitudePrefix
if latitude > 0 then
latitidePrefix = "N"
else
latitidePrefix = "S"
latitude = latitude*-1
end --if
local latitudeDegrees = math.floor(latitude)
local latitudeMinutes = math.floor((latitude - latitudeDegrees)*60)
local latitudeSeconds = (((latitude-latitudeDegrees)*60) - latitudeMinutes)*60
latitudeSeconds = Round(latitudeSeconds, 0)
if longitude > 0 then
longitudePrefix = "E"
else
longitudePrefix = "W"
longitude = longitude*-1
end --if
local longitudeDegrees = math.floor(longitude)
local longitudeMinutes = math.floor((longitude - longitudeDegrees)*60)
local longitudeSeconds = (((longitude-longitudeDegrees)*60) - longitudeMinutes)*60
longitudeSeconds = Round(longitudeSeconds, 0)
local result = (latitidePrefix..latitudeDegrees .. "°" .. latitudeMinutes .. "'" .. latitudeSeconds .. '", '..
longitudePrefix..longitudeDegrees .. "°" .. longitudeMinutes .. "'" .. longitudeSeconds .. '"')
return result
end --end function

local function GeneratePlayerSideUnitDataTable()
local result, unitList = {}, VP_GetSide({side='playerside'}).units
for k,v in ipairs (unitList) do
local unit = ScenEdit_GetUnit({guid=v.guid})
table.insert(result, unit)
end
return result
end

local function unitFound(u)
local unitPositionDescription = ConvertDecimalPositionToDegrees(u.latitude,u.longitude)
ScenEdit_SpecialMessage('playerside',u.name..' is currently located at '..unitPositionDescription..'<BR><BR> Click "Jump to Location" to go to this position.',{latitude=u.latitude,longitude=u.longitude})
end --function

local function listOfMatches(tableList)
local list = ''
for k,v in ipairs(tableList) do
list = list.. '\n' ..v
end
return list
end --function

::retry::

local userInput = ScenEdit_InputBox('Which unit do you want to locate? \n\nType any unique part of the unit name, e.g. 73, col or collins will match SSG 73 Collins; case insensitive.')
userInput = string.lower(userInput)
if userInput == '' then goto finish end --nothing entered

userInputTrimmed= trim(userInput) --trim only is doing exact comparison, spaces may be valuable in fuzzy search
-- check units for exact match, needed because fuzzy search returns both unit 1 and unit 11
local exactUnit = ScenEdit_GetUnit({side=ScenEdit_PlayerSide(), name=userInputTrimmed})
if exactUnit ~= nil then
unitFound(exactUnit)
return
end
--check contacts for exact match
local exactContact = ScenEdit_GetContact({side=ScenEdit_PlayerSide(), name=userInputTrimmed})
if exactContact ~= nil then
unitFound(exactContact)
return
end

local sideUnits = GeneratePlayerSideUnitDataTable()
local matchCount, matchedUnit, matches = 0, nil, {}
userInput = sanitize(userInput)

for k,v in ipairs (sideUnits) do
match = string.find(string.lower(v.name),userInput)
if match ~= nil then
matchedUnit = ScenEdit_GetUnit({guid=v.guid})
matchCount = matchCount + 1
table.insert(matches, matchedUnit.name)
end
end

local choice, retry = nil, nil

if matchCount == 0 then

retry = ScenEdit_MsgBox('No matches found. \n\nTry typing a more specific part of the unit name. Case is not important, but at least some of the name needs to be a match! \n\nDo you want to try again?',4)

if retry == 'Yes' then goto retry end

elseif matchCount == 1 then
choice = ScenEdit_MsgBox("Is the "..matchedUnit.type..", "..matchedUnit.classname.." '"..matchedUnit.name.."' the unit you're looking for ?",4)

elseif matchCount > 1 then
local possibleMatches = listOfMatches(matches)
retry = ScenEdit_MsgBox('Multiple matches found. \n\nTry typing a more specific part of the unit name. Case is not important, but at least some of the name needs to be a match! \nPossible Matches:\n'..possibleMatches..'\n\nDo you want to try again?',4)

if retry == 'Yes' then goto retry end
end

if choice == 'Yes' then
local unit = ScenEdit_GetUnit({guid=matchedUnit.guid})
unitFound(unit)
end

::finish::
User avatar
michaelm75au
Posts: 12457
Joined: Sat May 05, 2001 8:00 am
Location: Melbourne, Australia

RE: Locating my units?

Post by michaelm75au »

Contact number should be unique for a side; not sure if the uniqueness is overall or just for the contact type (e.g. SKUNK #1234, VAMPIRE #1234). I had a feeling it was side based so you shouldn't get SKUNK #1234 and VAMPIRE #1234 at same time for a single side.
Michael
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: Locating my units?

Post by Whicker »

I edited my code above to fix some things:

- first it tries to match an exact unit name, without it you cannot get a result with units named 'Flanker #1' and 'Flanker #11' as the the string.match method can't tell the difference
- next it tries to match an exact contact name - that is the only try for contacts, string.match would find too many units as it would match anything with 21 in it*
- added the list of possible matches to the message that says multiple matches found
- units with a special character in the name like a hyphen would not match anything cause special characters need to be escaped (added sanitize function)

* I wonder if the use case for searching for a contact would always be to find the most recent contact, which would be a larger number than existing contacts so maybe the string match would work if the contact was #123 and there was no 1123 or 1230. Even then you would still have to be careful as you would need to combine the results of units and contacts in order to know which one the user is looking for. '318' could be a contact or it could be unit '318 LR ASW Regt #2'.

I tested this a bit with one of gunners large scenarios and it seemed to perform well, I was worried loading all of a sides units into a table would eat up all the memory but it didn't. Last time I did something like this it did so maybe something was fixed.

this is a really neat lua example for anyone looking for a fairly advanced but doable code sample.
Dimitris
Posts: 15328
Joined: Sun Jul 31, 2005 10:29 am
Contact:

RE: Locating my units?

Post by Dimitris »

Added ORBAT keyword search in a future release.
User avatar
goldfinger35
Posts: 150
Joined: Thu Jan 01, 2009 4:59 pm

RE: Locating my units?

Post by goldfinger35 »

magi
Posts: 1533
Joined: Sat Feb 01, 2014 1:06 am

RE: Locating my units?

Post by magi »

ORIGINAL: goldfinger35

That. Or a simple search function in order of battle.
i actually heartily agree.... i asked about this in a post years ago.....
magi
Posts: 1533
Joined: Sat Feb 01, 2014 1:06 am

RE: Locating my units?

Post by magi »

ORIGINAL: Dimitris

ORIGINAL: spike2071
I would love a Jump To Location ability from the message log directly. Similar to the pop up, but without the actual pop up.

Stick around.
cool.....
MagpieS
Posts: 22
Joined: Sun Oct 19, 2008 3:46 am

RE: Locating my units?

Post by MagpieS »

ORIGINAL: magi

ORIGINAL: Dimitris

ORIGINAL: spike2071
I would love a Jump To Location ability from the message log directly. Similar to the pop up, but without the actual pop up.

Stick around.
cool.....


Why not just hot link the callsign in the message window ?
Post Reply

Return to “Command: Modern Operations series”