mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge pull request #1247 from FlightControl-Master/FF/Develop
ZONE_CAPTURE_COALITION and other fixes
This commit is contained in:
commit
0bb0c70667
@ -287,15 +287,15 @@ function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
-- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
||||
-- @param #AI_A2A_PATROL Fsm The FSM.
|
||||
function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:F( { "AI_A2A_PATROL.PatrolRoute:", AIPatrol:GetName() } )
|
||||
|
||||
if AIPatrol:IsAlive() then
|
||||
if AIPatrol and AIPatrol:IsAlive() then
|
||||
Fsm:Route()
|
||||
end
|
||||
|
||||
@ -309,7 +309,6 @@ end
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
|
||||
|
||||
self:F2()
|
||||
|
||||
-- When RTB, don't allow anymore the routing.
|
||||
|
||||
@ -80,7 +80,8 @@ AI_AIR_ENGAGE = {
|
||||
|
||||
--- Creates a new AI_AIR_ENGAGE object
|
||||
-- @param #AI_AIR_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param AI.AI_Air#AI_AIR AI_Air The AI_AIR FSM.
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AI group.
|
||||
-- @param DCS#Speed EngageMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#Speed EngageMaxSpeed (optional, default = 75% of max speed) The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||
-- @param DCS#Altitude EngageFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the engagement.
|
||||
|
||||
@ -99,7 +99,8 @@ AI_AIR_PATROL = {
|
||||
|
||||
--- Creates a new AI_AIR_PATROL object
|
||||
-- @param #AI_AIR_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param AI.AI_Air#AI_AIR AI_Air The AI_AIR FSM.
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AI group.
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param DCS#Altitude PatrolFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the patrol.
|
||||
-- @param DCS#Altitude PatrolCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the patrol.
|
||||
@ -270,14 +271,15 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
)
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
-- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
||||
-- @param #AI_AIR_PATROL Fsm The FSM.
|
||||
function AI_AIR_PATROL.___PatrolRoute( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:F( { "AI_AIR_PATROL.___PatrolRoute:", AIPatrol:GetName() } )
|
||||
|
||||
if AIPatrol:IsAlive() then
|
||||
if AIPatrol and AIPatrol:IsAlive() then
|
||||
Fsm:PatrolRoute()
|
||||
end
|
||||
|
||||
@ -299,7 +301,7 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
if AIPatrol:IsAlive() then
|
||||
if AIPatrol and AIPatrol:IsAlive() then
|
||||
|
||||
local PatrolRoute = {}
|
||||
|
||||
@ -316,13 +318,7 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
local speedkmh=ToTargetSpeed
|
||||
|
||||
local FromWP = CurrentCoord:WaypointAir(
|
||||
self.PatrolAltType or "RADIO",
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
local FromWP = CurrentCoord:WaypointAir(self.PatrolAltType or "RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
||||
PatrolRoute[#PatrolRoute+1] = FromWP
|
||||
|
||||
if self.racetrack then
|
||||
@ -360,7 +356,8 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
|
||||
|
||||
-- Task function to redo the patrol at other random position.
|
||||
local taskPatrol=AIPatrol:TaskFunction("AI_A2A_PATROL.PatrolRoute", self)
|
||||
--local taskPatrol=AIPatrol:TaskFunction("AI_A2A_PATROL.PatrolRoute", self)
|
||||
local taskPatrol=AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||
|
||||
-- Controlled task with task condition.
|
||||
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
|
||||
@ -372,18 +369,11 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
||||
else
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToWP = ToTargetCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToTargetSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
||||
PatrolRoute[#PatrolRoute+1] = ToWP
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_AIR_PATROL.___PatrolRoute", self )
|
||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
||||
|
||||
end
|
||||
@ -401,7 +391,7 @@ end
|
||||
function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } )
|
||||
if AIPatrol:IsAlive() then
|
||||
if AIPatrol and AIPatrol:IsAlive() then
|
||||
Fsm:__Reset( Fsm.TaskDelay )
|
||||
Fsm:__PatrolRoute( Fsm.TaskDelay )
|
||||
end
|
||||
|
||||
@ -636,7 +636,7 @@ function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
|
||||
|
||||
self.Controllable:OnReSpawn(
|
||||
function( PatrolGroup )
|
||||
self:E( "ReSpawn" )
|
||||
self:T( "ReSpawn" )
|
||||
self:__Reset( 1 )
|
||||
self:__Route( 5 )
|
||||
end
|
||||
@ -741,7 +741,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
-- This will make the plane fly immediately to the patrol zone.
|
||||
|
||||
if self.Controllable:InAir() == false then
|
||||
self:E( "Not in the air, finding route path within PatrolZone" )
|
||||
self:T( "Not in the air, finding route path within PatrolZone" )
|
||||
local CurrentVec2 = self.Controllable:GetVec2()
|
||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
@ -756,7 +756,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
)
|
||||
PatrolRoute[#PatrolRoute+1] = CurrentRoutePoint
|
||||
else
|
||||
self:E( "In the air, finding route path within PatrolZone" )
|
||||
self:T( "In the air, finding route path within PatrolZone" )
|
||||
local CurrentVec2 = self.Controllable:GetVec2()
|
||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
|
||||
@ -187,7 +187,7 @@ end
|
||||
function DATABASE:AddUnit( DCSUnitName )
|
||||
|
||||
if not self.UNITS[DCSUnitName] then
|
||||
self:I( { "Add UNIT:", DCSUnitName } )
|
||||
self:T( { "Add UNIT:", DCSUnitName } )
|
||||
local UnitRegister = UNIT:Register( DCSUnitName )
|
||||
self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
|
||||
|
||||
@ -509,7 +509,7 @@ end
|
||||
function DATABASE:AddGroup( GroupName )
|
||||
|
||||
if not self.GROUPS[GroupName] then
|
||||
self:I( { "Add GROUP:", GroupName } )
|
||||
self:T( { "Add GROUP:", GroupName } )
|
||||
self.GROUPS[GroupName] = GROUP:Register( GroupName )
|
||||
end
|
||||
|
||||
@ -521,7 +521,7 @@ end
|
||||
function DATABASE:AddPlayer( UnitName, PlayerName )
|
||||
|
||||
if PlayerName then
|
||||
self:I( { "Add player for unit:", UnitName, PlayerName } )
|
||||
self:T( { "Add player for unit:", UnitName, PlayerName } )
|
||||
self.PLAYERS[PlayerName] = UnitName
|
||||
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
|
||||
self.PLAYERSJOINED[PlayerName] = PlayerName
|
||||
@ -533,7 +533,7 @@ end
|
||||
function DATABASE:DeletePlayer( UnitName, PlayerName )
|
||||
|
||||
if PlayerName then
|
||||
self:I( { "Clean player:", PlayerName } )
|
||||
self:T( { "Clean player:", PlayerName } )
|
||||
self.PLAYERS[PlayerName] = nil
|
||||
self.PLAYERUNITS[PlayerName] = nil
|
||||
end
|
||||
@ -698,11 +698,11 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||
end
|
||||
|
||||
self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
|
||||
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
|
||||
Country = self.Templates.Groups[GroupTemplateName].CountryID,
|
||||
Units = UnitNames
|
||||
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
|
||||
Country = self.Templates.Groups[GroupTemplateName].CountryID,
|
||||
Units = UnitNames
|
||||
}
|
||||
)
|
||||
end
|
||||
@ -847,9 +847,9 @@ function DATABASE:_RegisterGroupsAndUnits()
|
||||
end
|
||||
end
|
||||
|
||||
self:I("Groups:")
|
||||
self:T("Groups:")
|
||||
for GroupName, Group in pairs( self.GROUPS ) do
|
||||
self:I( { "Group:", GroupName } )
|
||||
self:T( { "Group:", GroupName } )
|
||||
end
|
||||
|
||||
return self
|
||||
@ -861,7 +861,7 @@ end
|
||||
function DATABASE:_RegisterClients()
|
||||
|
||||
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
|
||||
self:I( { "Register Client:", ClientName } )
|
||||
self:T( { "Register Client:", ClientName } )
|
||||
self:AddClient( ClientName )
|
||||
end
|
||||
|
||||
@ -879,7 +879,7 @@ function DATABASE:_RegisterStatics()
|
||||
if DCSStatic:isExist() then
|
||||
local DCSStaticName = DCSStatic:getName()
|
||||
|
||||
self:I( { "Register Static:", DCSStaticName } )
|
||||
self:T( { "Register Static:", DCSStaticName } )
|
||||
self:AddStatic( DCSStaticName )
|
||||
else
|
||||
self:E( { "Static does not exist: ", DCSStatic } )
|
||||
@ -899,7 +899,7 @@ function DATABASE:_RegisterAirbases()
|
||||
|
||||
local DCSAirbaseName = DCSAirbase:getName()
|
||||
|
||||
self:I( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
|
||||
self:T( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
|
||||
self:AddAirbase( DCSAirbaseName )
|
||||
end
|
||||
end
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
|
||||
@ -53,6 +53,19 @@ SCHEDULEDISPATCHER = {
|
||||
Schedule = nil,
|
||||
}
|
||||
|
||||
--- Player data table holding all important parameters of each player.
|
||||
-- @type SCHEDULEDISPATCHER.ScheduleData
|
||||
-- @field #function Function The schedule function to be called.
|
||||
-- @field #table Arguments Schedule function arguments.
|
||||
-- @field #number Start Start time in seconds.
|
||||
-- @field #number Repeat Repeat time intervall in seconds.
|
||||
-- @field #number Randomize Randomization factor [0,1].
|
||||
-- @field #number Stop Stop time in seconds.
|
||||
-- @field #number StartTime Time in seconds when the scheduler is created.
|
||||
-- @field #number ScheduleID Schedule ID.
|
||||
-- @field #function CallHandler Function to be passed to the DCS timer.scheduleFunction().
|
||||
-- @field #boolean ShowTrace If true, show tracing info.
|
||||
|
||||
--- Create a new schedule dispatcher object.
|
||||
-- @param #SCHEDULEDISPATCHER self
|
||||
-- @return #SCHEDULEDISPATCHER self
|
||||
@ -76,7 +89,7 @@ end
|
||||
-- @param #number Stop Stop time in seconds.
|
||||
-- @param #number TraceLevel Trace level [0,3].
|
||||
-- @param Core.Fsm#FSM Fsm Finite state model.
|
||||
-- @return #table Call ID or nil.
|
||||
-- @return #string Call ID or nil.
|
||||
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel, Fsm )
|
||||
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel, Fsm } )
|
||||
|
||||
@ -85,9 +98,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
|
||||
-- Create ID.
|
||||
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
|
||||
|
||||
self:T2(string.format("Adding schedule #%d CallID=%s", self.CallID, CallID))
|
||||
|
||||
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
|
||||
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
|
||||
-- Initialize PersistentSchedulers
|
||||
self.PersistentSchedulers = self.PersistentSchedulers or {}
|
||||
|
||||
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
|
||||
@ -104,11 +118,11 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
|
||||
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
|
||||
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
|
||||
self.Schedule[Scheduler][CallID] = {}
|
||||
self.Schedule[Scheduler][CallID] = {} --#SCHEDULEDISPATCHER.ScheduleData
|
||||
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
||||
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
||||
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
|
||||
self.Schedule[Scheduler][CallID].Start = Start + .1
|
||||
self.Schedule[Scheduler][CallID].Start = Start + 0.1
|
||||
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
||||
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
||||
self.Schedule[Scheduler][CallID].Stop = Stop
|
||||
@ -150,6 +164,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
|
||||
self:T3( self.Schedule[Scheduler][CallID] )
|
||||
|
||||
--- Function passed to the DCS timer.scheduleFunction()
|
||||
self.Schedule[Scheduler][CallID].CallHandler = function( Params )
|
||||
|
||||
local CallID = Params.CallID
|
||||
@ -166,7 +181,8 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
return errmsg
|
||||
end
|
||||
|
||||
local Scheduler = self.ObjectSchedulers[CallID]
|
||||
-- Get object or persistant scheduler object.
|
||||
local Scheduler = self.ObjectSchedulers[CallID] --Core.Scheduler#SCHEDULER
|
||||
if not Scheduler then
|
||||
Scheduler = self.PersistentSchedulers[CallID]
|
||||
end
|
||||
@ -175,20 +191,24 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
|
||||
if Scheduler then
|
||||
|
||||
local MasterObject = tostring(Scheduler.MasterObject)
|
||||
local Schedule = self.Schedule[Scheduler][CallID]
|
||||
local MasterObject = tostring(Scheduler.MasterObject)
|
||||
|
||||
-- Schedule object.
|
||||
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
--self:T3( { Schedule = Schedule } )
|
||||
|
||||
local SchedulerObject = Scheduler.MasterObject --Scheduler.SchedulerObject Now is this the Maste or Scheduler object?
|
||||
local ScheduleFunction = Schedule.Function
|
||||
local ShowTrace = Scheduler.ShowTrace
|
||||
|
||||
local ScheduleFunction = Schedule.Function
|
||||
local ScheduleArguments = Schedule.Arguments or {}
|
||||
local Start = Schedule.Start
|
||||
local Repeat = Schedule.Repeat or 0
|
||||
local Randomize = Schedule.Randomize or 0
|
||||
local Stop = Schedule.Stop or 0
|
||||
local ScheduleID = Schedule.ScheduleID
|
||||
local ShowTrace = Scheduler.ShowTrace
|
||||
local Start = Schedule.Start
|
||||
local Repeat = Schedule.Repeat or 0
|
||||
local Randomize = Schedule.Randomize or 0
|
||||
local Stop = Schedule.Stop or 0
|
||||
local ScheduleID = Schedule.ScheduleID
|
||||
|
||||
|
||||
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
|
||||
|
||||
@ -215,24 +235,20 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local CurrentTime = timer.getTime()
|
||||
local StartTime = Schedule.StartTime
|
||||
|
||||
self:F3( { Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
|
||||
-- Debug info.
|
||||
self:F3( { CallID=CallID, ScheduleID=ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
|
||||
|
||||
|
||||
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
|
||||
|
||||
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
|
||||
local ScheduleTime =
|
||||
CurrentTime +
|
||||
Repeat +
|
||||
math.random(
|
||||
- ( Randomize * Repeat / 2 ),
|
||||
( Randomize * Repeat / 2 )
|
||||
) +
|
||||
0.0001 -- Accuracy
|
||||
local ScheduleTime = CurrentTime + Repeat + math.random(- ( Randomize * Repeat / 2 ), ( Randomize * Repeat / 2 )) + 0.0001 -- Accuracy
|
||||
--self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
|
||||
return ScheduleTime -- returns the next time the function needs to be called.
|
||||
else
|
||||
self:Stop( Scheduler, CallID )
|
||||
end
|
||||
|
||||
else
|
||||
self:Stop( Scheduler, CallID )
|
||||
end
|
||||
@ -265,24 +281,27 @@ end
|
||||
-- @param #SCHEDULEDISPATCHER self
|
||||
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
||||
-- @param #table CallID (Optional) Call ID.
|
||||
-- @param #table CallID Call ID.
|
||||
-- @param #string Info (Optional) Debug info.
|
||||
function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
|
||||
self:F2( { Start = CallID, Scheduler = Scheduler } )
|
||||
|
||||
if CallID then
|
||||
|
||||
local Schedule = self.Schedule[Scheduler]
|
||||
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
-- Only start when there is no ScheduleID defined!
|
||||
-- This prevents to "Start" the scheduler twice with the same CallID...
|
||||
if not Schedule[CallID].ScheduleID then
|
||||
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
|
||||
Schedule[CallID].ScheduleID = timer.scheduleFunction(
|
||||
Schedule[CallID].CallHandler,
|
||||
{ CallID = CallID, Info = Info },
|
||||
timer.getTime() + Schedule[CallID].Start
|
||||
)
|
||||
if not Schedule.ScheduleID then
|
||||
|
||||
-- Current time in seconds.
|
||||
local Tnow=timer.getTime()
|
||||
|
||||
Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started.
|
||||
|
||||
-- Start DCS schedule function https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction
|
||||
Schedule.ScheduleID = timer.scheduleFunction(Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start)
|
||||
|
||||
self:T(string.format("Starting scheduledispatcher Call ID=%s ==> Schedule ID=%s", tostring(CallID), tostring(Schedule.ScheduleID)))
|
||||
end
|
||||
|
||||
else
|
||||
@ -304,12 +323,20 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||
|
||||
if CallID then
|
||||
|
||||
local Schedule = self.Schedule[Scheduler]
|
||||
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
||||
if Schedule[CallID].ScheduleID then
|
||||
timer.removeFunction( Schedule[CallID].ScheduleID )
|
||||
Schedule[CallID].ScheduleID = nil
|
||||
if Schedule.ScheduleID then
|
||||
|
||||
self:T(string.format("scheduledispatcher stopping scheduler CallID=%s, ScheduleID=%s", tostring(CallID), tostring(Schedule.ScheduleID)))
|
||||
|
||||
-- Remove schedule function https://wiki.hoggitworld.com/view/DCS_func_removeFunction
|
||||
timer.removeFunction(Schedule.ScheduleID)
|
||||
|
||||
Schedule.ScheduleID = nil
|
||||
|
||||
else
|
||||
self:E(string.format("Error no ScheduleID for CallID=%s", tostring(CallID)))
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
@ -221,7 +221,7 @@ function SCHEDULER:New( MasterObject, SchedulerFunction, SchedulerArguments, Sta
|
||||
self.ShowTrace = false
|
||||
|
||||
if SchedulerFunction then
|
||||
ScheduleID = self:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, 4 )
|
||||
ScheduleID = self:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, 3 )
|
||||
end
|
||||
|
||||
return self, ScheduleID
|
||||
@ -243,13 +243,17 @@ function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments
|
||||
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
||||
self:T3( { SchedulerArguments } )
|
||||
|
||||
-- Debug info.
|
||||
local ObjectName = "-"
|
||||
if MasterObject and MasterObject.ClassName and MasterObject.ClassID then
|
||||
ObjectName = MasterObject.ClassName .. MasterObject.ClassID
|
||||
end
|
||||
self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } )
|
||||
|
||||
-- Set master object.
|
||||
self.MasterObject = MasterObject
|
||||
|
||||
-- Add schedule.
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
@ -269,32 +273,36 @@ end
|
||||
|
||||
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
|
||||
-- @param #SCHEDULER self
|
||||
-- @param #table ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
||||
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
||||
function SCHEDULER:Start( ScheduleID )
|
||||
self:F3( { ScheduleID } )
|
||||
self:T(string.format("Starting scheduler ID=%s", tostring(ScheduleID)))
|
||||
_SCHEDULEDISPATCHER:Start( self, ScheduleID )
|
||||
end
|
||||
|
||||
--- Stops the schedules or a specific schedule if a valid ScheduleID is provided.
|
||||
-- @param #SCHEDULER self
|
||||
-- @param #table ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
||||
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
||||
function SCHEDULER:Stop( ScheduleID )
|
||||
self:F3( { ScheduleID } )
|
||||
self:T(string.format("Stopping scheduler ID=%s", tostring(ScheduleID)))
|
||||
_SCHEDULEDISPATCHER:Stop( self, ScheduleID )
|
||||
end
|
||||
|
||||
--- Removes a specific schedule if a valid ScheduleID is provided.
|
||||
-- @param #SCHEDULER self
|
||||
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
|
||||
-- @param #string ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
|
||||
function SCHEDULER:Remove( ScheduleID )
|
||||
self:F3( { ScheduleID } )
|
||||
_SCHEDULEDISPATCHER:Remove( self, ScheduleID )
|
||||
self:T(string.format("Removing scheduler ID=%s", tostring(ScheduleID)))
|
||||
_SCHEDULEDISPATCHER:RemoveSchedule( self, ScheduleID )
|
||||
end
|
||||
|
||||
--- Clears all pending schedules.
|
||||
-- @param #SCHEDULER self
|
||||
function SCHEDULER:Clear()
|
||||
self:F3( )
|
||||
self:T(string.format("Clearing scheduler"))
|
||||
_SCHEDULEDISPATCHER:Clear( self )
|
||||
end
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
--- @type ZONE_BASE
|
||||
-- @field #string ZoneName Name of the zone.
|
||||
-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability.
|
||||
-- @extends Core.Base#BASE
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- This class is an abstract BASE class for derived classes, and is not meant to be instantiated.
|
||||
@ -685,30 +685,44 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local function EvaluateZone( ZoneObject )
|
||||
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
|
||||
if ZoneObject then
|
||||
if ZoneObject then
|
||||
|
||||
local ObjectCategory = ZoneObject:getCategory()
|
||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or
|
||||
(ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
||||
|
||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then
|
||||
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
|
||||
local Include = false
|
||||
if not UnitCategories then
|
||||
-- Anythink found is included.
|
||||
Include = true
|
||||
else
|
||||
-- Check if found object is in specified categories.
|
||||
local CategoryDCSUnit = ZoneObject:getDesc().category
|
||||
|
||||
for UnitCategoryID, UnitCategory in pairs( UnitCategories ) do
|
||||
if UnitCategory == CategoryDCSUnit then
|
||||
Include = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if Include then
|
||||
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
|
||||
-- This coalition is inside the zone.
|
||||
self.ScanData.Coalitions[CoalitionDCSUnit] = true
|
||||
|
||||
self.ScanData.Units[ZoneObject] = ZoneObject
|
||||
|
||||
self:F2( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } )
|
||||
end
|
||||
end
|
||||
|
||||
if ObjectCategory == Object.Category.SCENERY then
|
||||
local SceneryType = ZoneObject:getTypeName()
|
||||
local SceneryName = ZoneObject:getName()
|
||||
@ -716,21 +730,29 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||
self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject )
|
||||
self:F2( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Search objects.
|
||||
world.searchObjects( ObjectCategories, SphereSearch, EvaluateZone )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Count the number of different coalitions inside the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #table Table of DCS units and DCS statics inside the zone.
|
||||
function ZONE_RADIUS:GetScannedUnits()
|
||||
|
||||
return self.ScanData.Units
|
||||
end
|
||||
|
||||
|
||||
--- Count the number of different coalitions inside the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return Core.Set#SET_UNIT Set of units and statics inside the zone.
|
||||
function ZONE_RADIUS:GetScannedSetUnit()
|
||||
|
||||
local SetUnit = SET_UNIT:New()
|
||||
@ -756,6 +778,9 @@ function ZONE_RADIUS:GetScannedSetUnit()
|
||||
end
|
||||
|
||||
|
||||
--- Count the number of different coalitions inside the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #number Counted coalitions.
|
||||
function ZONE_RADIUS:CountScannedCoalitions()
|
||||
|
||||
local Count = 0
|
||||
@ -763,14 +788,25 @@ function ZONE_RADIUS:CountScannedCoalitions()
|
||||
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
|
||||
Count = Count + 1
|
||||
end
|
||||
|
||||
return Count
|
||||
end
|
||||
|
||||
--- Check if a certain coalition is inside a scanned zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number Coalition The coalition id, e.g. coalition.side.BLUE.
|
||||
-- @return #boolean If true, the coalition is inside the zone.
|
||||
function ZONE_RADIUS:CheckScannedCoalition( Coalition )
|
||||
if Coalition then
|
||||
return self.ScanData.Coalitions[Coalition]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get Coalitions of the units in the Zone, or Check if there are units of the given Coalition in the Zone.
|
||||
-- Returns nil if there are none ot two Coalitions in the zone!
|
||||
-- Returns nil if there are none to two Coalitions in the zone!
|
||||
-- Returns one Coalition if there are only Units of one Coalition in the Zone.
|
||||
-- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone
|
||||
-- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #table
|
||||
function ZONE_RADIUS:GetScannedCoalition( Coalition )
|
||||
@ -795,20 +831,27 @@ function ZONE_RADIUS:GetScannedCoalition( Coalition )
|
||||
end
|
||||
|
||||
|
||||
--- Get scanned scenery type
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #table Table of DCS scenery type objects.
|
||||
function ZONE_RADIUS:GetScannedSceneryType( SceneryType )
|
||||
return self.ScanData.Scenery[SceneryType]
|
||||
end
|
||||
|
||||
|
||||
--- Get scanned scenery table
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #table Table of DCS scenery objects.
|
||||
function ZONE_RADIUS:GetScannedScenery()
|
||||
return self.ScanData.Scenery
|
||||
end
|
||||
|
||||
|
||||
--- Is All in Zone of Coalition?
|
||||
-- Check if only the specifed coalition is inside the zone and noone else.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
-- @param #number Coalition Coalition ID of the coalition which is checked to be the only one in the zone.
|
||||
-- @return #boolean True, if **only** that coalition is inside the zone and no one else.
|
||||
-- @usage
|
||||
-- self.Zone:Scan()
|
||||
-- local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
|
||||
@ -820,11 +863,12 @@ end
|
||||
|
||||
|
||||
--- Is All in Zone of Other Coalition?
|
||||
-- Check if only one coalition is inside the zone and the specified coalition is not the one.
|
||||
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
|
||||
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
-- @param #number Coalition Coalition ID of the coalition which is not supposed to be in the zone.
|
||||
-- @return #boolean True, if and only if only one coalition is inside the zone and the specified coalition is not it.
|
||||
-- @usage
|
||||
-- self.Zone:Scan()
|
||||
-- local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
@ -836,11 +880,12 @@ end
|
||||
|
||||
|
||||
--- Is Some in Zone of Coalition?
|
||||
-- Check if more than one coaltion is inside the zone and the specifed coalition is one of them.
|
||||
-- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated!
|
||||
-- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
-- @param #number Coalition ID of the coaliton which is checked to be inside the zone.
|
||||
-- @return #boolean True if more than one coalition is inside the zone and the specified coalition is one of them.
|
||||
-- @usage
|
||||
-- self.Zone:Scan()
|
||||
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
|
||||
@ -550,7 +550,7 @@ RAT.id="RAT | "
|
||||
--- RAT version.
|
||||
-- @list version
|
||||
RAT.version={
|
||||
version = "2.3.8",
|
||||
version = "2.3.9",
|
||||
print = true,
|
||||
}
|
||||
|
||||
@ -5173,6 +5173,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
|
||||
if self.uncontrolled then
|
||||
-- This is used in the SPAWN:SpawnWithIndex() function. Some values are overwritten there!
|
||||
self.SpawnUnControlled=true
|
||||
SpawnTemplate.uncontrolled=true
|
||||
end
|
||||
|
||||
-- Number of units in the group. With grouping this can actually differ from the template group size!
|
||||
|
||||
@ -516,7 +516,7 @@ RANGE.MenuF10Root=nil
|
||||
|
||||
--- Range script version.
|
||||
-- @field #string version
|
||||
RANGE.version="2.2.0"
|
||||
RANGE.version="2.2.1"
|
||||
|
||||
--TODO list:
|
||||
--TODO: Verbosity level for messages.
|
||||
@ -2521,10 +2521,17 @@ function RANGE:_DisplayBombTargets(_unitname)
|
||||
local coord=self:_GetBombTargetCoordinate(bombtarget)
|
||||
|
||||
if coord then
|
||||
|
||||
-- Get elevation
|
||||
local elevation=coord:GetLandHeight()
|
||||
local eltxt=string.format("%d m", elevation)
|
||||
if _settings:IsImperial() then
|
||||
elevation=UTILS.MetersToFeet(elevation)
|
||||
eltxt=string.format("%d ft", elevation)
|
||||
end
|
||||
|
||||
local ca2g=coord:ToStringA2G(_unit,_settings)
|
||||
--local lldms=coord:ToStringLLDMS(_settings)
|
||||
_text=_text..string.format("\n- %s:\n%s", bombtarget.name or "unknown", ca2g)
|
||||
_text=_text..string.format("\n- %s:\n%s @ %s", bombtarget.name or "unknown", ca2g, eltxt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -868,13 +868,15 @@ end
|
||||
-- @param #boolean message Send message to all players.
|
||||
function SUPPRESSION:StatusReport(message)
|
||||
|
||||
local name=self.Controllable:GetName()
|
||||
local nunits=#self.Controllable:GetUnits()
|
||||
local group=self.Controllable --Wrapper.Group#GROUP
|
||||
|
||||
local nunits=group:CountAliveUnits()
|
||||
local roe=self.CurrentROE
|
||||
local state=self.CurrentAlarmState
|
||||
local life_min, life_max, life_ave, life_ave0, groupstrength=self:_GetLife()
|
||||
local at=self.Controllable:GetAmmunition()
|
||||
local ammotot=self.Controllable:GetAmmunition()
|
||||
|
||||
--[[
|
||||
local text=string.format("Status of group %s\n", name)
|
||||
text=text..string.format("Number of units: %d of %d\n", nunits, self.IniGroupStrength)
|
||||
text=text..string.format("Current state: %s\n", self:GetState())
|
||||
@ -887,6 +889,10 @@ function SUPPRESSION:StatusReport(message)
|
||||
text=text..string.format("Life ave0: %3.0f\n", life_ave0)
|
||||
text=text..string.format("Ammo tot: %d\n", at)
|
||||
text=text..string.format("Group strength: %3.0f", groupstrength)
|
||||
]]
|
||||
|
||||
local text=string.format("State %s, Units=%d/%d, ROE=%s Alarm State=%s, Hits=%d, Life=%d/%d/%d/%d, Ammo=%d",
|
||||
self:GetState(), nunits, self.IniGroupStrength, self.CurrentROE, self.CurrentAlarmState, self.Nhit, life_min, life_max, life_ave, life_ave0, ammotot)
|
||||
|
||||
MESSAGE:New(text, 10):ToAllIf(message or self.Debug)
|
||||
self:I(self.lid.."\n"..text)
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions: **Millertime** - Concept
|
||||
-- ### Contributions: **Millertime** - Concept, **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@ -49,6 +49,15 @@
|
||||
do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
--- @type ZONE_CAPTURE_COALITION
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number MarkBlue ID of blue F10 mark.
|
||||
-- @field #number MarkRed ID of red F10 mark.
|
||||
-- @field #number StartInterval Time in seconds after the status monitor is started.
|
||||
-- @field #number RepeatInterval Time in seconds after which the zone status is updated.
|
||||
-- @field #boolean HitsOn If true, hit events are monitored and trigger the "Attack" event when a defending unit is hit.
|
||||
-- @field #number HitTimeLast Time stamp in seconds when the last unit inside the zone was hit.
|
||||
-- @field #number HitTimeAttackOver Time interval in seconds before the zone goes from "Attacked" to "Guarded" state after the last hit.
|
||||
-- @field #boolean MarkOn If true, create marks of zone status on F10 map.
|
||||
-- @extends Functional.ZoneGoalCoalition#ZONE_GOAL_COALITION
|
||||
|
||||
|
||||
@ -197,8 +206,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
--
|
||||
-- ### IMPORTANT
|
||||
--
|
||||
-- **Each capture zone object must have the monitoring process started specifically.
|
||||
-- The monitoring process is NOT started by default!!!**
|
||||
-- **Each capture zone object must have the monitoring process started specifically. The monitoring process is NOT started by default!**
|
||||
--
|
||||
--
|
||||
-- # Full Example
|
||||
@ -338,29 +346,48 @@ do -- ZONE_CAPTURE_COALITION
|
||||
--
|
||||
-- @field #ZONE_CAPTURE_COALITION
|
||||
ZONE_CAPTURE_COALITION = {
|
||||
ClassName = "ZONE_CAPTURE_COALITION",
|
||||
ClassName = "ZONE_CAPTURE_COALITION",
|
||||
MarkBlue = nil,
|
||||
MarkRed = nil,
|
||||
StartInterval = nil,
|
||||
RepeatInterval = nil,
|
||||
HitsOn = nil,
|
||||
HitTimeLast = nil,
|
||||
HitTimeAttackOver = nil,
|
||||
MarkOn = nil,
|
||||
}
|
||||
|
||||
--- @field #table ZONE_CAPTURE_COALITION.States
|
||||
ZONE_CAPTURE_COALITION.States = {}
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor and Start/Stop Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- ZONE_CAPTURE_COALITION Constructor.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.
|
||||
-- @return #ZONE_CAPTURE_COALITION
|
||||
-- @usage
|
||||
--
|
||||
-- AttackZone = ZONE:New( "AttackZone" )
|
||||
--
|
||||
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( AttackZone, coalition.side.RED ) -- Create a new ZONE_CAPTURE_COALITION object of zone AttackZone with ownership RED coalition.
|
||||
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( AttackZone, coalition.side.RED, {UNITS ) -- Create a new ZONE_CAPTURE_COALITION object of zone AttackZone with ownership RED coalition.
|
||||
-- ZoneCaptureCoalition:__Guard( 1 ) -- Start the Guarding of the AttackZone.
|
||||
--
|
||||
function ZONE_CAPTURE_COALITION:New( Zone, Coalition, UnitCategories )
|
||||
function ZONE_CAPTURE_COALITION:New( Zone, Coalition, UnitCategories, ObjectCategories )
|
||||
|
||||
local self = BASE:Inherit( self, ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories ) ) -- #ZONE_CAPTURE_COALITION
|
||||
|
||||
self:F( { Zone = Zone, Coalition = Coalition, UnitCategories = UnitCategories } )
|
||||
self:F( { Zone = Zone, Coalition = Coalition, UnitCategories = UnitCategories, ObjectCategories = ObjectCategories } )
|
||||
|
||||
self:SetObjectCategories(ObjectCategories)
|
||||
|
||||
-- Default is no smoke.
|
||||
self:SetSmokeZone(false)
|
||||
-- Default is F10 marks ON.
|
||||
self:SetMarkZone(true)
|
||||
-- Start in state "Empty".
|
||||
self:SetStartState("Empty")
|
||||
|
||||
do
|
||||
|
||||
@ -545,184 +572,12 @@ do -- ZONE_CAPTURE_COALITION
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #number Delay
|
||||
|
||||
-- We check if a unit within the zone is hit.
|
||||
-- If it is, then we must move the zone to attack state.
|
||||
self:HandleEvent( EVENTS.Hit, self.OnEventHit )
|
||||
|
||||
-- ZoneGoal objects are added to the _DATABASE.ZONES_GOAL and SET_ZONE_GOAL sets.
|
||||
_EVENTDISPATCHER:CreateEventNewZoneGoal( self )
|
||||
_EVENTDISPATCHER:CreateEventNewZoneGoal(self)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||
|
||||
self:F({"hello"})
|
||||
|
||||
self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self )
|
||||
|
||||
self.Goal:Achieved()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsGuarded()
|
||||
|
||||
local IsGuarded = self:IsAllInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsGuarded = IsGuarded } )
|
||||
return IsGuarded
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsEmpty()
|
||||
|
||||
local IsEmpty = self:IsNoneInZone()
|
||||
self:F( { IsEmpty = IsEmpty } )
|
||||
return IsEmpty
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:F( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Mark.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:Mark()
|
||||
|
||||
local Coord = self:GetCoordinate()
|
||||
local ZoneName = self:GetZoneName()
|
||||
local State = self:GetState()
|
||||
|
||||
if self.MarkRed and self.MarkBlue then
|
||||
self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
|
||||
Coord:RemoveMark( self.MarkRed )
|
||||
Coord:RemoveMark( self.MarkBlue )
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
else
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
end
|
||||
end
|
||||
|
||||
--- Bound.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterGuarded()
|
||||
|
||||
--self:GetParent( self ):onenterGuarded()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
--elf.ProtectZone:BoundZone( 12, country.id.USA )
|
||||
else
|
||||
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
|
||||
end
|
||||
|
||||
self:Mark()
|
||||
|
||||
end
|
||||
|
||||
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||
|
||||
--self:GetParent( self ):onenterCaptured()
|
||||
|
||||
local NewCoalition = self:GetScannedCoalition()
|
||||
self:F( { NewCoalition = NewCoalition } )
|
||||
self:SetCoalition( NewCoalition )
|
||||
|
||||
self:Mark()
|
||||
self.Goal:Achieved()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:onenterEmpty()
|
||||
|
||||
--self:GetParent( self ):onenterEmpty()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:onenterAttacked()
|
||||
|
||||
--self:GetParent( self ):onenterAttacked()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
--- When started, check the Coalition status.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onafterGuard()
|
||||
|
||||
--self:F({BASE:GetParent( self )})
|
||||
--BASE:GetParent( self ).onafterGuard( self )
|
||||
|
||||
if not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 0.1, nil, self.StatusSmoke, self )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:F( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:StatusZone()
|
||||
|
||||
local State = self:GetState()
|
||||
self:F( { State = self:GetState() } )
|
||||
|
||||
self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self )
|
||||
|
||||
if State ~= "Guarded" and self:IsGuarded() then
|
||||
self:Guard()
|
||||
end
|
||||
|
||||
if State ~= "Empty" and self:IsEmpty() then
|
||||
self:Empty()
|
||||
end
|
||||
|
||||
if State ~= "Attacked" and self:IsAttacked() then
|
||||
self:Attack()
|
||||
end
|
||||
|
||||
if State ~= "Captured" and self:IsCaptured() then
|
||||
self:Capture()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Starts the zone capturing monitoring process.
|
||||
-- This process can be CPU intensive, ensure that you specify reasonable time intervals for the monitoring process.
|
||||
@ -733,6 +588,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #number StartInterval (optional) Specifies the start time interval in seconds when the zone state will be checked for the first time.
|
||||
-- @param #number RepeatInterval (optional) Specifies the repeat time interval in seconds when the zone state will be checked repeatedly.
|
||||
-- @return #ZONE_CAPTURE_COALITION self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Setup the zone.
|
||||
@ -747,13 +603,23 @@ do -- ZONE_CAPTURE_COALITION
|
||||
--
|
||||
function ZONE_CAPTURE_COALITION:Start( StartInterval, RepeatInterval )
|
||||
|
||||
self.StartInterval = StartInterval or 15
|
||||
self.StartInterval = StartInterval or 1
|
||||
self.RepeatInterval = RepeatInterval or 15
|
||||
|
||||
if self.ScheduleStatusZone then
|
||||
self:ScheduleStop( self.ScheduleStatusZone )
|
||||
end
|
||||
self.ScheduleStatusZone = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 1.5, nil, self.StatusZone, self )
|
||||
|
||||
-- Start Status scheduler.
|
||||
self.ScheduleStatusZone = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 0.1, nil, self.StatusZone, self )
|
||||
|
||||
-- We check if a unit within the zone is hit. If it is, then we must move the zone to attack state.
|
||||
self:HandleEvent(EVENTS.Hit, self.OnEventHit)
|
||||
|
||||
-- Create mark on F10 map.
|
||||
self:Mark()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@ -795,24 +661,266 @@ do -- ZONE_CAPTURE_COALITION
|
||||
function ZONE_CAPTURE_COALITION:Stop()
|
||||
|
||||
if self.ScheduleStatusZone then
|
||||
self:ScheduleStop( self.ScheduleStatusZone )
|
||||
self:ScheduleStop(self.ScheduleStatusZone)
|
||||
end
|
||||
|
||||
if self.SmokeScheduler then
|
||||
self:ScheduleStop(self.SmokeScheduler)
|
||||
end
|
||||
|
||||
self:UnHandleEvent(EVENTS.Hit)
|
||||
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User API Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Set whether hit events of defending units are monitored and trigger "Attack" events.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #boolean Switch If *true*, hit events are monitored. If *false* or *nil*, hit events are not monitored.
|
||||
-- @param #number TimeAttackOver (Optional) Time in seconds after an attack is over after the last hit and the zone state goes to "Guarded". Default is 300 sec = 5 min.
|
||||
-- @return #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:SetMonitorHits(Switch, TimeAttackOver)
|
||||
self.HitsOn=Switch
|
||||
self.HitTimeAttackOver=TimeAttackOver or 5*60
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set whether marks on the F10 map are shown, which display the current zone status.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #boolean Switch If *true* or *nil*, marks are shown. If *false*, marks are not displayed.
|
||||
-- @return #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:SetMarkZone(Switch)
|
||||
if Switch==nil or Switch==true then
|
||||
self.MarkOn=true
|
||||
else
|
||||
self.MarkOn=false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- DCS Event Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--- @param #ZONE_CAPTURE_COALITION self
|
||||
--- Monitor hit events.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param Core.Event#EVENTDATA EventData The event data.
|
||||
function ZONE_CAPTURE_COALITION:OnEventHit( EventData )
|
||||
|
||||
local UnitHit = EventData.TgtUnit
|
||||
|
||||
if UnitHit then
|
||||
if UnitHit:IsInZone( self ) then
|
||||
self:Attack()
|
||||
if self.HitsOn then
|
||||
|
||||
local UnitHit = EventData.TgtUnit
|
||||
|
||||
-- Check if unit is inside the capture zone and that it is of the defending coalition.
|
||||
if UnitHit and UnitHit:IsInZone(self) and UnitHit:GetCoalition()==self.Coalition then
|
||||
|
||||
-- Update last hit time.
|
||||
self.HitTimeLast=timer.getTime()
|
||||
|
||||
-- Only trigger attacked event if not already in state "Attacked".
|
||||
if self:GetState()~="Attacked" then
|
||||
self:F2("Hit ==> Attack")
|
||||
self:Attack()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FSM Event Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- On after "Guard" event.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onafterGuard()
|
||||
self:F2("After Guard")
|
||||
|
||||
if self.SmokeZone and not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 0.1, nil, self.StatusSmoke, self )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- On enter "Guarded" state.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterGuarded()
|
||||
self:F2("Enter Guarded")
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
--- On enter "Captured" state.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||
self:F2("Enter Captured")
|
||||
|
||||
-- Get new coalition.
|
||||
local NewCoalition = self:GetScannedCoalition()
|
||||
self:F( { NewCoalition = NewCoalition } )
|
||||
|
||||
-- Set new owner of zone.
|
||||
self:SetCoalition(NewCoalition)
|
||||
|
||||
-- Update mark.
|
||||
self:Mark()
|
||||
|
||||
-- Goal achieved.
|
||||
self.Goal:Achieved()
|
||||
end
|
||||
|
||||
--- On enter "Empty" state.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterEmpty()
|
||||
self:F2("Enter Empty")
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
--- On enter "Attacked" state.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterAttacked()
|
||||
self:F2("Enter Attacked")
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Status Check Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Check if zone is "Empty".
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @return #boolean self:IsNoneInZone()
|
||||
function ZONE_CAPTURE_COALITION:IsEmpty()
|
||||
|
||||
local IsEmpty = self:IsNoneInZone()
|
||||
self:F( { IsEmpty = IsEmpty } )
|
||||
|
||||
return IsEmpty
|
||||
end
|
||||
|
||||
--- Check if zone is "Guarded", i.e. only one (the defending) coaliton is present inside the zone.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @return #boolean self:IsAllInZoneOfCoalition( self.Coalition )
|
||||
function ZONE_CAPTURE_COALITION:IsGuarded()
|
||||
|
||||
local IsGuarded = self:IsAllInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsGuarded = IsGuarded } )
|
||||
|
||||
return IsGuarded
|
||||
end
|
||||
|
||||
--- Check if zone is "Captured", i.e. another coalition took control over the zone and is the only one present.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @return #boolean self:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:F( { IsCaptured = IsCaptured } )
|
||||
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
--- Check if zone is "Attacked", i.e. another coaliton entered the zone.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsAttacked = IsAttacked } )
|
||||
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:StatusZone()
|
||||
|
||||
-- Get FSM state.
|
||||
local State = self:GetState()
|
||||
|
||||
-- Scan zone in parent class ZONE_GOAL_COALITION
|
||||
self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self )
|
||||
|
||||
local Tnow=timer.getTime()
|
||||
|
||||
-- Check if zone is guarded.
|
||||
if State ~= "Guarded" and self:IsGuarded() then
|
||||
|
||||
-- Check that there was a sufficient amount of time after the last hit before going back to "Guarded".
|
||||
if self.HitTimeLast==nil or Tnow>=self.HitTimeLast+self.HitTimeAttackOver then
|
||||
self:Guard()
|
||||
self.HitTimeLast=nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if zone is empty.
|
||||
if State ~= "Empty" and self:IsEmpty() then
|
||||
self:Empty()
|
||||
end
|
||||
|
||||
-- Check if zone is attacked.
|
||||
if State ~= "Attacked" and self:IsAttacked() then
|
||||
self:Attack()
|
||||
end
|
||||
|
||||
-- Check if zone is captured.
|
||||
if State ~= "Captured" and self:IsCaptured() then
|
||||
self:Capture()
|
||||
end
|
||||
|
||||
-- Status text.
|
||||
local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), State)
|
||||
local NewState = self:GetState()
|
||||
if NewState~=State then
|
||||
text=text..string.format(" --> %s", NewState)
|
||||
end
|
||||
self:I(text)
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--- Update Mark on F10 map.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:Mark()
|
||||
|
||||
if self.MarkOn then
|
||||
|
||||
local Coord = self:GetCoordinate()
|
||||
local ZoneName = self:GetZoneName()
|
||||
local State = self:GetState()
|
||||
|
||||
-- Remove marks.
|
||||
if self.MarkRed then
|
||||
Coord:RemoveMark(self.MarkRed)
|
||||
end
|
||||
if self.MarkBlue then
|
||||
Coord:RemoveMark(self.MarkBlue)
|
||||
end
|
||||
|
||||
-- Create new marks for each coaliton.
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
elseif self.Coalition == coalition.side.RED then
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
else
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Neutral\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Neutral\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@ -17,10 +18,16 @@
|
||||
do -- Zone
|
||||
|
||||
--- @type ZONE_GOAL
|
||||
-- @extends Core.Fsm#FSM
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field Core.Goal#GOAL Goal The goal object.
|
||||
-- @field #number SmokeTime Time stamp in seconds when the last smoke of the zone was triggered.
|
||||
-- @field Core.Scheduler#SCHEDULER SmokeScheduler Scheduler responsible for smoking the zone.
|
||||
-- @field #number SmokeColor Color of the smoke.
|
||||
-- @field #boolean SmokeZone If true, smoke zone.
|
||||
-- @extends Core.Zone#ZONE_RADIUS
|
||||
|
||||
|
||||
-- Models processes that have a Goal with a defined achievement involving a Zone.
|
||||
--- Models processes that have a Goal with a defined achievement involving a Zone.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ## 1. ZONE_GOAL constructor
|
||||
@ -39,7 +46,12 @@ do -- Zone
|
||||
--
|
||||
-- @field #ZONE_GOAL
|
||||
ZONE_GOAL = {
|
||||
ClassName = "ZONE_GOAL",
|
||||
ClassName = "ZONE_GOAL",
|
||||
Goal = nil,
|
||||
SmokeTime = nil,
|
||||
SmokeScheduler = nil,
|
||||
SmokeColor = nil,
|
||||
SmokeZone = nil,
|
||||
}
|
||||
|
||||
--- ZONE_GOAL Constructor.
|
||||
@ -51,11 +63,24 @@ do -- Zone
|
||||
local self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
|
||||
self:F( { Zone = Zone } )
|
||||
|
||||
-- Goal object.
|
||||
self.Goal = GOAL:New()
|
||||
|
||||
self.SmokeTime = nil
|
||||
|
||||
-- Set smoke ON.
|
||||
self:SetSmokeZone(true)
|
||||
|
||||
self:AddTransition( "*", "DestroyedUnit", "*" )
|
||||
|
||||
--- DestroyedUnit event.
|
||||
-- @function [parent=#ZONE_GOAL] DestroyedUnit
|
||||
-- @param #ZONE_GOAL self
|
||||
|
||||
--- DestroyedUnit delayed event
|
||||
-- @function [parent=#ZONE_GOAL] __DestroyedUnit
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
|
||||
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
|
||||
@ -66,19 +91,18 @@ do -- Zone
|
||||
-- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the Zone
|
||||
--- Get the Zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return Core.Zone#ZONE_BASE
|
||||
-- @return #ZONE_GOAL
|
||||
function ZONE_GOAL:GetZone()
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the name of the ProtectZone
|
||||
--- Get the name of the Zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return #string
|
||||
function ZONE_GOAL:GetZoneName()
|
||||
@ -86,36 +110,48 @@ do -- Zone
|
||||
end
|
||||
|
||||
|
||||
--- Smoke the center of theh zone.
|
||||
--- Activate smoking of zone with the color or the current owner.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #SMOKECOLOR.Color SmokeColor
|
||||
function ZONE_GOAL:Smoke( SmokeColor )
|
||||
|
||||
-- @param #boolean switch If *true* or *nil* activate smoke. If *false* or *nil*, no smoke.
|
||||
-- @return #ZONE_GOAL
|
||||
function ZONE_GOAL:SetSmokeZone(switch)
|
||||
self.SmokeZone=switch
|
||||
--[[
|
||||
if switch==nil or switch==true then
|
||||
self.SmokeZone=true
|
||||
else
|
||||
self.SmokeZone=false
|
||||
end
|
||||
]]
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the smoke color.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param DCS#SMOKECOLOR.Color SmokeColor
|
||||
function ZONE_GOAL:Smoke( SmokeColor )
|
||||
self:F( { SmokeColor = SmokeColor} )
|
||||
|
||||
self.SmokeColor = SmokeColor
|
||||
end
|
||||
|
||||
|
||||
--- Flare the center of the zone.
|
||||
--- Flare the zone boundary.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #SMOKECOLOR.Color FlareColor
|
||||
-- @param DCS#SMOKECOLOR.Color FlareColor
|
||||
function ZONE_GOAL:Flare( FlareColor )
|
||||
self:FlareZone( FlareColor, math.random( 1, 360 ) )
|
||||
self:FlareZone( FlareColor, 30)
|
||||
end
|
||||
|
||||
|
||||
--- When started, check the Smoke and the Zone status.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:onafterGuard()
|
||||
|
||||
--self:GetParent( self ):onafterStart()
|
||||
|
||||
self:F("Guard")
|
||||
|
||||
--self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
|
||||
if not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||
|
||||
-- Start smoke
|
||||
if self.SmokeZone and not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat(1, 1, 0.1, nil, self.StatusSmoke, self)
|
||||
end
|
||||
end
|
||||
|
||||
@ -123,42 +159,54 @@ do -- Zone
|
||||
--- Check status Smoke.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:StatusSmoke()
|
||||
|
||||
self:F({self.SmokeTime, self.SmokeColor})
|
||||
|
||||
local CurrentTime = timer.getTime()
|
||||
|
||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||
if self.SmokeColor then
|
||||
self:GetCoordinate():Smoke( self.SmokeColor )
|
||||
--self.SmokeColor = nil
|
||||
self.SmokeTime = CurrentTime
|
||||
if self.SmokeZone then
|
||||
|
||||
-- Current time.
|
||||
local CurrentTime = timer.getTime()
|
||||
|
||||
-- Restart smoke every 5 min.
|
||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||
if self.SmokeColor then
|
||||
self:GetCoordinate():Smoke( self.SmokeColor )
|
||||
self.SmokeTime = CurrentTime
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||
function ZONE_GOAL:__Destroyed( EventData )
|
||||
self:F( { "EventDead", EventData } )
|
||||
|
||||
self:F( { EventData.IniUnit } )
|
||||
|
||||
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||
self:F( { Vec3 = Vec3 } )
|
||||
|
||||
if EventData.IniDCSUnit then
|
||||
if self:IsVec3InZone(Vec3) then
|
||||
|
||||
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||
self:F( { Vec3 = Vec3 } )
|
||||
|
||||
if Vec3 and self:IsVec3InZone(Vec3) then
|
||||
|
||||
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
|
||||
|
||||
if PlayerHits then
|
||||
|
||||
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
|
||||
self.Goal:AddPlayerContribution( PlayerName )
|
||||
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@ -17,6 +17,11 @@
|
||||
do -- ZoneGoal
|
||||
|
||||
--- @type ZONE_GOAL_COALITION
|
||||
-- @field #string ClassName Name of the Class.
|
||||
-- @field #number Coalition The current coalition ID of the zone owner.
|
||||
-- @field #number PreviousCoalition The previous owner of the zone.
|
||||
-- @field #table UnitCategories Table of unit categories that are able to capture and hold the zone. Default is only GROUND units.
|
||||
-- @field #table ObjectCategories Table of object categories that are able to hold a zone. Default is UNITS and STATICS.
|
||||
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
||||
|
||||
|
||||
@ -37,7 +42,11 @@ do -- ZoneGoal
|
||||
--
|
||||
-- @field #ZONE_GOAL_COALITION
|
||||
ZONE_GOAL_COALITION = {
|
||||
ClassName = "ZONE_GOAL_COALITION",
|
||||
ClassName = "ZONE_GOAL_COALITION",
|
||||
Coalition = nil,
|
||||
PreviousCoaliton = nil,
|
||||
UnitCategories = nil,
|
||||
ObjectCategories = nil,
|
||||
}
|
||||
|
||||
--- @field #table ZONE_GOAL_COALITION.States
|
||||
@ -46,27 +55,70 @@ do -- ZoneGoal
|
||||
--- ZONE_GOAL_COALITION Constructor.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone. Default coalition.side.NEUTRAL.
|
||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:New( Zone, Coalition )
|
||||
function ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories )
|
||||
|
||||
if not Zone then
|
||||
BASE:E("ERROR: No Zone specified in ZONE_GOAL_COALITON!")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Inherit ZONE_GOAL.
|
||||
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_COALITION
|
||||
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||
|
||||
self:SetCoalition( Coalition )
|
||||
|
||||
|
||||
-- Set initial owner.
|
||||
self:SetCoalition( Coalition or coalition.side.NEUTRAL)
|
||||
|
||||
-- Set default unit and object categories for the zone scan.
|
||||
self:SetUnitCategories(UnitCategories)
|
||||
self:SetObjectCategories()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The coalition ID, e.g. *coalition.side.RED*.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:SetCoalition( Coalition )
|
||||
self.PreviousCoalition=self.Coalition or Coalition
|
||||
self.Coalition = Coalition
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:SetUnitCategories( UnitCategories )
|
||||
|
||||
if UnitCategories and type(UnitCategories)~="table" then
|
||||
UnitCategories={UnitCategories}
|
||||
end
|
||||
|
||||
self.UnitCategories=UnitCategories or {Unit.Category.GROUND_UNIT}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:SetObjectCategories( ObjectCategories )
|
||||
|
||||
if ObjectCategories and type(ObjectCategories)~="table" then
|
||||
ObjectCategories={ObjectCategories}
|
||||
end
|
||||
|
||||
self.ObjectCategories=ObjectCategories or {Object.Category.UNIT, Object.Category.STATIC}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
@ -75,37 +127,38 @@ do -- ZoneGoal
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
--- Get the previous coaliton, i.e. the one owning the zone before the current one.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
function ZONE_GOAL_COALITION:GetPreviousCoalition()
|
||||
return self.PreviousCoalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition name of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return #string Coalition name.
|
||||
function ZONE_GOAL_COALITION:GetCoalitionName()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
return "Blue"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.RED then
|
||||
return "Red"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
end
|
||||
|
||||
return ""
|
||||
return UTILS.GetCoalitionName(self.Coalition)
|
||||
end
|
||||
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:StatusZone()
|
||||
|
||||
-- Get current state.
|
||||
local State = self:GetState()
|
||||
self:F( { State = self:GetState() } )
|
||||
|
||||
self:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
|
||||
-- Debug text.
|
||||
local text=string.format("Zone state=%s, Owner=%s, Scanning...", State, self:GetCoalitionName())
|
||||
self:F(text)
|
||||
|
||||
-- Scan zone.
|
||||
self:Scan( self.ObjectCategories, self.UnitCategories )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
-- @field #string modex Tail number of the tanker.
|
||||
-- @field #boolean eplrs If true, enable data link, e.g. if used as AWACS.
|
||||
-- @field #boolean recovery If true, tanker will recover using the AIRBOSS marshal pattern.
|
||||
-- @field #number terminaltype Terminal type of used parking spots on airbases.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Recovery Tanker.
|
||||
@ -298,6 +299,7 @@ RECOVERYTANKER = {
|
||||
modex = nil,
|
||||
eplrs = nil,
|
||||
recovery = nil,
|
||||
terminaltype = nil,
|
||||
}
|
||||
|
||||
--- Unique ID (global).
|
||||
@ -306,7 +308,7 @@ _RECOVERYTANKERID=0
|
||||
|
||||
--- Class version.
|
||||
-- @field #string version
|
||||
RECOVERYTANKER.version="1.0.8"
|
||||
RECOVERYTANKER.version="1.0.9"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -381,6 +383,7 @@ function RECOVERYTANKER:New(carrierunit, tankergroupname)
|
||||
self:SetPatternUpdateInterval()
|
||||
self:SetAWACS(false)
|
||||
self:SetRecoveryAirboss(false)
|
||||
self.terminaltype=AIRBASE.TerminalType.OpenMedOrBig
|
||||
|
||||
-- Debug trace.
|
||||
if false then
|
||||
@ -615,8 +618,9 @@ end
|
||||
--- Set home airbase of the tanker. This is the airbase where the tanker will go when it is out of fuel.
|
||||
-- @param #RECOVERYTANKER self
|
||||
-- @param Wrapper.Airbase#AIRBASE airbase The home airbase. Can be the airbase name or a Moose AIRBASE object.
|
||||
-- @param #number terminaltype (Optional) The terminal type of parking spots used for spawning at airbases. Default AIRBASE.TerminalType.OpenMedOrBig.
|
||||
-- @return #RECOVERYTANKER self
|
||||
function RECOVERYTANKER:SetHomeBase(airbase)
|
||||
function RECOVERYTANKER:SetHomeBase(airbase, terminaltype)
|
||||
if type(airbase)=="string" then
|
||||
self.airbase=AIRBASE:FindByName(airbase)
|
||||
else
|
||||
@ -625,6 +629,9 @@ function RECOVERYTANKER:SetHomeBase(airbase)
|
||||
if not self.airbase then
|
||||
self:E(self.lid.."ERROR: Airbase is nil!")
|
||||
end
|
||||
if termialtype then
|
||||
self.terminaltype=terminaltype
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@ -937,7 +944,7 @@ function RECOVERYTANKER:onafterStart(From, Event, To)
|
||||
else
|
||||
|
||||
-- Spawn tanker at airbase.
|
||||
self.tanker=Spawn:SpawnAtAirbase(self.airbase, self.takeoff, nil, AIRBASE.TerminalType.OpenMedOrBig)
|
||||
self.tanker=Spawn:SpawnAtAirbase(self.airbase, self.takeoff, nil, self.terminaltype)
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -237,7 +237,7 @@ _RESCUEHELOID=0
|
||||
|
||||
--- Class version.
|
||||
-- @field #string version
|
||||
RESCUEHELO.version="1.0.9"
|
||||
RESCUEHELO.version="1.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -902,7 +902,7 @@ function RESCUEHELO:onafterStart(From, Event, To)
|
||||
else
|
||||
|
||||
-- Check if an uncontrolled helo group was requested.
|
||||
if self.useuncontrolled then
|
||||
if self.uncontrolledac then
|
||||
|
||||
-- Use an uncontrolled aircraft group.
|
||||
self.helo=GROUP:FindByName(self.helogroupname)
|
||||
|
||||
@ -1037,3 +1037,26 @@ function UTILS.CheckMemory(output)
|
||||
end
|
||||
return mem
|
||||
end
|
||||
|
||||
|
||||
--- Get the coalition name from its numerical ID, e.g. coaliton.side.RED.
|
||||
-- @param #number Coalition The coalition ID.
|
||||
-- @return #string The coalition name, i.e. "Neutral", "Red" or "Blue" (or "Unknown").
|
||||
function UTILS.GetCoalitionName(Coalition)
|
||||
|
||||
if Coalition then
|
||||
if Coalition==coalition.side.BLUE then
|
||||
return "Blue"
|
||||
elseif Coalition==coalition.side.RED then
|
||||
return "Red"
|
||||
elseif Coalition==coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
else
|
||||
return "Unknown"
|
||||
end
|
||||
else
|
||||
return "Unknown"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -168,20 +168,13 @@ function IDENTIFIABLE:GetCoalitionName()
|
||||
local DCSIdentifiable = self:GetDCSObject()
|
||||
|
||||
if DCSIdentifiable then
|
||||
|
||||
-- Get coaliton ID.
|
||||
local IdentifiableCoalition = DCSIdentifiable:getCoalition()
|
||||
self:T3( IdentifiableCoalition )
|
||||
|
||||
if IdentifiableCoalition == coalition.side.BLUE then
|
||||
return "Blue"
|
||||
end
|
||||
return UTILS.GetCoalitionName(IdentifiableCoalition)
|
||||
|
||||
if IdentifiableCoalition == coalition.side.RED then
|
||||
return "Red"
|
||||
end
|
||||
|
||||
if IdentifiableCoalition == coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
end
|
||||
end
|
||||
|
||||
self:F( self.ClassName .. " " .. self.IdentifiableName .. " not found!" )
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user