Follow Ship Code

All discussions & material related to Command's Lua interface

Moderators: angster, RoryAndersonCDT, michaelm75au, MOD_Command

Post Reply
BDukes
Posts: 2693
Joined: Wed Dec 27, 2017 12:59 pm

Follow Ship Code

Post by BDukes »

JM posted a question here about some code to follow a ship.

https://www.matrixgames.com/forums/tm.asp?m=5122003

Here's a solution. Its is not detection-based (bigger project) but should be suitable for the AI to just trail something.

--AI chase solution. Not perfect as its cheating abit as its not based on detection but will model a unit following a unit at a distance.
-- Setup is to create a support mission with a reference point and assign your chasing unit to it. Place the unit at a distance that makes sense.
--You set the script below to run periodically. You can determine what's reasonable.
local MeepMeep = ScenEdit_GetUnit({guid='1T8G9D-0HMED9MJH8QTB'})--Unit to be Followed
local MeepCounter = ScenEdit_GetKeyValue("Meeps");--Of coarse you can store meeps ya Maroon!
local MeepCounterF = tonumber(MeepCounter)
if MeepCounterF == nil then
MeepCounterF = 0;
end
MeepCounterF = MeepCounterF +1;
local MeepDel = (MeepCounterF) -1;
if MeepMeep ~= Nil then
ScenEdit_SetKeyValue("Meeps", tostring(MeepCounterF));
ScenEdit_AddReferencePoint({side='WilyECoyote', name=tostring(MeepCounterF),latitude=MeepMeep.latitude, longitude=MeepMeep.longitude, highlighted=true})--Drops a reference point at the targets position
ScenEdit_SetMission('WilyECoyote', 'RoadrunnerChase',{zone={(MeepCounterF)}}) --Adds the reference point to your support mission mission and unassings the old points.
ScenEdit_SetUnit({name='Coyote', guid='1T8G9D-0HMED9MJH8R7N',manualSpeed=(MeepMeep.speed)})--matches target speed
ScenEdit_DeleteReferencePoint({side='WilyECoyote', name=(MeepDel)})--Cleaning up the last reference point
else
end

Attached file has the code in an event action and special action so you can see how to set it up.


Attachments
Test Chase.zip
(14.32 KiB) Downloaded 17 times
Don't call it a comeback...
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

nice, thx. Always fun to try lua stuff
regards GJ
BDukes
Posts: 2693
Joined: Wed Dec 27, 2017 12:59 pm

RE: Follow Ship Code

Post by BDukes »

Updated with the reference point cleanup lines in.

Mike
Don't call it a comeback...
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

Mike, thx.

I tried to learn from it in my own test scen, works great. From another lesson I got, I took how to put the RP in another position. Thx KH.

I put what I made in here, you or someone else might see stupid things or addons. Love to hear if thats the case.

A question, when allowed: could you make some sort of a condition that a specific unit is detected by the AGI side?

local shadowed = ScenEdit_GetUnit({guid='P7ML9T-0HMECC07850U3'})--Unit to be Followed
local ShCounter = ScenEdit_GetKeyValue("ShRps");--Of coarse you can store ShRps ya Maroon!
local ShCounterF = tonumber(ShCounter)
local Brg1 = 090;
local Dist1 = 10;
local pt = World_GetPointFromBearing({LATITUDE=shadowed.latitude,LONGITUDE=shadowed.longitude,BEARING=Brg1, DISTANCE=Dist1});
if ShCounterF == nil then
ShCounterF = 0;
end
ShCounterF = ShCounterF +1;
if shadowed ~= Nil then
ScenEdit_SetKeyValue("ShRps", tostring(ShCounterF));
ScenEdit_AddReferencePoint({side='Brown', name='Sh'..tostring(ShCounterF), lat=pt.latitude,lon=pt.longitude, highlighted=true})--Drops a reference point at the targets position
ScenEdit_DeleteReferencePoint ({side='Brown', name='Sh'..tostring(ShCounterF-1)}) -- deletes old Sh RP's
ScenEdit_SetMission('Brown', 'ShadowByAgi',{zone={('Sh'..tostring(ShCounterF))}}) --Adds the reference point to your support mission mission and unassings the old points.
ScenEdit_SetUnit({name='AGI#1', guid='P7ML9T-0HMEDSB8JT06O',manualSpeed=10})--matches target speed
else
end

regards GJ

ps Claude I don't wanna steel your question, just like to possibilities
BDukes
Posts: 2693
Joined: Wed Dec 27, 2017 12:59 pm

RE: Follow Ship Code

Post by BDukes »

ORIGINAL: Parel803

Mike, thx.

I tried to learn from it in my own test scen, works great. From another lesson I got, I took how to put the RP in another position. Thx KH.

I put what I made in here, you or someone else might see stupid things or addons. Love to hear if thats the case.

A question, when allowed: could you make some sort of a condition that a specific unit is detected by the AGI side?

local shadowed = ScenEdit_GetUnit({guid='P7ML9T-0HMECC07850U3'})--Unit to be Followed
local ShCounter = ScenEdit_GetKeyValue("ShRps");--Of coarse you can store ShRps ya Maroon!
local ShCounterF = tonumber(ShCounter)
local Brg1 = 090;
local Dist1 = 10;
local pt = World_GetPointFromBearing({LATITUDE=shadowed.latitude,LONGITUDE=shadowed.longitude,BEARING=Brg1, DISTANCE=Dist1});
if ShCounterF == nil then
ShCounterF = 0;
end
ShCounterF = ShCounterF +1;
if shadowed ~= Nil then
ScenEdit_SetKeyValue("ShRps", tostring(ShCounterF));
ScenEdit_AddReferencePoint({side='Brown', name='Sh'..tostring(ShCounterF), lat=pt.latitude,lon=pt.longitude, highlighted=true})--Drops a reference point at the targets position
ScenEdit_DeleteReferencePoint ({side='Brown', name='Sh'..tostring(ShCounterF-1)}) -- deletes old Sh RP's
ScenEdit_SetMission('Brown', 'ShadowByAgi',{zone={('Sh'..tostring(ShCounterF))}}) --Adds the reference point to your support mission mission and unassings the old points.
ScenEdit_SetUnit({name='AGI#1', guid='P7ML9T-0HMEDSB8JT06O',manualSpeed=10})--matches target speed
else
end

regards GJ

ps Claude I don't wanna steel your question, just like to possibilities

Nice work and good idea about getting it detection based!

Mike
Don't call it a comeback...
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

Good afternoon,
I made same event but with two RP's (no doubt in very ineffective way). I left the speed line out to make use of the mission speeds for ship. My AGI goes with transit speed to a couiple of NM from line and switched to station speed.
I was wondering if the point were she switch to station speed is a fixed distance to the support mission line?
Realazing it's not a LUA question but maybe someone already having the answer.

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

RE: Follow Ship Code

Post by Parel803 »

Good afternoon,
A question:
Can I make a condition (to put in the event) that an unit a contact is for a specific side?
This works great in an event, like said bit cheating. Could I somehow make a condition that only lets it fire when the AGI side has this unit (that is shadowed) on a sensor as a contact.

Hope it makes some sense.
best regards GJ
BDukes
Posts: 2693
Joined: Wed Dec 27, 2017 12:59 pm

RE: Follow Ship Code

Post by BDukes »

ORIGINAL: Parel803

Good afternoon,
A question:
Can I make a condition (to put in the event) that an unit a contact is for a specific side?
This works great in an event, like said bit cheating. Could I somehow make a condition that only lets it fire when the AGI side has this unit (that is shadowed) on a sensor as a contact.

Hope it makes some sense.
best regards GJ

There is a get contact so you can probably evaluate it a bunch of different ways. The problem is- its a shit to of time to sort to little gain other than a -yeah me! Do I want to spend a Saturday/Sunday playing the game or writing code for a small thing? Sometime letting things go is the smarter play in the overall scheme of things. So basically I have an awesome excuse for not taking this up for a long time[8D]

Mike
Don't call it a comeback...
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

Mike,
Np thanks for answering
regards GJ
BDukes
Posts: 2693
Joined: Wed Dec 27, 2017 12:59 pm

RE: Follow Ship Code

Post by BDukes »

ORIGINAL: Parel803

Mike,
Np thanks for answering
regards GJ


Good luck if it's your jam! That's how I roll.

M
Don't call it a comeback...
musurca
Posts: 168
Joined: Wed Jul 15, 2020 10:06 pm
Contact:

RE: Follow Ship Code

Post by musurca »

Can I make a condition (to put in the event) that an unit a contact is for a specific side?

For an example of using GetContact to determine what your side knows about a particular Unit, check out lines 169-184 of this: https://github.com/musurca/IKE/blob/mai ... m_msgs.lua

Basically, every Unit has a field called .ascontact which is a table of how it appears as a Contact to all sides in the scenario. You can query this table to get the GUIDs of the corresponding Contacts, their apparent positions, and how much is known about what they actually are. (The .classificationlevel field of the Contact wrapper is particularly useful, as it tells you on a scale 0-4 how much is known about the Contact. A value of 3, for example, means that the Unit class is known, but not the name.)

The tricky thing about the .ascontact table is that the Contacts are not indexed by Side name, but by Side GUID -- which is (I think) the only place in the API where this is the case. You can find the GUID that corresponds to a Side via VP_GetSides().
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: Follow Ship Code

Post by KnightHawk75 »

which is (I think) the only place in the API where this is the case.
My own memory tells me you are correct there.
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

Thank you,
Going to check it out.
best regards GJ
BDukes
Posts: 2693
Joined: Wed Dec 27, 2017 12:59 pm

RE: Follow Ship Code

Post by BDukes »

PITA stuff like this would be worth a paying into patreon, Kofi or something like that. I'd gladly pay out few clams to make the pain of doing this go away.

Mike
Don't call it a comeback...
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

I tried this:
local u = ScenEdit_GetUnit({name='P 840 Holland', guid='P7ML9T-0HMFADT2S1EQI'})
--print (u.ascontact)
for k, contact in ipairs(u.ascontact) do
if contact.side == 'P7ML9T-0HMECBS5C0K1S' then
local c = ScenEdit_GetContact({side='P7ML9T-0HMECBS5C0K1S', guid=contact.guid})
--print (c.guid)
if (c) ~= nil then
return true
else
return false
end
end
end

At first glance this looks like what I intended in the condition of the event. I do apologize if I do not understand all the English words and phrases on the forum.
If there are obvious mistake I would like to hear it, realizing time is a precious thing. It's not by understanding on my part but copy/paste & trial/error.

best regards GJ
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: Follow Ship Code

Post by KnightHawk75 »

@parel803
These may be helpful, more than you need for your exact specifics, but also flexible for other uses.

Code: Select all

 function getUpdatedSideTable()
   local sides = VP_GetSides();
   local t ={}
   for k,v in pairs(sides) do t[v.name] = v.guid; end
   return t;
 end
 

Code: Select all

 --// function to determine if a contact has been detected by a side in a given amount of time.
 --// optionally can either do it based on detection age overall, or specific to a particular unit, or age and particular.
 --//requires: build  1147.34+ (contact last detection table added) 
 ---@param viewSidename string - required name of the side the contact guid is associated with.
 ---@param contactGuid string - required guid of the contact object.
 ---@param ageSeconds? number - optional number of seconds; last detection time qualifier. (less than or eq) 
 ---@param detectorGuid? string - optional guid of the unit doing the detecting. ie has this particular unit detected the contact recently.
 ---@return boolean - true|false - true if qualified match found.
 function isContactRecentlyDetectedBySide(viewSidename,contactGuid,ageSeconds,detectorGuid)
   local retval,c = pcall(ScenEdit_GetContact,{side=viewSidename,guid=contactGuid});
   if (retval) and c ~=nil then
     if c.lastDetections ~=nil then
 

Code: Select all

       for i=1,#c.lastDetections do
         if ageSeconds < 0 and detectorGuid ==nil then --error 
           print('age and detector guid can not both be empty, aborting.'); return false;
         elseif ageSeconds < 0 and detectorGuid ~=nil then -- no age check just unit.
             if (c.lastDetections[i].detector_guid ~=nil) and c.lastDetections[i].detector_guid == detectorGuid then 
               return true;
             end
         elseif ageSeconds > 0 and detectorGuid ~=nil then --specific unit and age check for that unit.
             if (c.lastDetections[i].age ~=nil and c.lastDetections[i].detector_guid ~=nil) and c.lastDetections[i].age <= ageSeconds and c.lastDetections[i].detector_guid == detectorGuid then 
               return true;
             end
         elseif ageSeconds > 0 and detectorGuid ==nil then -- just age
           if (c.lastDetections[i].age ~=nil) and c.lastDetections[i].age <= ageSeconds then 
             return true;
           end
         end
       end
     end 
   else print('Contact guid does not exist on that side.');
   end 
   return false;
 end
 

Code: Select all

 
 --// Return true if unit is a contact on a given side.
 --// Can optionally further check if contact was last detected in a given amount of seconds.
 --// Can optionally further check if contact was as last detected in given time, specific unit, or both
 --//requires: build 1147.34+
 ---@param unitGuid string - The guid of the unit.
 ---@param bySideName string - The sidename to search for this unit as a contact on.
 ---@param ageSeconds? number - Optional time age in seconds (< or eq to this time)
 ---@param detectorGuid? string - optional guid of the unit doing the detecting. ie has this particular unit detected the contact recently.
 ---@return boolean - true|false - true if qualifying match
 function isContactByUnitGuid(unitGuid,bySideName,ageSeconds,detectorGuid)
   if unitGuid == nil then print ('Missing unitGuid param. aborting.'); return false; end
   if bySideName == nil then print('Missing bySideName param aborting.'); return false; end
   if ageSeconds == nil then ageSeconds = -1; end
   local retval,realUnit = pcall(ScenEdit_GetUnit,{guid=unitGuid});
   if ((retval) and realUnit ~=nil) then
     if realUnit.ascontact ~=nil then 
       local sidetable = getUpdatedSideTable();
 

Code: Select all

       for _,c in pairs(realUnit.ascontact) do
         if c.side == sidetable[bySideName] then
           if ageSeconds == -1 then return true; --skip recent detection check.
           elseif isContactRecentlyDetectedBySide(bySideName,c.guid,ageSeconds,detectorGuid) then return true; end
         end
       end
     end
   else print("A unit with that guid does not exist.");
   end 
   return false;
 end
 

Usage:
Assume 4FH7PU-0HMFAK0FJQ7F5 is some Blue ship guid (unit being followed)
Assume 4FH7PU-0HMFAK0FJQ94G is some Red Unit guid (who you want to know if it specifically has spotted the ship recently)

Code: Select all

 --Is this unit a contact on side Red?
 print(isContactByUnitGuid('4FH7PU-0HMFAK0FJQ7F5',"Red")); --all you need if I read the thread right.
 --Is this unit a contact on side Red, and if so has it been seen in the last 60 seconds by any Red unit.
 print(isContactByUnitGuid('4FH7PU-0HMFAK0FJQ7F5',"Red",180)); -- if you want to make sure the contact is reasonably fresh. 
 --Is this unit a contact on side Red, and if so has it been seen in the last 60 seconds by a specific unit.
 print(isContactByUnitGuid('4FH7PU-0HMFAK0FJQ7F5',"Red",60,"4FH7PU-0HMFAK0FJQ94G"));
 
Parel803
Posts: 941
Joined: Thu Oct 10, 2019 3:39 pm
Location: Netherlands

RE: Follow Ship Code

Post by Parel803 »

Thanks for answers and your time.
It's going very slow but learning all the time.

regards GJ
Post Reply

Return to “Lua Legion”