Update Skynet and Mist.

This commit is contained in:
Dan Albert 2020-12-06 13:36:53 -08:00
parent edfaaacd04
commit e544063c40
5 changed files with 1043 additions and 7247 deletions

View File

@ -5,7 +5,7 @@
"specificOptions": [], "specificOptions": [],
"scriptsWorkOrders": [ "scriptsWorkOrders": [
{ {
"file": "mist_4_3_74.lua", "file": "mist_4_4_90.lua",
"mnemonic": "mist" "mnemonic": "mist"
}, },
{ {

File diff suppressed because it is too large Load Diff

View File

@ -9,10 +9,6 @@
} }
], ],
"scriptsWorkOrders": [ "scriptsWorkOrders": [
{
"file": "mist_4_3_74.lua",
"mnemonic": "mist"
},
{ {
"file": "JTACAutoLase.lua", "file": "JTACAutoLase.lua",
"mnemonic": "jtacautolase-script" "mnemonic": "jtacautolase-script"

View File

@ -1,4 +1,4 @@
env.info("--- SKYNET VERSION: 1.1.3 | BUILD TIME: 30.09.2020 1816Z ---") env.info("--- SKYNET VERSION: 1.2.0 | BUILD TIME: 21.11.2020 1159Z ---")
do do
--this file contains the required units per sam type --this file contains the required units per sam type
samTypesDB = { samTypesDB = {
@ -554,8 +554,10 @@ function SkynetIADS:addEarlyWarningRadar(earlyWarningRadarUnitName)
ewRadar:setCachedTargetsMaxAge(self:getCachedTargetsMaxAge()) ewRadar:setCachedTargetsMaxAge(self:getCachedTargetsMaxAge())
-- for performance improvement, if iads is not scanning no update coverage update needs to be done, will be executed once when iads activates -- for performance improvement, if iads is not scanning no update coverage update needs to be done, will be executed once when iads activates
if self.ewRadarScanMistTaskID ~= nil then if self.ewRadarScanMistTaskID ~= nil then
self:updateIADSCoverage() self:buildRadarCoverageForEarlyWarningRadar(ewRadar)
end end
ewRadar:setActAsEW(true)
ewRadar:setToCorrectAutonomousState()
ewRadar:goLive() ewRadar:goLive()
table.insert(self.earlyWarningRadars, ewRadar) table.insert(self.earlyWarningRadars, ewRadar)
if self:getDebugSettings().addedEWRadar then if self:getDebugSettings().addedEWRadar then
@ -623,12 +625,12 @@ function SkynetIADS:addSAMSite(samSiteName)
self:setCoalition(samSiteDCS) self:setCoalition(samSiteDCS)
local samSite = SkynetIADSSamSite:create(samSiteDCS, self) local samSite = SkynetIADSSamSite:create(samSiteDCS, self)
samSite:setupElements() samSite:setupElements()
samSite:goLive()
-- for performance improvement, if iads is not scanning no update coverage update needs to be done, will be executed once when iads activates -- for performance improvement, if iads is not scanning no update coverage update needs to be done, will be executed once when iads activates
if self.ewRadarScanMistTaskID ~= nil then if self.ewRadarScanMistTaskID ~= nil then
self:updateIADSCoverage() self:buildRadarCoverageForSAMSite(samSite)
end end
samSite:setCachedTargetsMaxAge(self:getCachedTargetsMaxAge()) samSite:setCachedTargetsMaxAge(self:getCachedTargetsMaxAge())
samSite:goLive()
if samSite:getNatoName() == "UNKNOWN" then if samSite:getNatoName() == "UNKNOWN" then
self:printOutput("you have added an SAM Site that Skynet IADS can not handle: "..samSite:getDCSName(), true) self:printOutput("you have added an SAM Site that Skynet IADS can not handle: "..samSite:getDCSName(), true)
samSite:cleanUp() samSite:cleanUp()
@ -695,48 +697,31 @@ function SkynetIADS:addCommandCenter(commandCenter)
self:setCoalition(commandCenter) self:setCoalition(commandCenter)
local comCenter = SkynetIADSCommandCenter:create(commandCenter, self) local comCenter = SkynetIADSCommandCenter:create(commandCenter, self)
table.insert(self.commandCenters, comCenter) table.insert(self.commandCenters, comCenter)
-- when IADS is active the radars will be added to the new command center. If it not active this will happen when radar coverage is built
if self.ewRadarScanMistTaskID ~= nil then
self:addRadarsToCommandCenters()
end
return comCenter return comCenter
end end
function SkynetIADS:isCommandCenterUsable() function SkynetIADS:isCommandCenterUsable()
local hasWorkingCommandCenter = (#self.commandCenters == 0) if #self:getCommandCenters() == 0 then
for i = 1, #self.commandCenters do return true
local comCenter = self.commandCenters[i]
if comCenter:isDestroyed() == false and comCenter:hasWorkingPowerSource() then
hasWorkingCommandCenter = true
break
else
hasWorkingCommandCenter = false
end
end end
return hasWorkingCommandCenter local usableComCenters = self:getUsableAbstractRadarElemtentsOfTable(self:getCommandCenters())
return (#usableComCenters > 0)
end end
function SkynetIADS:getCommandCenters() function SkynetIADS:getCommandCenters()
return self.commandCenters return self.commandCenters
end end
function SkynetIADS:setSAMSitesToAutonomousMode()
for i= 1, #self.samSites do
samSite = self.samSites[i]
samSite:goAutonomous()
end
end
function SkynetIADS.evaluateContacts(self) function SkynetIADS.evaluateContacts(self)
if self:isCommandCenterUsable() == false then
if self:getDebugSettings().noWorkingCommmandCenter then
self:printOutput("No Working Command Center")
end
self:setSAMSitesToAutonomousMode()
return
end
local ewRadars = self:getUsableEarlyWarningRadars() local ewRadars = self:getUsableEarlyWarningRadars()
local samSites = self:getUsableSAMSites() local samSites = self:getUsableSAMSites()
-- rewrote this part of the code to keep loops to a minimum
--will add SAM Sites acting as EW Rardars to the ewRadars array: --will add SAM Sites acting as EW Rardars to the ewRadars array:
for i = 1, #samSites do for i = 1, #samSites do
local samSite = samSites[i] local samSite = samSites[i]
@ -761,13 +746,13 @@ function SkynetIADS.evaluateContacts(self)
local ewRadar = ewRadars[i] local ewRadar = ewRadars[i]
--call go live in case ewRadar had to shut down (HARM attack) --call go live in case ewRadar had to shut down (HARM attack)
ewRadar:goLive() ewRadar:goLive()
-- if an awacs has traveled more than a predeterminded distance we update the autonomous state of the sams -- if an awacs has traveled more than a predeterminded distance we update the autonomous state of the SAMs
if getmetatable(ewRadar) == SkynetIADSAWACSRadar and ewRadar:isUpdateOfAutonomousStateOfSAMSitesRequired() then if getmetatable(ewRadar) == SkynetIADSAWACSRadar and ewRadar:isUpdateOfAutonomousStateOfSAMSitesRequired() then
self:updateAutonomousStatesOfSAMSites() self:buildRadarCoverageForEarlyWarningRadar(ewRadar)
end end
local ewContacts = ewRadar:getDetectedTargets() local ewContacts = ewRadar:getDetectedTargets()
if #ewContacts > 0 then if #ewContacts > 0 then
local samSitesUnderCoverage = ewRadar:getSAMSitesInCoveredArea() local samSitesUnderCoverage = ewRadar:getUsableChildRadars()
for j = 1, #samSitesUnderCoverage do for j = 1, #samSitesUnderCoverage do
local samSiteUnterCoverage = samSitesUnderCoverage[j] local samSiteUnterCoverage = samSitesUnderCoverage[j]
-- only if a SAM site is not active we add it to the hash of SAM sites to be iterated later on -- only if a SAM site is not active we add it to the hash of SAM sites to be iterated later on
@ -817,62 +802,115 @@ function SkynetIADS:cleanAgedTargets()
self.contacts = contactsToKeep self.contacts = contactsToKeep
end end
function SkynetIADS:buildSAMSitesInCoveredArea() --TODO unit test this method:
local samSites = self:getUsableSAMSites() function SkynetIADS:getAbstracRadarElements()
for i = 1, #samSites do local abstractRadarElements = {}
local samSite = samSites[i] local ewRadars = self:getEarlyWarningRadars()
samSite:updateSAMSitesInCoveredArea() local samSites = self:getSAMSites()
end
local ewRadars = self:getUsableEarlyWarningRadars()
for i = 1, #ewRadars do for i = 1, #ewRadars do
local ewRadar = ewRadars[i] local ewRadar = ewRadars[i]
ewRadar:updateSAMSitesInCoveredArea() table.insert(abstractRadarElements, ewRadar)
end end
end
function SkynetIADS:updateIADSCoverage()
self:buildSAMSitesInCoveredArea()
self:enforceRebuildAutonomousStateOfSAMSites()
--update moose connector with radar group names Skynet is able to use
self:getMooseConnector():update()
end
function SkynetIADS:updateAutonomousStatesOfSAMSites(deadUnit)
--deat unit is to prevent multiple calls via the event handling of SkynetIADSAbstractElement when a units power source or connection node is destroyed
if deadUnit == nil or self.destroyedUnitResponsibleForUpdateAutonomousStateOfSAMSite ~= deadUnit then
self:updateIADSCoverage()
self.destroyedUnitResponsibleForUpdateAutonomousStateOfSAMSite = deadUnit
end
end
function SkynetIADS:enforceRebuildAutonomousStateOfSAMSites()
local ewRadars = self:getUsableEarlyWarningRadars()
local samSites = self:getUsableSAMSites()
for i = 1, #samSites do for i = 1, #samSites do
local samSite = samSites[i] local samSite = samSites[i]
if samSite:getActAsEW() then table.insert(abstractRadarElements, samSite)
table.insert(ewRadars, samSite) end
return abstractRadarElements
end
function SkynetIADS:addRadarsToCommandCenters()
--we clear any existing radars that may have been added earlier
local comCenters = self:getCommandCenters()
for i = 1, #comCenters do
local comCenter = comCenters[i]
comCenter:clearChildRadars()
end
-- then we add child radars to the command centers
local abstractRadarElements = self:getAbstracRadarElements()
for i = 1, #abstractRadarElements do
local abstractRadar = abstractRadarElements[i]
self:addSingleRadarToCommandCenters(abstractRadar)
end end
end end
function SkynetIADS:addSingleRadarToCommandCenters(abstractRadarElement)
local comCenters = self:getCommandCenters()
for i = 1, #comCenters do
local comCenter = comCenters[i]
comCenter:addChildRadar(abstractRadarElement)
end
end
-- this method rebuilds the radar coverage of the IADS, a complete rebuild is only required the first time the IADS is activated
-- during runtime it is sufficient to call buildRadarCoverageForSAMSite or buildRadarCoverageForEarlyWarningRadar method that just updates the IADS for one unit, this saves script execution time
function SkynetIADS:buildRadarCoverage()
--to build the basic radar coverage we use all SAM sites. Checks if SAM site has power or a connection node is done when using the SAM site later on
local samSites = self:getSAMSites()
--first we clear all child and parent radars that may have been added previously
for i = 1, #samSites do for i = 1, #samSites do
local samSite = samSites[i] local samSite = samSites[i]
local inRange = false samSite:clearChildRadars()
for j = 1, #ewRadars do samSite:clearParentRadars()
if samSite:isInRadarDetectionRangeOf(ewRadars[j]) then end
inRange = true
local ewRadars = self:getEarlyWarningRadars()
for i = 1, #ewRadars do
local ewRadar = ewRadars[i]
ewRadar:clearChildRadars()
end
--then we rebuild the radar coverage
local abstractRadarElements = self:getAbstracRadarElements()
for i = 1, #abstractRadarElements do
local abstract = abstractRadarElements[i]
self:buildRadarCoverageForAbstractRadarElement(abstract)
end
self:addRadarsToCommandCenters()
end
function SkynetIADS:buildRadarCoverageForAbstractRadarElement(abstractRadarElement)
local abstractRadarElements = self:getAbstracRadarElements()
for i = 1, #abstractRadarElements do
local aElementToCompare = abstractRadarElements[i]
if aElementToCompare ~= abstractRadarElement then
if aElementToCompare:isInRadarDetectionRangeOf(abstractRadarElement) then
if getmetatable(aElementToCompare) == SkynetIADSSamSite and getmetatable(abstractRadarElement) == SkynetIADSSamSite then
abstractRadarElement:addChildRadar(aElementToCompare)
end
if getmetatable(aElementToCompare) == SkynetIADSSamSite and getmetatable(abstractRadarElement) == SkynetIADSEWRadar then
abstractRadarElement:addChildRadar(aElementToCompare)
end
--EW Radars should not have parent Radars
if getmetatable(aElementToCompare) ~= SkynetIADSEWRadar then
aElementToCompare:addParentRadar(abstractRadarElement)
end
end end
end
if inRange == false then
samSite:goAutonomous()
else
samSite:resetAutonomousState()
end end
end end
end end
function SkynetIADS:buildRadarCoverageForSAMSite(samSite)
self:buildRadarCoverageForAbstractRadarElement(samSite)
self:addSingleRadarToCommandCenters(samSite)
end
function SkynetIADS:buildRadarCoverageForEarlyWarningRadar(ewRadar)
self:buildRadarCoverageForAbstractRadarElement(ewRadar)
self:addSingleRadarToCommandCenters(ewRadar)
end
function SkynetIADS:mergeContact(contact) function SkynetIADS:mergeContact(contact)
local existingContact = false local existingContact = false
for i = 1, #self.contacts do for i = 1, #self.contacts do
@ -887,6 +925,7 @@ function SkynetIADS:mergeContact(contact)
end end
end end
function SkynetIADS:getContacts() function SkynetIADS:getContacts()
return self.contacts return self.contacts
end end
@ -909,7 +948,7 @@ function SkynetIADS.activate(self)
mist.removeFunction(self.ewRadarScanMistTaskID) mist.removeFunction(self.ewRadarScanMistTaskID)
mist.removeFunction(self.samSetupMistTaskID) mist.removeFunction(self.samSetupMistTaskID)
self.ewRadarScanMistTaskID = mist.scheduleFunction(SkynetIADS.evaluateContacts, {self}, 1, self.contactUpdateInterval) self.ewRadarScanMistTaskID = mist.scheduleFunction(SkynetIADS.evaluateContacts, {self}, 1, self.contactUpdateInterval)
self:updateIADSCoverage() self:buildRadarCoverage()
end end
function SkynetIADS:setupSAMSitesAndThenActivate(setupTime) function SkynetIADS:setupSAMSitesAndThenActivate(setupTime)
@ -920,9 +959,7 @@ function SkynetIADS:setupSAMSitesAndThenActivate(setupTime)
for i = 1, #samSites do for i = 1, #samSites do
local sam = samSites[i] local sam = samSites[i]
sam:goLive() sam:goLive()
--stop harm scan, because this function will shut down point defences --point defences will go dark after sam:goLive() call on the SAM they are protecting, so we load them by calling a separate goLive call here, point defence SAMs will therefore receive 2 goLive calls
sam:stopScanningForHARMs()
--point defences will go dark after sam:goLive() call on the SAM they are protecting, so we load them and call a separate goLive call here, some SAMs will therefore receive 2 goLive calls
-- this should not have a negative impact on performance -- this should not have a negative impact on performance
local pointDefences = sam:getPointDefences() local pointDefences = sam:getPointDefences()
for j = 1, #pointDefences do for j = 1, #pointDefences do
@ -930,21 +967,12 @@ function SkynetIADS:setupSAMSitesAndThenActivate(setupTime)
pointDefence:goLive() pointDefence:goLive()
end end
end end
self.samSetupMistTaskID = mist.scheduleFunction(SkynetIADS.postSetupSAMSites, {self}, timer.getTime() + self.samSetupTime) self.samSetupMistTaskID = mist.scheduleFunction(SkynetIADS.activate, {self}, timer.getTime() + self.samSetupTime)
end
function SkynetIADS.postSetupSAMSites(self)
local samSites = self:getSAMSites()
for i = 1, #samSites do
local sam = samSites[i]
--turn on the scan again otherwise SAMs that fired a missile while in setup will not turn off anymore
sam:scanForHarms()
end
self:activate()
end end
function SkynetIADS:deactivate() function SkynetIADS:deactivate()
mist.removeFunction(self.ewRadarScanMistTaskID) mist.removeFunction(self.ewRadarScanMistTaskID)
mist.removeFunction(self.samSetupMistTaskID)
self:deativateSAMSites() self:deativateSAMSites()
self:deactivateEarlyWarningRadars() self:deactivateEarlyWarningRadars()
self:deactivateCommandCenters() self:deactivateCommandCenters()
@ -1062,7 +1090,7 @@ function SkynetIADS:printDetailedEarlyWarningRadarStatus()
local intactPowerSources = numPowerSources - numDamagedPowerSources local intactPowerSources = numPowerSources - numDamagedPowerSources
local detectedTargets = ewRadar:getDetectedTargets() local detectedTargets = ewRadar:getDetectedTargets()
local samSitesInCoveredArea = ewRadar:getSAMSitesInCoveredArea() local samSitesInCoveredArea = ewRadar:getChildRadars()
local unitName = "DESTROYED" local unitName = "DESTROYED"
@ -1137,7 +1165,7 @@ function SkynetIADS:printDetailedSAMSiteStatus()
local detectedTargets = samSite:getDetectedTargets() local detectedTargets = samSite:getDetectedTargets()
local samSitesInCoveredArea = samSite:getSAMSitesInCoveredArea() local samSitesInCoveredArea = samSite:getChildRadars()
env.info("GROUP: "..samSite:getDCSName().." | TYPE: "..samSite:getNatoName()) env.info("GROUP: "..samSite:getDCSName().." | TYPE: "..samSite:getNatoName())
env.info("ACTIVE: "..tostring(isActive).." | AUTONOMOUS: "..tostring(isAutonomous).." | IS ACTING AS EW: "..tostring(samSite:getActAsEW()).." | DETECTED TARGETS: "..#detectedTargets.." | DEFENDING HARM: "..tostring(samSite:isDefendingHARM()).." | MISSILES IN FLIGHT:"..tostring(samSite:getNumberOfMissilesInFlight())) env.info("ACTIVE: "..tostring(isActive).." | AUTONOMOUS: "..tostring(isAutonomous).." | IS ACTING AS EW: "..tostring(samSite:getActAsEW()).." | DETECTED TARGETS: "..#detectedTargets.." | DEFENDING HARM: "..tostring(samSite:isDefendingHARM()).." | MISSILES IN FLIGHT:"..tostring(samSite:getNumberOfMissilesInFlight()))
@ -1180,28 +1208,28 @@ function SkynetIADS:printSystemStatus()
if self:getDebugSettings().IADSStatus then if self:getDebugSettings().IADSStatus then
local numComCenters = #self.commandCenters local numComCenters = #self:getCommandCenters()
local numIntactComCenters = 0
local numDestroyedComCenters = 0 local numDestroyedComCenters = 0
local numComCentersNoPower = 0 local numComCentersNoPower = 0
local numComCentersServingIADS = 0 local numComCentersNoConnectionNode = 0
local numIntactComCenters = 0
for i = 1, #self.commandCenters do for i = 1, #self.commandCenters do
local commandCenter = self.commandCenters[i] local commandCenter = self.commandCenters[i]
if commandCenter:hasWorkingPowerSource() == false then if commandCenter:hasWorkingPowerSource() == false then
numComCentersNoPower = numComCentersNoPower + 1 numComCentersNoPower = numComCentersNoPower + 1
end end
if commandCenter:hasActiveConnectionNode() == false then
numComCentersNoConnectionNode = numComCentersNoConnectionNode + 1
end
if commandCenter:isDestroyed() == false then if commandCenter:isDestroyed() == false then
numIntactComCenters = numIntactComCenters + 1 numIntactComCenters = numIntactComCenters + 1
end end
if commandCenter:isDestroyed() == false and commandCenter:hasWorkingPowerSource() then
numComCentersServingIADS = numComCentersServingIADS + 1
end
end end
numDestroyedComCenters = numComCenters - numIntactComCenters numDestroyedComCenters = numComCenters - numIntactComCenters
self:printOutput("COMMAND CENTERS: Serving IADS: "..numComCentersServingIADS.." | Total: "..numComCenters.." | Intact: "..numIntactComCenters.." | Destroyed: "..numDestroyedComCenters.." | NoPower: "..numComCentersNoPower) self:printOutput("COMMAND CENTERS: "..numComCenters.." | Destroyed: "..numDestroyedComCenters.." | NoPowr: "..numComCentersNoPower.." | NoCon: "..numComCentersNoConnectionNode)
local ewNoPower = 0 local ewNoPower = 0
local ewTotal = #self:getEarlyWarningRadars() local ewTotal = #self:getEarlyWarningRadars()
@ -1224,7 +1252,7 @@ function SkynetIADS:printSystemStatus()
ewRadarsInactive = ewTotal - ewActive ewRadarsInactive = ewTotal - ewActive
local numEWRadarsDestroyed = #self:getDestroyedEarlyWarningRadars() local numEWRadarsDestroyed = #self:getDestroyedEarlyWarningRadars()
self:printOutput("EW: "..ewTotal.." | Act: "..ewActive.." | Inact: "..ewRadarsInactive.." | Destroyed: "..numEWRadarsDestroyed.." | NoPowr: "..ewNoPower.." | NoCon: "..ewNoConnectionNode) self:printOutput("EW: "..ewTotal.." | On: "..ewActive.." | Off: "..ewRadarsInactive.." | Destroyed: "..numEWRadarsDestroyed.." | NoPowr: "..ewNoPower.." | NoCon: "..ewNoConnectionNode)
local samSitesInactive = 0 local samSitesInactive = 0
local samSitesActive = 0 local samSitesActive = 0
@ -1257,7 +1285,7 @@ function SkynetIADS:printSystemStatus()
end end
samSitesInactive = samSitesTotal - samSitesActive samSitesInactive = samSitesTotal - samSitesActive
self:printOutput("SAM: "..samSitesTotal.." | Act: "..samSitesActive.." | Inact: "..samSitesInactive.." | Autonm: "..samSiteAutonomous.." | Raddest: "..samSiteRadarDestroyed.." | NoPowr: "..samSitesNoPower.." | NoCon: "..samSitesNoConnectionNode.." | NoAmmo: "..samSitesOutOfAmmo) self:printOutput("SAM: "..samSitesTotal.." | On: "..samSitesActive.." | Off: "..samSitesInactive.." | Autonm: "..samSiteAutonomous.." | Raddest: "..samSiteRadarDestroyed.." | NoPowr: "..samSitesNoPower.." | NoCon: "..samSitesNoConnectionNode.." | NoAmmo: "..samSitesOutOfAmmo)
end end
if self:getDebugSettings().contacts then if self:getDebugSettings().contacts then
for i = 1, #self.contacts do for i = 1, #self.contacts do
@ -1378,19 +1406,17 @@ function SkynetIADSAbstractDCSObjectWrapper:create(dcsObject)
setmetatable(instance, self) setmetatable(instance, self)
self.__index = self self.__index = self
instance.dcsObject = dcsObject instance.dcsObject = dcsObject
if dcsObject and dcsObject:isExist() and getmetatable(dcsObject) == Unit then instance.name = dcsObject:getName()
--we store inital life here, because getLife0() returs a value that is lower that getLife() when no damage has happened... instance.typeName = dcsObject:getTypeName()
instance.initialLife = dcsObject:getLife()
end
return instance return instance
end end
function SkynetIADSAbstractDCSObjectWrapper:getName() function SkynetIADSAbstractDCSObjectWrapper:getName()
return self.dcsObject:getName() return self.name
end end
function SkynetIADSAbstractDCSObjectWrapper:getTypeName() function SkynetIADSAbstractDCSObjectWrapper:getTypeName()
return self.dcsObject:getTypeName() return self.typeName
end end
function SkynetIADSAbstractDCSObjectWrapper:getPosition() function SkynetIADSAbstractDCSObjectWrapper:getPosition()
@ -1405,20 +1431,12 @@ function SkynetIADSAbstractDCSObjectWrapper:isExist()
end end
end end
function SkynetIADSAbstractDCSObjectWrapper:getLifePercentage()
if self.dcsObject and self.dcsObject:isExist() then
return self.dcsObject:getLife() / self.initialLife * 100
else
return 0
end
end
function SkynetIADSAbstractDCSObjectWrapper:getDCSRepresentation() function SkynetIADSAbstractDCSObjectWrapper:getDCSRepresentation()
return self.dcsObject return self.dcsObject
end end
end end
do do
SkynetIADSAbstractElement = {} SkynetIADSAbstractElement = {}
@ -1451,6 +1469,7 @@ end
function SkynetIADSAbstractElement:addPowerSource(powerSource) function SkynetIADSAbstractElement:addPowerSource(powerSource)
table.insert(self.powerSources, powerSource) table.insert(self.powerSources, powerSource)
self:informChildrenOfStateChange()
return self return self
end end
@ -1460,7 +1479,7 @@ end
function SkynetIADSAbstractElement:addConnectionNode(connectionNode) function SkynetIADSAbstractElement:addConnectionNode(connectionNode)
table.insert(self.connectionNodes, connectionNode) table.insert(self.connectionNodes, connectionNode)
self.iads:updateAutonomousStatesOfSAMSites() self:informChildrenOfStateChange()
return self return self
end end
@ -1526,11 +1545,10 @@ function SkynetIADSAbstractElement:onEvent(event)
if event.id == world.event.S_EVENT_DEAD then if event.id == world.event.S_EVENT_DEAD then
if self:hasWorkingPowerSource() == false or self:isDestroyed() then if self:hasWorkingPowerSource() == false or self:isDestroyed() then
self:goDark() self:goDark()
self.iads:updateAutonomousStatesOfSAMSites(event.initiator) self:informChildrenOfStateChange()
end end
if self:hasActiveConnectionNode() == false then if self:hasActiveConnectionNode() == false then
self:goAutonomous() self:informChildrenOfStateChange()
self.iads:updateAutonomousStatesOfSAMSites(event.initiator)
end end
end end
if event.id == world.event.S_EVENT_SHOT then if event.id == world.event.S_EVENT_SHOT then
@ -1553,6 +1571,16 @@ function SkynetIADSAbstractElement:goAutonomous()
end end
--placeholder method, can be implemented by subclasses
function SkynetIADSAbstractElement:setToCorrectAutonomousState()
end
--placeholder method, can be implemented by subclasses
function SkynetIADSAbstractElement:informChildrenOfStateChange()
end
-- helper code for class inheritance -- helper code for class inheritance
function inheritsFrom( baseClass ) function inheritsFrom( baseClass )
@ -1626,13 +1654,14 @@ function SkynetIADSAbstractRadarElement:create(dcsElementWithRadar, iads)
instance.launchers = {} instance.launchers = {}
instance.trackingRadars = {} instance.trackingRadars = {}
instance.searchRadars = {} instance.searchRadars = {}
instance.samSitesInCoveredArea = {} instance.parentRadars = {}
instance.childRadars = {}
instance.missilesInFlight = {} instance.missilesInFlight = {}
instance.pointDefences = {} instance.pointDefences = {}
instance.ingnoreHARMSWhilePointDefencesHaveAmmo = false instance.ingnoreHARMSWhilePointDefencesHaveAmmo = false
instance.autonomousBehaviour = SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI instance.autonomousBehaviour = SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI
instance.goLiveRange = SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE instance.goLiveRange = SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE
instance.isAutonomous = false instance.isAutonomous = true
instance.harmDetectionChance = 0 instance.harmDetectionChance = 0
instance.minHarmShutdownTime = 0 instance.minHarmShutdownTime = 0
instance.maxHarmShutDownTime = 0 instance.maxHarmShutDownTime = 0
@ -1687,21 +1716,108 @@ function SkynetIADSAbstractRadarElement:getPointDefences()
return self.pointDefences return self.pointDefences
end end
function SkynetIADSAbstractRadarElement:addParentRadar(parentRadar)
function SkynetIADSAbstractRadarElement:updateSAMSitesInCoveredArea() self:abstractAddRadar(parentRadar, self.parentRadars)
local samSites = self.iads:getUsableSAMSites() self:informChildrenOfStateChange()
self.samSitesInCoveredArea = {}
for i = 1, #samSites do
local samSite = samSites[i]
if samSite:isInRadarDetectionRangeOf(self) and samSite ~= self then
table.insert(self.samSitesInCoveredArea, samSite)
end
end
return self.samSitesInCoveredArea
end end
function SkynetIADSAbstractRadarElement:getSAMSitesInCoveredArea() function SkynetIADSAbstractRadarElement:getParentRadars()
return self.samSitesInCoveredArea return self.parentRadars
end
function SkynetIADSAbstractRadarElement:clearParentRadars()
self.parentRadars = {}
end
function SkynetIADSAbstractRadarElement:abstractAddRadar(radar, tbl)
local isAdded = false
for i = 1, #tbl do
local child = tbl[i]
if child == radar then
isAdded = true
end
end
if isAdded == false then
table.insert(tbl, radar)
end
end
function SkynetIADSAbstractRadarElement:addChildRadar(childRadar)
self:abstractAddRadar(childRadar, self.childRadars)
end
function SkynetIADSAbstractRadarElement:getChildRadars()
return self.childRadars
end
function SkynetIADSAbstractRadarElement:clearChildRadars()
self.childRadars = {}
end
--TODO: unit test this method
function SkynetIADSAbstractRadarElement:getUsableChildRadars()
local usableRadars = {}
for i = 1, #self.childRadars do
local childRadar = self.childRadars[i]
if childRadar:hasWorkingPowerSource() and childRadar:hasActiveConnectionNode() then
table.insert(usableRadars, childRadar)
end
end
return usableRadars
end
function SkynetIADSAbstractRadarElement:informChildrenOfStateChange()
self:setToCorrectAutonomousState()
local children = self:getChildRadars()
for i = 1, #children do
local childRadar = children[i]
childRadar:setToCorrectAutonomousState()
end
self.iads:getMooseConnector():update()
end
function SkynetIADSAbstractRadarElement:setToCorrectAutonomousState()
local parents = self:getParentRadars()
for i = 1, #parents do
local parent = parents[i]
--of one parent exists that still is connected to the IADS, the SAM site does not have to go autonomous
--instead of isDestroyed() write method, hasWorkingSearchRadars()
if self:hasActiveConnectionNode() and self.iads:isCommandCenterUsable() and parent:hasWorkingPowerSource() and parent:hasActiveConnectionNode() and parent:getActAsEW() == true and parent:isDestroyed() == false then
self:resetAutonomousState()
return
end
end
self:goAutonomous()
end
function SkynetIADSAbstractRadarElement:setAutonomousBehaviour(mode)
if mode ~= nil then
self.autonomousBehaviour = mode
end
return self
end
function SkynetIADSAbstractRadarElement:getAutonomousBehaviour()
return self.autonomousBehaviour
end
function SkynetIADSAbstractRadarElement:resetAutonomousState()
self.isAutonomous = false
self:goDark()
end
function SkynetIADSAbstractRadarElement:goAutonomous()
self.isAutonomous = true
if self.autonomousBehaviour == SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DARK then
self:goDark()
else
self:goLive()
end
end
function SkynetIADSAbstractRadarElement:getAutonomousState()
return self.isAutonomous
end end
function SkynetIADSAbstractRadarElement:pointDefencesHaveRemainingAmmo(minNumberOfMissiles) function SkynetIADSAbstractRadarElement:pointDefencesHaveRemainingAmmo(minNumberOfMissiles)
@ -1717,7 +1833,7 @@ function SkynetIADSAbstractRadarElement:pointDefencesHaveRemainingAmmo(minNumber
return returnValue return returnValue
end end
function SkynetIADSAbstractElement:pointDefencesHaveEnoughLaunchers(minNumberOfLaunchers) function SkynetIADSAbstractRadarElement:pointDefencesHaveEnoughLaunchers(minNumberOfLaunchers)
local numOfLaunchers = 0 local numOfLaunchers = 0
for i = 1, #self.pointDefences do for i = 1, #self.pointDefences do
local pointDefence = self.pointDefences[i] local pointDefence = self.pointDefences[i]
@ -1730,7 +1846,7 @@ function SkynetIADSAbstractElement:pointDefencesHaveEnoughLaunchers(minNumberOfL
return returnValue return returnValue
end end
function SkynetIADSAbstractElement:setIgnoreHARMSWhilePointDefencesHaveAmmo(state) function SkynetIADSAbstractRadarElement:setIgnoreHARMSWhilePointDefencesHaveAmmo(state)
if state == true or state == false then if state == true or state == false then
self.ingnoreHARMSWhilePointDefencesHaveAmmo = state self.ingnoreHARMSWhilePointDefencesHaveAmmo = state
end end
@ -1770,7 +1886,14 @@ end
function SkynetIADSAbstractRadarElement:setActAsEW(ewState) function SkynetIADSAbstractRadarElement:setActAsEW(ewState)
if ewState == true or ewState == false then if ewState == true or ewState == false then
local stateChange = false
if ewState ~= self.actAsEW then
stateChange = true
end
self.actAsEW = ewState self.actAsEW = ewState
if stateChange then
self:informChildrenOfStateChange()
end
end end
if self.actAsEW == true then if self.actAsEW == true then
self:goLive() self:goLive()
@ -1967,7 +2090,6 @@ end
function SkynetIADSAbstractRadarElement:goLive() function SkynetIADSAbstractRadarElement:goLive()
if ( self.aiState == false and self:hasWorkingPowerSource() and self.harmSilenceID == nil) if ( self.aiState == false and self:hasWorkingPowerSource() and self.harmSilenceID == nil)
and ( (self.isAutonomous == false) or (self.isAutonomous == true and self.autonomousBehaviour == SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI ) )
and (self:hasRemainingAmmo() == true ) and (self:hasRemainingAmmo() == true )
then then
if self:isDestroyed() == false then if self:isDestroyed() == false then
@ -1976,8 +2098,8 @@ function SkynetIADSAbstractRadarElement:goLive()
cont:setOption(AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.RED) cont:setOption(AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.RED)
cont:setOption(AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE) cont:setOption(AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE)
self.goLiveTime = timer.getTime() self.goLiveTime = timer.getTime()
self.aiState = true
end end
self.aiState = true
self:pointDefencesStopActingAsEW() self:pointDefencesStopActingAsEW()
if self.iads:getDebugSettings().radarWentLive then if self.iads:getDebugSettings().radarWentLive then
self.iads:printOutput(self:getDescription().." going live") self.iads:printOutput(self:getDescription().." going live")
@ -1994,21 +2116,9 @@ function SkynetIADSAbstractRadarElement:pointDefencesStopActingAsEW()
end end
function SkynetIADSAbstractRadarElement:noDamageToRadars()
local radars = self:getRadars()
for i = 1, #radars do
local radar = radars[i]
if radar:getLifePercentage() < 100 then
return false
end
end
return true
end
function SkynetIADSAbstractRadarElement:goDark() function SkynetIADSAbstractRadarElement:goDark()
if ( self.aiState == true ) if (self:hasWorkingPowerSource() == false) or ( self.aiState == true )
and (self.harmSilenceID ~= nil or ( self.harmSilenceID == nil and #self:getDetectedTargets() == 0 and self:hasMissilesInFlight() == false) or ( self.harmSilenceID == nil and #self:getDetectedTargets() > 0 and self:hasMissilesInFlight() == false and self:hasRemainingAmmo() == false ) ) and (self.harmSilenceID ~= nil or ( self.harmSilenceID == nil and #self:getDetectedTargets() == 0 and self:hasMissilesInFlight() == false) or ( self.harmSilenceID == nil and #self:getDetectedTargets() > 0 and self:hasMissilesInFlight() == false and self:hasRemainingAmmo() == false ) )
and ( self.isAutonomous == false or ( self.isAutonomous == true and self.autonomousBehaviour == SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DARK ) )
then then
if self:isDestroyed() == false then if self:isDestroyed() == false then
local controller = self:getController() local controller = self:getController()
@ -2108,36 +2218,6 @@ function SkynetIADSAbstractRadarElement:getDistanceToUnit(unitPosA, unitPosB)
return mist.utils.round(mist.utils.get2DDist(unitPosA, unitPosB, 0)) return mist.utils.round(mist.utils.get2DDist(unitPosA, unitPosB, 0))
end end
function SkynetIADSAbstractRadarElement:setAutonomousBehaviour(mode)
if mode ~= nil then
self.autonomousBehaviour = mode
end
return self
end
function SkynetIADSAbstractRadarElement:getAutonomousBehaviour()
return self.autonomousBehaviour
end
function SkynetIADSAbstractRadarElement:resetAutonomousState()
if self.isAutonomous == true then
self.isAutonomous = false
self:goDark()
end
end
function SkynetIADSAbstractRadarElement:goAutonomous()
if self.isAutonomous == false then
self.isAutonomous = true
self:goDark()
self:goLive()
end
end
function SkynetIADSAbstractRadarElement:getAutonomousState()
return self.isAutonomous
end
function SkynetIADSAbstractRadarElement:hasWorkingRadar() function SkynetIADSAbstractRadarElement:hasWorkingRadar()
local radars = self:getRadars() local radars = self:getRadars()
for i = 1, #radars do for i = 1, #radars do
@ -2176,11 +2256,11 @@ function SkynetIADSAbstractRadarElement:scanForHarms()
self.harmScanID = mist.scheduleFunction(SkynetIADSAbstractRadarElement.evaluateIfTargetsContainHARMs, {self}, 1, 2) self.harmScanID = mist.scheduleFunction(SkynetIADSAbstractRadarElement.evaluateIfTargetsContainHARMs, {self}, 1, 2)
end end
function SkynetIADSAbstractElement:isScanningForHARMs() function SkynetIADSAbstractRadarElement:isScanningForHARMs()
return self.harmScanID ~= nil return self.harmScanID ~= nil
end end
function SkynetIADSAbstractElement:isDefendingHARM() function SkynetIADSAbstractRadarElement:isDefendingHARM()
return self.harmSilenceID ~= nil return self.harmSilenceID ~= nil
end end
@ -2191,7 +2271,7 @@ end
function SkynetIADSAbstractRadarElement:goSilentToEvadeHARM(timeToImpact) function SkynetIADSAbstractRadarElement:goSilentToEvadeHARM(timeToImpact)
self:finishHarmDefence(self) self:finishHarmDefence(self)
self.objectsIdentifiedAsHarms = {} --self.objectsIdentifiedAsHarms = {}
local harmTime = self:getHarmShutDownTime() local harmTime = self:getHarmShutDownTime()
if self.iads:getDebugSettings().harmDefence then if self.iads:getDebugSettings().harmDefence then
self.iads:printOutput("HARM DEFENCE: "..self:getDCSName().." shutting down | FOR: "..harmTime.." seconds | TTI: "..timeToImpact) self.iads:printOutput("HARM DEFENCE: "..self:getDCSName().." shutting down | FOR: "..harmTime.." seconds | TTI: "..timeToImpact)
@ -2281,20 +2361,23 @@ end
function SkynetIADSAbstractRadarElement:cleanUpOldObjectsIdentifiedAsHARMS() function SkynetIADSAbstractRadarElement:cleanUpOldObjectsIdentifiedAsHARMS()
local validObjects = {} local validObjects = {}
local validCount = 0
for unitName, unit in pairs(self.objectsIdentifiedAsHarms) do for unitName, unit in pairs(self.objectsIdentifiedAsHarms) do
local harm = unit['target'] local harm = unit['target']
if harm:getAge() <= self.objectsIdentifiedAsHarmsMaxTargetAge then if harm:getAge() <= self.objectsIdentifiedAsHarmsMaxTargetAge then
validObjects[harm:getName()] = {} validObjects[harm:getName()] = {}
validObjects[harm:getName()]['target'] = harm validObjects[harm:getName()]['target'] = harm
validObjects[harm:getName()]['count'] = unit['count'] validObjects[harm:getName()]['count'] = unit['count']
validCount = validCount + 1
end end
end end
self.objectsIdentifiedAsHarms = validObjects --stop point defences acting as ew (always on), will occur if activated via shallIgnoreHARMShutdown() in evaluateIfTargetsContainHARMs
--if in this iteration all harms where cleared we turn of the point defence. But in any other cases we dont turn of point defences, that interferes with other parts of the iads
--stop point defences acting as ew (always on), will occur of activated via shallIgnoreHARMShutdown() in evaluateIfTargetsContainHARMs -- when setting up the iads (letting pds go to read state)
if self:getNumberOfObjectsItentifiedAsHARMS() == 0 then if validCount == 0 and self:getNumberOfObjectsItentifiedAsHARMS() > 0 then
self:pointDefencesStopActingAsEW() self:pointDefencesStopActingAsEW()
end end
self.objectsIdentifiedAsHarms = validObjects
end end
@ -2374,6 +2457,7 @@ function SkynetIADSAWACSRadar:create(radarUnit, iads)
setmetatable(instance, self) setmetatable(instance, self)
self.__index = self self.__index = self
instance.lastUpdatePosition = nil instance.lastUpdatePosition = nil
instance.natoName = radarUnit:getTypeName()
return instance return instance
end end
@ -2384,9 +2468,6 @@ function SkynetIADSAWACSRadar:setupElements()
table.insert(self.searchRadars, radar) table.insert(self.searchRadars, radar)
end end
function SkynetIADSAWACSRadar:getNatoName()
return self:getDCSRepresentation():getTypeName()
end
-- AWACs will not scan for HARMS -- AWACs will not scan for HARMS
function SkynetIADSAWACSRadar:scanForHarms() function SkynetIADSAWACSRadar:scanForHarms()
@ -2394,12 +2475,18 @@ function SkynetIADSAWACSRadar:scanForHarms()
end end
function SkynetIADSAWACSRadar:getMaxAllowedMovementForAutonomousUpdateInNM() function SkynetIADSAWACSRadar:getMaxAllowedMovementForAutonomousUpdateInNM()
local radarRange = mist.utils.metersToNM(self.searchRadars[1]:getMaxRangeFindingTarget()) --local radarRange = mist.utils.metersToNM(self.searchRadars[1]:getMaxRangeFindingTarget())
return mist.utils.round(radarRange / 10) --return mist.utils.round(radarRange / 10)
--fixed to 10 nm miles to better fit small SAM sites
return 10
end end
function SkynetIADSAWACSRadar:isUpdateOfAutonomousStateOfSAMSitesRequired() function SkynetIADSAWACSRadar:isUpdateOfAutonomousStateOfSAMSitesRequired()
return self:getDistanceTraveledSinceLastUpdate() > self:getMaxAllowedMovementForAutonomousUpdateInNM() local isUpdateRequired = self:getDistanceTraveledSinceLastUpdate() > self:getMaxAllowedMovementForAutonomousUpdateInNM()
if isUpdateRequired then
self.lastUpdatePosition = nil
end
return isUpdateRequired
end end
function SkynetIADSAWACSRadar:getDistanceTraveledSinceLastUpdate() function SkynetIADSAWACSRadar:getDistanceTraveledSinceLastUpdate()
@ -2417,7 +2504,7 @@ end
do do
SkynetIADSCommandCenter = {} SkynetIADSCommandCenter = {}
SkynetIADSCommandCenter = inheritsFrom(SkynetIADSAbstractElement) SkynetIADSCommandCenter = inheritsFrom(SkynetIADSAbstractRadarElement)
function SkynetIADSCommandCenter:create(commandCenter, iads) function SkynetIADSCommandCenter:create(commandCenter, iads)
local instance = self:superClass():create(commandCenter, iads) local instance = self:superClass():create(commandCenter, iads)
@ -2427,6 +2514,14 @@ function SkynetIADSCommandCenter:create(commandCenter, iads)
return instance return instance
end end
function SkynetIADSCommandCenter:goDark()
end
function SkynetIADSCommandCenter:goLive()
end
end end
do do
@ -2440,21 +2535,12 @@ function SkynetIADSContact:create(dcsRadarTarget)
instance.firstContactTime = timer.getAbsTime() instance.firstContactTime = timer.getAbsTime()
instance.lastTimeSeen = 0 instance.lastTimeSeen = 0
instance.dcsRadarTarget = dcsRadarTarget instance.dcsRadarTarget = dcsRadarTarget
instance.name = instance.dcsObject:getName()
instance.typeName = instance.dcsObject:getTypeName()
instance.position = instance.dcsObject:getPosition() instance.position = instance.dcsObject:getPosition()
instance.numOfTimesRefreshed = 0 instance.numOfTimesRefreshed = 0
instance.speed = 0 instance.speed = 0
return instance return instance
end end
function SkynetIADSContact:getName()
return self.name
end
function SkynetIADSContact:getTypeName()
return self.typeName
end
function SkynetIADSContact:isTypeKnown() function SkynetIADSContact:isTypeKnown()
return self.dcsRadarTarget.type return self.dcsRadarTarget.type
@ -2520,6 +2606,17 @@ function SkynetIADSEWRadar:create(radarUnit, iads)
return instance return instance
end end
--an Early Warning Radar has simplified check to detrmine if its autonomous or not
function SkynetIADSEWRadar:setToCorrectAutonomousState()
if self:hasActiveConnectionNode() and self:hasWorkingPowerSource() and self.iads:isCommandCenterUsable() then
self:resetAutonomousState()
self:goLive()
end
if self:hasActiveConnectionNode() == false or self.iads:isCommandCenterUsable() == false then
self:goAutonomous()
end
end
end end
do do