SelectedUnit in RangeTool

All discussions & material related to Command's Lua interface

Moderators: angster, RoryAndersonCDT, michaelm75au, MOD_Command

Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

SelectedUnit in RangeTool

Post by Parel803 »

A smal question: is it possible to use the ScenEdit_SelectedUnits() in the Tool_Range. The first is a GuiD. If so what am I to use in the second part of the tool.
with regards
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

yes.

Just grab the guid of the selected unit(s) for the first, the second param is either the guid of another unit you are ranging too, or a location table.

Example function you can use and adapt for your needs.

Code: Select all

 local function processUnitsForRangeAirandShip(toLocationOrUnitGuid)
   local range;
   local DestUnit;
   if (type(toLocationOrUnitGuid) == 'table') then
     DestUnit = nil;
   else
     DestUnit = ScenEdit_GetUnit({guid=toLocationOrUnitGuid});
   end
 
   local sUnits=ScenEdit_SelectedUnits(); --get the list.
 

Code: Select all

  -- compile a list of all units and contacts.
   local myTempTable = {}
   if(sUnits.units ~=nil) then --validate it
     for k,v in pairs(sUnits.units) do
       table.insert(myTempTable,{name= v.name,guid = v.guid})
     end
   end
   if(sUnits.contacts ~=nil) then
     for k,v in pairs(sUnits.contacts) do
       table.insert(myTempTable,{name= v.name,guid = v.guid})
     end
   end
   sUnits = nil;  --don't need it anymore.
 

Code: Select all

   --now process the combined table of units and contacts.
   if(#myTempTable > 0) then --if our temptable has more than 0 entries.
     local u; 
     for k,v in pairs(myTempTable) do --loop though selected unit table
       u = VP_GetUnit({guid=v.guid}); --get the unit via guid or contact guid. just used for example.
       if((u ~=nil) and (u.type == 'Aircraft' or u.type=='Ship')) then --only attempt for aircraft or ships.
         range = Tool_Range(v.guid, toLocationOrUnitGuid) --guid of selected unit, guid or location table of destination
         -- .. do what you want here'ish.
         if (DestUnit == nil) then  --we are a location.
           print(string.format( 'Range from %s to destination is %s ',tostring(v.name), tostring(range)));
         else
           print(string.format( 'Range from %s to unit %s is %s', tostring(v.name), tostring(DestUnit.name),tostring(range)));
         end
       end
       u = nil; --clear before iterate
     end --end for
   end --end if
   myTempTable = nil;
 end
 

Code: Select all

 -- call with either the destination unit guid or location table. 
 processUnitsForRangeAirandShip('4FH7PU-0HM3HVNP3NNLS')
 processUnitsForRangeAirandShip({latitude='33.1991547589118', longitude='138.376876749942'})
 
 prints in my sample of 1 aircraft, 1 ship and 1 sub selected and "A base" unit as the destination guid:
 Range from 3MN-1 Bison B [Bomber] to unit A Base is 723.50629978241
 Range from LUSV to unit A Base is 788.83927325605
 Range from 3MN-1 Bison B [Bomber] to destination is 5984.4327076228 
 Range from LUSV to destination is 6093.4341254081 
 
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

thanks again. The whole LUA is still very compex for me to grasp. Gonna try tonight.
And again I have more questions, sorry. But could a result been inseted in a message via a special action? I'll also try tonight but probably won't have a clue.
with regards
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

Yup you could include the result in whatever you want, just note it's a float so tostring() it before using it as string. Yes the above it a slightly more complex example, but I included to show how it might be used while dealing with more than one selected units, and it has some basic error checking, and highlight some re-usability. The key answer to your question was 'v.guid' above, when dealing with a selectedUnits return table.
"But could a result been inseted in a message via a special action?"
Sure change the lines print(...bla bla bla ) to ScenEdit_SpecialMessage(sidename, bla bla bla),

Here is another example,obviously you don't have to wrap things in a function but I do it out of habit so that I can reuse (copy pasta and tweak) stuff more easily and most of the time my things sit in global functions anyway, but that's another topic. This one sends a message if range is less than certain amount, and rounds the range to 2 digits after the decimal point before converting to string.

Code: Select all

 local function rangeCheckLtSendMyMessage(UnitGuid,toLocationOrUnitGuid,NM,TheSide)
   local range; --declare local var
   local theMsg ='<p>Alert!</p><p>';
   local u; --declare var for unit
   if((NM == nil) or type(NM) ~= 'number') then NM=500; end  --set a default if NM was left empty.
   if((TheSide==nil) or type(TheSide) ~= 'string') then  --validate TheSide parameter isn't empty.
     print('rangeCheckLtSendMyMessage() Error: You are missing the side parameter. Aborting.');
     return;
   else 
     u = ScenEdit_GetUnit({guid=UnitGuid})
     if (u ~=nil) then  --make sure we were able to get the unit.
       range = Tool_Range(UnitGuid, toLocationOrUnitGuid)  --get the range as decimal number
       if (range < NM) then  --if range vale < NM parameter send message.
         theMsg = theMsg .. string.format('Unit %s is %.2f nm from target unit or location.</p>', tostring(u.name), tostring(range)) --add to existing msg
         ScenEdit_SpecialMessage(TheSide, theMsg,{latitude = u.latitude,longitude = u.longitude});  --send the msg
       end
     else --handle missing unit.
       print('rangeCheckLtSendMyMessage() Error: unit no longer exists, or could not obtain unit.');
     end
   end 
 end --end func
 

Code: Select all

 
 --now use it
 
 --check if a certain specific unit is less than 500nm from my carrier.
 --send msg if it is.
 rangeCheckLtSendMyMessage( 'GUIDOF-SOURCEUNIT001', 'GUIDOF-MYCARRIER0005',500, 'RedSide' )
 
 --check if any 'Aircraft' on an entire side are less than 300nm from my carrier.
 --and send msg for each if they are.
 local objSide = VP_GetSide({name='BlueSide'});
 local filteredUnits = objSide:unitsBy('Aircraft');
 if ((filteredUnits ~=nil) and #filteredUnits > 0) then --then we have some units.
   for k,v in pairs(filteredUnits) do -- do a for-each on all units in the list.
     rangeCheckLtSendMyMessage(v.guid,'GUIDOF-MYCARRIER0005',300,'RedSide');
   end
 end
 filterUnits = nil;  --explicitly release memory, just habit
 objSide = nil;  --explicitly release memory, just habit
 
If you have a very specific thing you are trying to do just let me know can probably give you a very specific example relating to what it is you want. If you have any question about what a line does, or why it's there etc... just ask.
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

I'strugling. I put your text in the lua console including the first calling of the function. Got: ERROR: [string "Console"]:33: attempt to call a nil value (global 'processUnitsForRangeAirandShip')
Change the calling in processUnitsForRange('50PVO4-0HM3LUPQ3KCDV'). Got no reply in lua console.
Selected the unit that is Guid in the calling, got: Range from P 840 Holland to unit P 840 Holland is 0.0
The selected unit unit in the first try was an A/C of the Civilian side.
Sorry to ask again, not easy for me to fully understand the your text. Appriciate the help a lot.
with regards

Same question (I think), got the special message working it I put the whole text in. Should I do that in another way with less text in the special action or is this the way it is intended.
grts GJ
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

I renamed the function while testing the sample and in the cut paste forgot to grab the renamed first line it in the top of the post. ie... it read:
local function processUnitsForRange vs
local function processUnitsForRangeAirandShip
--
Very sorry, corrected now. re-paste post #1 sample function and you shouldn't get the nil value errors.
Change the calling in processUnitsForRange('50PVO4-0HM3LUPQ3KCDV'). Got no reply in lua console.
Well you wouldn't if nothing was selected or what was wasn't an aircraft or ship.
Selected the unit that is Guid in the calling, got: Range from P 840 Holland to unit P 840 Holland is 0.0
Yes if you select the same unit as what you're ranging against you would logically get 0.0 as a range.
The selected unit unit in the first try was an A/C of the Civilian side.
Which is the first try, the one with the error or the one where you called processUnitsForRange('50PVO4-0HM3LUPQ3KCDV')

If the latter and you are not in God Mode, then yes then the guids of other sides will not be in the sUnits.units but in sUnits.contacts, and they're contact guids not unit guids, so it wouldn't print anything. If you want your code to handle that you'd also have to iterate though the selected units contacts table (sUnits.contacts), and use VP_GetUnit() to grab the unit since it will handle the contact guid to unit guid conversion for you.

I have updated post #1 one to now include it handling "contacts" as well your own "units". Also shows you how to build a combined list.
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

Thanks again for you're help and time.
with regards
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

Sorry to keep asking questions I'm more at sea sitting behind the sensors we simulate in the game than the LUA. But keep trying. If I load you're first post in the LUA console it works great.
Should I be able to first load the function (I think that are the 3 blocks of you're text) and than later only load the call function. My brainn would think I got the same reslut but it doesn't. Hoping you can and will explain why that is. (than I get a nil)
with regards
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

I tried the alert text in a event and that works nicely. I also tried to get an alert when that unit comes within the assigned distance. Made event with trigger every 5 seconds. Result is that I get the message every 5 seconds cause I had to make it repeatable. Would there be a way that it checks every 5 seconds untill the message is send and then the event goes to inactive?
with regards
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

ORIGINAL: Parel803

Should I be able to first load the function (I think that are the 3 blocks of you're text) and than later only load the call function. My brainn would think I got the same reslut but it doesn't. Hoping you can and will explain why that is. (than I get a nil)
with regards

So if you remove the word local in front of the word function, yes you can just stick them in a script that runs on scene loadup, and it (they) will be accessible globally there after for you to reuse by just calling them from anywhere like in other lua scripts or special actions etc.
I tried the alert text in a event and that works nicely. I also tried to get an alert when that unit comes within the assigned distance. Made event with trigger every 5 seconds. Result is that I get the message every 5 seconds cause I had to make it repeatable. Would there be a way that it checks every 5 seconds untill the message is send and then the event goes to inactive?
with regards

You have two options there, with-in the event script itself after messaging the user you can disable the event itself. Another way is you can just have a global variable or stored value\marker in the scene itself control it.

for example:

Code: Select all

 --Using Key's example
 
 If ScenEdit_GetKeyValue("MyRepeatMarkerName") == '' then   --it did not exist yet.
    --....do my call to message the user...
    --...now set the keyvalue so this part of the code never runs again.
    ScenEdit_SetKeyValue("MyRepeatMarkerName","1")  --set it to something.
 end 
 
 
 --using the disable event example..
  --...your code that you only want to run once here.
  --...then disable the event.
 ScenEdit_SetEvent("MyEventNameHere",{isActive=false}); --turn off this event from running again.
 
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

KnightHawk,
thanks again, very nice to learn about it.
with regards
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

ORIGINAL: Parel803

KnightHawk,
thanks again, very nice to learn about it.
with regards

Glad to help. I'm not the best teacher but I'll do what I can, when I can.
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

KnightHawk, teacher. Again a question if I may. I put in this as a function
function processUnitsForRangeAirandShip(toLocationOrUnitGuid)
local range;
local DestUnit;
if (type(toLocationOrUnitGuid) == 'table') then
DestUnit = nil;
else
DestUnit = ScenEdit_GetUnit({guid=toLocationOrUnitGuid});
end

local sUnits=ScenEdit_SelectedUnits(); --get the list.

-- compile a list of all units and contacts.
local myTempTable = {}
if(sUnits.units ~=nil) then --validate it
for k,v in pairs(sUnits.units) do
table.insert(myTempTable,{name= v.name,guid = v.guid})
end
end
if(sUnits.contacts ~=nil) then
for k,v in pairs(sUnits.contacts) do
table.insert(myTempTable,{name= v.name,guid = v.guid})
end
end
sUnits = nil; --don't need it anymore.


--now process the combined table of units and contacts.
if(#myTempTable > 0) then --if our temptable has more than 0 entries.
local u;
for k,v in pairs(myTempTable) do --loop though selected unit table
u = VP_GetUnit({guid=v.guid}); --get the unit via guid or contact guid. just used for example.
if((u ~=nil) and (u.type == 'Aircraft' or u.type=='Ship')) then --only attempt for aircraft or ships.
range = Tool_Range(v.guid, toLocationOrUnitGuid) --guid of selected unit, guid or location table of destination
-- .. do what you want here'ish.
if (DestUnit == nil) then --we are a location.
ScenEdit_SpecialMessage('Blue', string.format( 'Range from %s to destination is %s ',tostring(v.name), tostring(range)));
else
ScenEdit_SpecialMessage('Blue', string.format( 'Range from %s to unit %s is %s', tostring(DestUnit.name), tostring(v.name), tostring(range)));
end
end
u = nil; --clear before iterate
end --end for
end --end if
myTempTable = nil;
end


Then I put the function call in a special action. Got the correct message but also a error message. Can you with a quick look see what I did wrong? I changed position of the reporting unit and selected unit in the 'print' line.

with regards. My learning is more a trial and error (and asking help)
Attachments
testDistance.jpg
testDistance.jpg (224.37 KiB) Viewed 434 times
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

First thing I see is in your special action you have an extra () after the function call.

Code: Select all

 processUnitsForRangeAirandShip('Your guid here') ()
 
 should be 
 processUnitsForRangeAirandShip('Your guid here');
 
Change that and let me know if all is well then.
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

Thx that was it, bit stupid but nice if stuff works :-)
now to try the 5 sec stop.
thx again, regards GJ
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

I tried the SetEvent. This disables the event after first time fired. Probably logical but I got a inbound unit which is outside the given range at start.
So the first few 'scenario event fired' don't give the alert message.
Not sure if it's possible what I want but I like the event to run untill the actual 'alert' message is send.
Hope my writing makes some sense. Now to study on the key example.
with regards GJ
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

was thinking about enter area but disregarded it
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: SelectedUnit in RangeTool

Post by KnightHawk75 »

ORIGINAL: Parel803

I tried the SetEvent. This disables the event after first time fired. Probably logical but I got a inbound unit which is outside the given range at start.
So the first few 'scenario event fired' don't give the alert message.
Not sure if it's possible what I want but I like the event to run untill the actual 'alert' message is send.
Hope my writing makes some sense. Now to study on the key example.
with regards GJ
Shouldn't be a problem so long as the setEvent to inactive only triggers when the message is sent.

An example of #1 tweaked for that.

Code: Select all

 ... clipped
 
 range = Tool_Range(UnitGuid, toLocationOrUnitGuid)  --get the range as decimal number
 if (range < NM) then  --if range vale < NM parameter send message.
         theMsg = theMsg .. string.format('Unit %s is %.2f nm from target unit or location.</p>', tostring(u.name), tostring(range)) --add to existing msg
         ScenEdit_SpecialMessage(TheSide, theMsg,{latitude = u.latitude,longitude = u.longitude});  --send the msg
         ScenEdit_SetEvent("YourEventNameHere",{isActive=false}); --turn off this event from running again.
 end
 
 ...clipped
 
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

Thanks for youre time, gonna try.
with regards
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: SelectedUnit in RangeTool

Post by Parel803 »

dear teacher, it works great.
Thx also for you're time and work
with regards GJ
Post Reply

Return to “Lua Legion”