mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Updates
This commit is contained in:
parent
d3ecbac40a
commit
c5236d337e
@ -225,6 +225,7 @@ function AI_ESCORT:New( EscortUnit, EscortGroupSet, EscortName, EscortBriefing )
|
|||||||
|
|
||||||
self.EscortBriefing = EscortBriefing
|
self.EscortBriefing = EscortBriefing
|
||||||
|
|
||||||
|
self.Menu = {}
|
||||||
|
|
||||||
-- if not EscortBriefing then
|
-- if not EscortBriefing then
|
||||||
-- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " ..
|
-- EscortGroup:MessageToClient( EscortGroup:GetCategoryName() .. " '" .. EscortName .. "' (" .. EscortGroup:GetCallsign() .. ") reporting! " ..
|
||||||
@ -545,26 +546,36 @@ function AI_ESCORT:MenuFormationBox( XStart, XSpace, YStart, YSpace, ZStart, ZSp
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Sets a menu slot to join formation for an escort.
|
||||||
|
-- @param #AI_ESCORT self
|
||||||
|
-- @return #AI_ESCORT
|
||||||
|
function AI_ESCORT:EscortMenuJoinUp( EscortGroup )
|
||||||
|
|
||||||
|
if self.Menu.JoinUp == true then
|
||||||
|
if EscortGroup:IsAir() then
|
||||||
|
local EscortGroupName = EscortGroup:GetName()
|
||||||
|
local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu )
|
||||||
|
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu )
|
||||||
|
local EscortMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation, AI_ESCORT._JoinUp, self, EscortGroup )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines --- Defines a menu slot to let the escort to join formation.
|
--- Defines --- Defines a menu slot to let the escort to join formation.
|
||||||
-- This menu will appear under **Formation**.
|
|
||||||
-- @param #AI_ESCORT self
|
-- @param #AI_ESCORT self
|
||||||
-- @return #AI_ESCORT
|
-- @return #AI_ESCORT
|
||||||
function AI_ESCORT:MenuJoinUp()
|
function AI_ESCORT:MenuJoinUp()
|
||||||
|
|
||||||
|
self.Menu.JoinUp = true
|
||||||
|
|
||||||
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
|
local FlightMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", self.FlightMenu )
|
||||||
local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self )
|
local FlightMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", FlightMenuReportNavigation, AI_ESCORT._FlightJoinUp, self )
|
||||||
|
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.EscortGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
function( EscortGroup )
|
function( EscortGroup )
|
||||||
if EscortGroup:IsAir() then
|
self:EscortSetMenuJoinUp( EscortGroup )
|
||||||
|
|
||||||
local EscortGroupName = EscortGroup:GetName()
|
|
||||||
local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu )
|
|
||||||
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu )
|
|
||||||
local EscortMenuJoinUp = MENU_GROUP_COMMAND:New( self.PlayerGroup, "Join Up", EscortMenuReportNavigation, AI_ESCORT._JoinUp, self )
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -572,6 +583,32 @@ function AI_ESCORT:MenuJoinUp()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function AI_ESCORT:EscortMenuHoldAtEscortPosition( EscortGroup )
|
||||||
|
|
||||||
|
for _, HoldAtEscortPosition in pairs( self.Menu.HoldAtEscortPosition ) do
|
||||||
|
if EscortGroup:IsAir() then
|
||||||
|
local EscortGroupName = EscortGroup:GetName()
|
||||||
|
local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu )
|
||||||
|
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu )
|
||||||
|
local EscortMenuHoldPosition = MENU_GROUP_COMMAND
|
||||||
|
:New(
|
||||||
|
self.PlayerGroup,
|
||||||
|
HoldAtEscortPosition.MenuText,
|
||||||
|
EscortMenuReportNavigation,
|
||||||
|
AI_ESCORT._HoldPosition,
|
||||||
|
self,
|
||||||
|
EscortGroup,
|
||||||
|
EscortGroup,
|
||||||
|
HoldAtEscortPosition.Height,
|
||||||
|
HoldAtEscortPosition.Speed
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.
|
--- Defines a menu slot to let the escort hold at their current position and stay low with a specified height during a specified time in seconds.
|
||||||
-- This menu will appear under **Hold position**.
|
-- This menu will appear under **Hold position**.
|
||||||
-- @param #AI_ESCORT self
|
-- @param #AI_ESCORT self
|
||||||
@ -619,28 +656,16 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat )
|
|||||||
Speed
|
Speed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.Menu.HoldAtEscortPosition = self.Menu.HoldAtEscortPosition or {}
|
||||||
|
self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition+1] = {}
|
||||||
|
self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].Height = Height
|
||||||
|
self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].Speed = Speed
|
||||||
|
self.Menu.HoldAtEscortPosition[#self.Menu.HoldAtEscortPosition].MenuText = MenuText
|
||||||
|
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.EscortGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
function( EscortGroup )
|
function( EscortGroup )
|
||||||
if EscortGroup:IsAir() then
|
self:EscortMenuHoldAtEscortPosition( EscortGroup )
|
||||||
|
|
||||||
local EscortGroupName = EscortGroup:GetName()
|
|
||||||
local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu )
|
|
||||||
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu )
|
|
||||||
|
|
||||||
local EscortMenuHoldPosition = MENU_GROUP_COMMAND
|
|
||||||
:New(
|
|
||||||
self.PlayerGroup,
|
|
||||||
MenuText,
|
|
||||||
EscortMenuReportNavigation,
|
|
||||||
AI_ESCORT._HoldPosition,
|
|
||||||
self,
|
|
||||||
EscortGroup,
|
|
||||||
EscortGroup,
|
|
||||||
Height,
|
|
||||||
Speed
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -648,6 +673,33 @@ function AI_ESCORT:MenuHoldAtEscortPosition( Height, Speed, MenuTextFormat )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function AI_ESCORT:EscortMenuHoldAtLeaderPosition( EscortGroup )
|
||||||
|
|
||||||
|
for _, HoldAtLeaderPosition in pairs( self.Menu.HoldAtLeaderPosition ) do
|
||||||
|
if EscortGroup:IsAir() then
|
||||||
|
|
||||||
|
local EscortGroupName = EscortGroup:GetName()
|
||||||
|
local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu )
|
||||||
|
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu )
|
||||||
|
|
||||||
|
local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND
|
||||||
|
:New(
|
||||||
|
self.PlayerGroup,
|
||||||
|
HoldAtLeaderPosition.MenuText,
|
||||||
|
EscortMenuReportNavigation,
|
||||||
|
AI_ESCORT._HoldPosition,
|
||||||
|
self,
|
||||||
|
self.PlayerGroup,
|
||||||
|
EscortGroup,
|
||||||
|
HoldAtLeaderPosition.Height,
|
||||||
|
HoldAtLeaderPosition.Speed
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.
|
--- Defines a menu slot to let the escort hold at the client position and stay low with a specified height during a specified time in seconds.
|
||||||
-- This menu will appear under **Navigation**.
|
-- This menu will appear under **Navigation**.
|
||||||
-- @param #AI_ESCORT self
|
-- @param #AI_ESCORT self
|
||||||
@ -695,28 +747,16 @@ function AI_ESCORT:MenuHoldAtLeaderPosition( Height, Speed, MenuTextFormat )
|
|||||||
Speed
|
Speed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.Menu.HoldAtLeaderPosition = self.Menu.HoldAtLeaderPosition or {}
|
||||||
|
self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition+1] = {}
|
||||||
|
self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].Height = Height
|
||||||
|
self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].Speed = Speed
|
||||||
|
self.Menu.HoldAtLeaderPosition[#self.Menu.HoldAtLeaderPosition].MenuText = MenuText
|
||||||
|
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.EscortGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
function( EscortGroup )
|
function( EscortGroup )
|
||||||
if EscortGroup:IsAir() then
|
self:EscortMenuHoldAtLeaderPosition( EscortGroup )
|
||||||
|
|
||||||
local EscortGroupName = EscortGroup:GetName()
|
|
||||||
local EscortMenu = MENU_GROUP:New( self.PlayerGroup, EscortGroupName, self.MainMenu )
|
|
||||||
local EscortMenuReportNavigation = MENU_GROUP:New( self.PlayerGroup, "Navigation", EscortMenu )
|
|
||||||
|
|
||||||
local EscortMenuHoldAtLeaderPosition = MENU_GROUP_COMMAND
|
|
||||||
:New(
|
|
||||||
self.PlayerGroup,
|
|
||||||
MenuText,
|
|
||||||
EscortMenuReportNavigation,
|
|
||||||
AI_ESCORT._HoldPosition,
|
|
||||||
self,
|
|
||||||
self.PlayerGroup,
|
|
||||||
EscortGroup,
|
|
||||||
Height,
|
|
||||||
Speed
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1140,7 +1180,7 @@ function AI_ESCORT:_JoinUp( EscortGroup )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function AI_ESCORT:_FlightJoinUp( EscortGroup )
|
function AI_ESCORT:_FlightJoinUp()
|
||||||
|
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.EscortGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
@ -1339,7 +1379,7 @@ function AI_ESCORT.___Resume( EscortGroup, self )
|
|||||||
local PlayerGroup = self.PlayerGroup
|
local PlayerGroup = self.PlayerGroup
|
||||||
|
|
||||||
self:JoinFormation( EscortGroup )
|
self:JoinFormation( EscortGroup )
|
||||||
EscortGroup:MessageTypeToClient( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup )
|
EscortGroup:MessageTypeToGroup( "Destroyed all targets. Rejoining.", MESSAGE.Type.Information, PlayerGroup )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1347,7 +1387,7 @@ end
|
|||||||
--- @param #AI_ESCORT self
|
--- @param #AI_ESCORT self
|
||||||
-- @param Wrapper.Group#GROUP EscortGroup
|
-- @param Wrapper.Group#GROUP EscortGroup
|
||||||
-- @param #number WayPoint
|
-- @param #number WayPoint
|
||||||
function AI_ESCORT._ResumeMission( EscortGroup, WayPoint )
|
function AI_ESCORT:_ResumeMission( EscortGroup, WayPoint )
|
||||||
|
|
||||||
--self.FollowScheduler:Stop( self.FollowSchedule )
|
--self.FollowScheduler:Stop( self.FollowSchedule )
|
||||||
|
|
||||||
@ -1360,7 +1400,7 @@ function AI_ESCORT._ResumeMission( EscortGroup, WayPoint )
|
|||||||
|
|
||||||
EscortGroup:SetTask( EscortGroup:TaskRoute( WayPoints ), 1 )
|
EscortGroup:SetTask( EscortGroup:TaskRoute( WayPoints ), 1 )
|
||||||
|
|
||||||
EscortGroup:MessageTypeToClient( "Resuming mission from waypoint ", MESSAGE.Type.Information, self.PlayerGroup )
|
EscortGroup:MessageTypeToGroup( "Resuming mission from waypoint ", MESSAGE.Type.Information, self.PlayerGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -193,7 +193,7 @@ AI_ESCORT_REQUEST = {
|
|||||||
-- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where escorts will be spawned once requested.
|
-- @param Wrapper.Airbase#AIRBASE EscortAirbase The airbase where escorts will be spawned once requested.
|
||||||
-- @param #string EscortName Name of the escort.
|
-- @param #string EscortName Name of the escort.
|
||||||
-- @param #string EscortBriefing A text showing the AI_ESCORT_REQUEST briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown.
|
-- @param #string EscortBriefing A text showing the AI_ESCORT_REQUEST briefing to the player. Note that if no EscortBriefing is provided, the default briefing will be shown.
|
||||||
-- @return #AI_ESCORT_REQUEST self
|
-- @return #AI_ESCORT_REQUEST
|
||||||
-- @usage
|
-- @usage
|
||||||
-- EscortSpawn = SPAWN:NewWithAlias( "Red A2G Escort Template", "Red A2G Escort AI" ):InitLimit( 10, 10 )
|
-- EscortSpawn = SPAWN:NewWithAlias( "Red A2G Escort Template", "Red A2G Escort AI" ):InitLimit( 10, 10 )
|
||||||
-- EscortSpawn:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Sochi_Adler ), AIRBASE.TerminalType.OpenBig )
|
-- EscortSpawn:ParkAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Sochi_Adler ), AIRBASE.TerminalType.OpenBig )
|
||||||
@ -223,10 +223,9 @@ function AI_ESCORT_REQUEST:New( EscortUnit, EscortSpawn, EscortAirbase, EscortNa
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_ESCORT_REQUEST self
|
--- @param #AI_ESCORT_REQUEST self
|
||||||
-- @param Core.Set#SET_GROUP EscortGroupSet
|
|
||||||
function AI_ESCORT_REQUEST:SpawnEscort()
|
function AI_ESCORT_REQUEST:SpawnEscort()
|
||||||
|
|
||||||
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Cold )
|
local EscortGroup = self.EscortSpawn:SpawnAtAirbase( self.EscortAirbase, SPAWN.Takeoff.Hot )
|
||||||
self.EscortGroupSet:AddGroup( EscortGroup )
|
self.EscortGroupSet:AddGroup( EscortGroup )
|
||||||
|
|
||||||
EscortGroup:OptionROTVertical()
|
EscortGroup:OptionROTVertical()
|
||||||
@ -241,11 +240,27 @@ function AI_ESCORT_REQUEST:SpawnEscort()
|
|||||||
Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) )
|
Report:Add( "Joining Up " .. self.EscortGroupSet:GetUnitTypeNames():Text( ", " ) .. " from " .. LeaderEscort:GetCoordinate():ToString( self.EscortUnit ) )
|
||||||
|
|
||||||
LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit )
|
LeaderEscort:MessageTypeToGroup( Report:Text(), MESSAGE.Type.Information, self.PlayerUnit )
|
||||||
|
self:FormationTrail( 50, 50, 50 )
|
||||||
if self.SpawnMode == self.__Enum.Mode.Formation then
|
if self.SpawnMode == self.__Enum.Mode.Formation then
|
||||||
self:FormationTrail( 50, 50, 50 )
|
|
||||||
self:JoinFormation( EscortGroup )
|
self:JoinFormation( EscortGroup )
|
||||||
end
|
end
|
||||||
self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels )
|
|
||||||
|
--self:Menus( self.XStart, self.XSpace, self.YStart, self.YSpace, self.ZStart, self.ZSpace, self.ZLevels )
|
||||||
|
|
||||||
|
self:EscortMenuJoinUp( EscortGroup )
|
||||||
|
|
||||||
|
self:EscortMenuHoldAtEscortPosition( EscortGroup )
|
||||||
|
self:EscortMenuHoldAtLeaderPosition( EscortGroup )
|
||||||
|
|
||||||
|
self:MenuFlare()
|
||||||
|
self:MenuSmoke()
|
||||||
|
|
||||||
|
self:MenuReportTargets( 60 )
|
||||||
|
self:MenuAssistedAttack()
|
||||||
|
self:MenuROE()
|
||||||
|
self:MenuROT()
|
||||||
|
|
||||||
|
self:MenuResumeMission()
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -717,7 +717,6 @@ function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, X
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
FollowGroup:SetState( FollowGroup, "Formation", Formation )
|
FollowGroup:SetState( FollowGroup, "Formation", Formation )
|
||||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -873,7 +872,6 @@ function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event ,
|
|||||||
FollowGroup:SetState( self, "FormationVec3", Vec3 )
|
FollowGroup:SetState( self, "FormationVec3", Vec3 )
|
||||||
i = i + 1
|
i = i + 1
|
||||||
FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Vic )
|
FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Vic )
|
||||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -934,7 +932,6 @@ function AI_FORMATION:onafterFormationBox( FollowGroupSet, From , Event , To, XS
|
|||||||
FollowGroup:SetState( self, "FormationVec3", Vec3 )
|
FollowGroup:SetState( self, "FormationVec3", Vec3 )
|
||||||
i = i + 1
|
i = i + 1
|
||||||
FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Box )
|
FollowGroup:SetState( FollowGroup, "Formation", self.__Enum.Formation.Box )
|
||||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -1026,7 +1023,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
ClientUnit:SetState( self, "CV1", CV2 )
|
ClientUnit:SetState( self, "CV1", CV2 )
|
||||||
end
|
end
|
||||||
|
|
||||||
FollowGroupSet:ForEachGroup(
|
FollowGroupSet:ForEachGroupAlive(
|
||||||
--- @param Wrapper.Group#GROUP FollowGroup
|
--- @param Wrapper.Group#GROUP FollowGroup
|
||||||
-- @param Wrapper.Unit#UNIT ClientUnit
|
-- @param Wrapper.Unit#UNIT ClientUnit
|
||||||
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
|
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
|
||||||
|
|||||||
@ -1835,6 +1835,336 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Will park a group at an @{Wrapper.Airbase}.
|
||||||
|
--
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Wrapper.Airbase} where to spawn the group.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE.TerminalType TerminalType (optional) The terminal type the aircraft should be spawned at. See @{Wrapper.Airbase#AIRBASE.TerminalType}.
|
||||||
|
-- @param #table Parkingdata (optional) Table holding the coordinates and terminal ids for all units of the group. Spawning will be forced to happen at exactily these spots!
|
||||||
|
-- @return #nil Nothing is returned!
|
||||||
|
function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex )
|
||||||
|
|
||||||
|
self:F( { SpawnIndex = SpawnIndex, SpawnMaxGroups = self.SpawnMaxGroups } )
|
||||||
|
|
||||||
|
-- Get position of airbase.
|
||||||
|
local PointVec3 = SpawnAirbase:GetCoordinate()
|
||||||
|
self:T2(PointVec3)
|
||||||
|
|
||||||
|
-- Set take off type. Default is hot.
|
||||||
|
local Takeoff = SPAWN.Takeoff.Cold
|
||||||
|
|
||||||
|
-- Get group template.
|
||||||
|
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
|
||||||
|
|
||||||
|
if SpawnTemplate then
|
||||||
|
|
||||||
|
-- Check if the aircraft with the specified SpawnIndex is already spawned.
|
||||||
|
-- If yes, ensure that the aircraft is spawned at the same aircraft spot.
|
||||||
|
|
||||||
|
local GroupAlive = self:GetGroupFromIndex( SpawnIndex )
|
||||||
|
|
||||||
|
-- Debug output
|
||||||
|
self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
||||||
|
|
||||||
|
-- Template group, unit and its attributes.
|
||||||
|
local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix)
|
||||||
|
local TemplateUnit=TemplateGroup:GetUnit(1)
|
||||||
|
local ishelo=TemplateUnit:HasAttribute("Helicopters")
|
||||||
|
local isbomber=TemplateUnit:HasAttribute("Bombers")
|
||||||
|
local istransport=TemplateUnit:HasAttribute("Transports")
|
||||||
|
local isfighter=TemplateUnit:HasAttribute("Battleplanes")
|
||||||
|
|
||||||
|
-- Number of units in the group. With grouping this can actually differ from the template group size!
|
||||||
|
local nunits=#SpawnTemplate.units
|
||||||
|
|
||||||
|
-- First waypoint of the group.
|
||||||
|
local SpawnPoint = SpawnTemplate.route.points[1]
|
||||||
|
|
||||||
|
-- These are only for ships and FARPS.
|
||||||
|
SpawnPoint.linkUnit = nil
|
||||||
|
SpawnPoint.helipadId = nil
|
||||||
|
SpawnPoint.airdromeId = nil
|
||||||
|
|
||||||
|
-- Get airbase ID and category.
|
||||||
|
local AirbaseID = SpawnAirbase:GetID()
|
||||||
|
local AirbaseCategory = SpawnAirbase:GetDesc().category
|
||||||
|
self:F( { AirbaseCategory = AirbaseCategory } )
|
||||||
|
|
||||||
|
-- Set airdromeId.
|
||||||
|
if AirbaseCategory == Airbase.Category.SHIP then
|
||||||
|
SpawnPoint.linkUnit = AirbaseID
|
||||||
|
SpawnPoint.helipadId = AirbaseID
|
||||||
|
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
||||||
|
SpawnPoint.linkUnit = AirbaseID
|
||||||
|
SpawnPoint.helipadId = AirbaseID
|
||||||
|
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||||
|
SpawnPoint.airdromeId = AirbaseID
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set waypoint type/action.
|
||||||
|
SpawnPoint.alt = 0
|
||||||
|
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||||
|
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||||
|
|
||||||
|
-- Check if we spawn on ground.
|
||||||
|
local spawnonground=not (Takeoff==SPAWN.Takeoff.Air)
|
||||||
|
self:T({spawnonground=spawnonground, TOtype=Takeoff, TOair=Takeoff==SPAWN.Takeoff.Air})
|
||||||
|
|
||||||
|
-- Check where we actually spawn if we spawn on ground.
|
||||||
|
local spawnonship=false
|
||||||
|
local spawnonfarp=false
|
||||||
|
local spawnonrunway=false
|
||||||
|
local spawnonairport=false
|
||||||
|
if spawnonground then
|
||||||
|
if AirbaseCategory == Airbase.Category.SHIP then
|
||||||
|
spawnonship=true
|
||||||
|
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
||||||
|
spawnonfarp=true
|
||||||
|
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||||
|
spawnonairport=true
|
||||||
|
end
|
||||||
|
spawnonrunway=Takeoff==SPAWN.Takeoff.Runway
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Array with parking spots coordinates.
|
||||||
|
local parkingspots={}
|
||||||
|
local parkingindex={}
|
||||||
|
local spots
|
||||||
|
|
||||||
|
-- Spawn happens on ground, i.e. at an airbase, a FARP or a ship.
|
||||||
|
if spawnonground and not SpawnTemplate.parked then
|
||||||
|
|
||||||
|
|
||||||
|
-- Number of free parking spots.
|
||||||
|
local nfree=0
|
||||||
|
|
||||||
|
-- Set terminal type.
|
||||||
|
local termtype=TerminalType
|
||||||
|
|
||||||
|
-- Scan options. Might make that input somehow.
|
||||||
|
local scanradius=50
|
||||||
|
local scanunits=true
|
||||||
|
local scanstatics=true
|
||||||
|
local scanscenery=false
|
||||||
|
local verysafe=false
|
||||||
|
|
||||||
|
-- Number of free parking spots at the airbase.
|
||||||
|
if spawnonship or spawnonfarp or spawnonrunway then
|
||||||
|
-- These places work procedural and have some kind of build in queue ==> Less effort.
|
||||||
|
self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
||||||
|
nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true)
|
||||||
|
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true)
|
||||||
|
elseif Parkingdata~=nil then
|
||||||
|
-- Parking data explicitly set by user as input parameter.
|
||||||
|
nfree=#Parkingdata
|
||||||
|
spots=Parkingdata
|
||||||
|
else
|
||||||
|
if ishelo then
|
||||||
|
if termtype==nil then
|
||||||
|
-- Helo is spawned. Try exclusive helo spots first.
|
||||||
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
if nfree<nunits then
|
||||||
|
-- Not enough helo ports. Let's try also other terminal types.
|
||||||
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- No terminal type specified. We try all spots except shelters.
|
||||||
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Fixed wing aircraft is spawned.
|
||||||
|
if termtype==nil then
|
||||||
|
--TODO: Add some default cases for transport, bombers etc. if no explicit terminal type is provided.
|
||||||
|
--TODO: We don't want Bombers to spawn in shelters. But I don't know a good attribute for just fighers.
|
||||||
|
--TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out.
|
||||||
|
if isbomber or istransport then
|
||||||
|
-- First we fill the potentially bigger spots.
|
||||||
|
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
if nfree<nunits then
|
||||||
|
-- Now we try the smaller ones.
|
||||||
|
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Terminal type explicitly given.
|
||||||
|
self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype)))
|
||||||
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
||||||
|
nfree=#spots
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get parking data.
|
||||||
|
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
||||||
|
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||||
|
for _,_spot in pairs(parkingdata) do
|
||||||
|
self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
||||||
|
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
||||||
|
end
|
||||||
|
self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||||
|
|
||||||
|
-- Set this to true if not enough spots are available for emergency air start.
|
||||||
|
local _notenough=false
|
||||||
|
|
||||||
|
-- Need to differentiate some cases again.
|
||||||
|
if spawnonship or spawnonfarp or spawnonrunway then
|
||||||
|
|
||||||
|
-- On free spot required in these cases.
|
||||||
|
if nfree >=1 then
|
||||||
|
|
||||||
|
-- All units get the same spot. DCS takes care of the rest.
|
||||||
|
for i=1,nunits do
|
||||||
|
table.insert(parkingspots, spots[1].Coordinate)
|
||||||
|
table.insert(parkingindex, spots[1].TerminalID)
|
||||||
|
end
|
||||||
|
-- This is actually used...
|
||||||
|
PointVec3=spots[1].Coordinate
|
||||||
|
|
||||||
|
else
|
||||||
|
-- If there is absolutely no spot ==> air start!
|
||||||
|
_notenough=true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif spawnonairport then
|
||||||
|
|
||||||
|
if nfree>=nunits then
|
||||||
|
|
||||||
|
for i=1,nunits do
|
||||||
|
table.insert(parkingspots, spots[i].Coordinate)
|
||||||
|
table.insert(parkingindex, spots[i].TerminalID)
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Not enough spots for the whole group ==> air start!
|
||||||
|
_notenough=true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Not enough spots ==> Prepare airstart.
|
||||||
|
if _notenough then
|
||||||
|
|
||||||
|
if not self.SpawnUnControlled then
|
||||||
|
else
|
||||||
|
self:E(string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if not SpawnTemplate.parked then
|
||||||
|
-- Translate the position of the Group Template to the Vec3.
|
||||||
|
|
||||||
|
SpawnTemplate.parked = true
|
||||||
|
|
||||||
|
for UnitID = 1, nunits do
|
||||||
|
self:F('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y)
|
||||||
|
|
||||||
|
-- Template of the current unit.
|
||||||
|
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||||
|
|
||||||
|
-- Tranlate position and preserve the relative position/formation of all aircraft.
|
||||||
|
local SX = UnitTemplate.x
|
||||||
|
local SY = UnitTemplate.y
|
||||||
|
local BX = SpawnTemplate.route.points[1].x
|
||||||
|
local BY = SpawnTemplate.route.points[1].y
|
||||||
|
local TX = PointVec3.x + (SX-BX)
|
||||||
|
local TY = PointVec3.z + (SY-BY)
|
||||||
|
|
||||||
|
if spawnonground then
|
||||||
|
|
||||||
|
-- Ships and FARPS seem to have a build in queue.
|
||||||
|
if spawnonship or spawnonfarp or spawnonrunway then
|
||||||
|
|
||||||
|
self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
||||||
|
|
||||||
|
-- Spawn on ship. We take only the position of the ship.
|
||||||
|
SpawnTemplate.units[UnitID].x = PointVec3.x --TX
|
||||||
|
SpawnTemplate.units[UnitID].y = PointVec3.z --TY
|
||||||
|
SpawnTemplate.units[UnitID].alt = PointVec3.y
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID]))
|
||||||
|
|
||||||
|
-- Get coordinates of parking spot.
|
||||||
|
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
|
||||||
|
SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z
|
||||||
|
SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y
|
||||||
|
|
||||||
|
--parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID]))
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
||||||
|
|
||||||
|
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
|
||||||
|
SpawnTemplate.units[UnitID].x = TX
|
||||||
|
SpawnTemplate.units[UnitID].y = TY
|
||||||
|
SpawnTemplate.units[UnitID].alt = PointVec3.y
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Parking spot id.
|
||||||
|
UnitTemplate.parking = nil
|
||||||
|
UnitTemplate.parking_id = nil
|
||||||
|
if parkingindex[UnitID] then
|
||||||
|
UnitTemplate.parking = parkingindex[UnitID]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug output.
|
||||||
|
self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking)))
|
||||||
|
self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id)))
|
||||||
|
self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set gereral spawnpoint position.
|
||||||
|
SpawnPoint.x = PointVec3.x
|
||||||
|
SpawnPoint.y = PointVec3.z
|
||||||
|
SpawnPoint.alt = PointVec3.y
|
||||||
|
|
||||||
|
SpawnTemplate.x = PointVec3.x
|
||||||
|
SpawnTemplate.y = PointVec3.z
|
||||||
|
|
||||||
|
SpawnTemplate.uncontrolled = true
|
||||||
|
|
||||||
|
-- Spawn group.
|
||||||
|
local GroupSpawned = self:SpawnWithIndex( SpawnIndex, true )
|
||||||
|
|
||||||
|
-- When spawned in the air, we need to generate a Takeoff Event.
|
||||||
|
if Takeoff == GROUP.Takeoff.Air then
|
||||||
|
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
||||||
|
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 5 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive.
|
||||||
|
if Takeoff~=SPAWN.Takeoff.Runway and Takeoff~=SPAWN.Takeoff.Air and spawnonairport then
|
||||||
|
SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 75, true} , 1.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Will park a group at an @{Wrapper.Airbase}.
|
--- Will park a group at an @{Wrapper.Airbase}.
|
||||||
-- This method is mostly advisable to be used if you want to simulate parking units at an airbase and be visible.
|
-- This method is mostly advisable to be used if you want to simulate parking units at an airbase and be visible.
|
||||||
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
||||||
@ -1876,325 +2206,10 @@ end
|
|||||||
function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, R2.4, R2.5
|
function SPAWN:ParkAtAirbase( SpawnAirbase, TerminalType, Parkingdata ) -- R2.2, R2.4, R2.5
|
||||||
self:F( { self.SpawnTemplatePrefix, SpawnAirbase, TerminalType } )
|
self:F( { self.SpawnTemplatePrefix, SpawnAirbase, TerminalType } )
|
||||||
|
|
||||||
-- Get position of airbase.
|
self:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, 1 )
|
||||||
local PointVec3 = SpawnAirbase:GetCoordinate()
|
|
||||||
|
|
||||||
-- Set take off type. Default is hot.
|
for SpawnIndex = 2, self.SpawnMaxGroups do
|
||||||
local Takeoff = SPAWN.Takeoff.Cold
|
self:ScheduleOnce( SpawnIndex * 0.1, SPAWN.ParkAircraft, self, SpawnAirbase, TerminalType, Parkingdata, SpawnIndex )
|
||||||
|
|
||||||
for SpawnIndex = 1, self.SpawnMaxGroups do
|
|
||||||
|
|
||||||
self:F( { SpawnIndex = SpawnIndex, SpawnMaxGroups = self.SpawnMaxGroups } )
|
|
||||||
|
|
||||||
-- Get group template.
|
|
||||||
local SpawnTemplate = self.SpawnGroups[SpawnIndex].SpawnTemplate
|
|
||||||
|
|
||||||
if SpawnTemplate then
|
|
||||||
|
|
||||||
-- Check if the aircraft with the specified SpawnIndex is already spawned.
|
|
||||||
-- If yes, ensure that the aircraft is spawned at the same aircraft spot.
|
|
||||||
|
|
||||||
local GroupAlive = self:GetGroupFromIndex( SpawnIndex )
|
|
||||||
|
|
||||||
-- Debug output
|
|
||||||
self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
|
||||||
|
|
||||||
-- Template group, unit and its attributes.
|
|
||||||
local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix)
|
|
||||||
local TemplateUnit=TemplateGroup:GetUnit(1)
|
|
||||||
local ishelo=TemplateUnit:HasAttribute("Helicopters")
|
|
||||||
local isbomber=TemplateUnit:HasAttribute("Bombers")
|
|
||||||
local istransport=TemplateUnit:HasAttribute("Transports")
|
|
||||||
local isfighter=TemplateUnit:HasAttribute("Battleplanes")
|
|
||||||
|
|
||||||
-- Number of units in the group. With grouping this can actually differ from the template group size!
|
|
||||||
local nunits=#SpawnTemplate.units
|
|
||||||
|
|
||||||
-- First waypoint of the group.
|
|
||||||
local SpawnPoint = SpawnTemplate.route.points[1]
|
|
||||||
|
|
||||||
-- These are only for ships and FARPS.
|
|
||||||
SpawnPoint.linkUnit = nil
|
|
||||||
SpawnPoint.helipadId = nil
|
|
||||||
SpawnPoint.airdromeId = nil
|
|
||||||
|
|
||||||
-- Get airbase ID and category.
|
|
||||||
local AirbaseID = SpawnAirbase:GetID()
|
|
||||||
local AirbaseCategory = SpawnAirbase:GetDesc().category
|
|
||||||
self:F( { AirbaseCategory = AirbaseCategory } )
|
|
||||||
|
|
||||||
-- Set airdromeId.
|
|
||||||
if AirbaseCategory == Airbase.Category.SHIP then
|
|
||||||
SpawnPoint.linkUnit = AirbaseID
|
|
||||||
SpawnPoint.helipadId = AirbaseID
|
|
||||||
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
|
||||||
SpawnPoint.linkUnit = AirbaseID
|
|
||||||
SpawnPoint.helipadId = AirbaseID
|
|
||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
|
||||||
SpawnPoint.airdromeId = AirbaseID
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set waypoint type/action.
|
|
||||||
SpawnPoint.alt = 0
|
|
||||||
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
|
||||||
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
|
||||||
|
|
||||||
-- Check if we spawn on ground.
|
|
||||||
local spawnonground=not (Takeoff==SPAWN.Takeoff.Air)
|
|
||||||
self:T({spawnonground=spawnonground, TOtype=Takeoff, TOair=Takeoff==SPAWN.Takeoff.Air})
|
|
||||||
|
|
||||||
-- Check where we actually spawn if we spawn on ground.
|
|
||||||
local spawnonship=false
|
|
||||||
local spawnonfarp=false
|
|
||||||
local spawnonrunway=false
|
|
||||||
local spawnonairport=false
|
|
||||||
if spawnonground then
|
|
||||||
if AirbaseCategory == Airbase.Category.SHIP then
|
|
||||||
spawnonship=true
|
|
||||||
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
|
||||||
spawnonfarp=true
|
|
||||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
|
||||||
spawnonairport=true
|
|
||||||
end
|
|
||||||
spawnonrunway=Takeoff==SPAWN.Takeoff.Runway
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Array with parking spots coordinates.
|
|
||||||
local parkingspots={}
|
|
||||||
local parkingindex={}
|
|
||||||
local spots
|
|
||||||
|
|
||||||
-- Spawn happens on ground, i.e. at an airbase, a FARP or a ship.
|
|
||||||
if spawnonground and not SpawnTemplate.parked then
|
|
||||||
|
|
||||||
|
|
||||||
-- Number of free parking spots.
|
|
||||||
local nfree=0
|
|
||||||
|
|
||||||
-- Set terminal type.
|
|
||||||
local termtype=TerminalType
|
|
||||||
|
|
||||||
-- Scan options. Might make that input somehow.
|
|
||||||
local scanradius=50
|
|
||||||
local scanunits=true
|
|
||||||
local scanstatics=true
|
|
||||||
local scanscenery=false
|
|
||||||
local verysafe=false
|
|
||||||
|
|
||||||
-- Number of free parking spots at the airbase.
|
|
||||||
if spawnonship or spawnonfarp or spawnonrunway then
|
|
||||||
-- These places work procedural and have some kind of build in queue ==> Less effort.
|
|
||||||
self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
|
||||||
nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true)
|
|
||||||
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true)
|
|
||||||
elseif Parkingdata~=nil then
|
|
||||||
-- Parking data explicitly set by user as input parameter.
|
|
||||||
nfree=#Parkingdata
|
|
||||||
spots=Parkingdata
|
|
||||||
else
|
|
||||||
if ishelo then
|
|
||||||
if termtype==nil then
|
|
||||||
-- Helo is spawned. Try exclusive helo spots first.
|
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
if nfree<nunits then
|
|
||||||
-- Not enough helo ports. Let's try also other terminal types.
|
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- No terminal type specified. We try all spots except shelters.
|
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Fixed wing aircraft is spawned.
|
|
||||||
if termtype==nil then
|
|
||||||
--TODO: Add some default cases for transport, bombers etc. if no explicit terminal type is provided.
|
|
||||||
--TODO: We don't want Bombers to spawn in shelters. But I don't know a good attribute for just fighers.
|
|
||||||
--TODO: Some attributes are "Helicopters", "Bombers", "Transports", "Battleplanes". Need to check it out.
|
|
||||||
if isbomber or istransport then
|
|
||||||
-- First we fill the potentially bigger spots.
|
|
||||||
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
if nfree<nunits then
|
|
||||||
-- Now we try the smaller ones.
|
|
||||||
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Terminal type explicitly given.
|
|
||||||
self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype)))
|
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
|
||||||
nfree=#spots
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get parking data.
|
|
||||||
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
|
||||||
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
|
||||||
for _,_spot in pairs(parkingdata) do
|
|
||||||
self:T2(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
|
|
||||||
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
|
||||||
end
|
|
||||||
self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
|
||||||
|
|
||||||
-- Set this to true if not enough spots are available for emergency air start.
|
|
||||||
local _notenough=false
|
|
||||||
|
|
||||||
-- Need to differentiate some cases again.
|
|
||||||
if spawnonship or spawnonfarp or spawnonrunway then
|
|
||||||
|
|
||||||
-- On free spot required in these cases.
|
|
||||||
if nfree >=1 then
|
|
||||||
|
|
||||||
-- All units get the same spot. DCS takes care of the rest.
|
|
||||||
for i=1,nunits do
|
|
||||||
table.insert(parkingspots, spots[1].Coordinate)
|
|
||||||
table.insert(parkingindex, spots[1].TerminalID)
|
|
||||||
end
|
|
||||||
-- This is actually used...
|
|
||||||
PointVec3=spots[1].Coordinate
|
|
||||||
|
|
||||||
else
|
|
||||||
-- If there is absolutely no spot ==> air start!
|
|
||||||
_notenough=true
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif spawnonairport then
|
|
||||||
|
|
||||||
if nfree>=nunits then
|
|
||||||
|
|
||||||
for i=1,nunits do
|
|
||||||
table.insert(parkingspots, spots[i].Coordinate)
|
|
||||||
table.insert(parkingindex, spots[i].TerminalID)
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
-- Not enough spots for the whole group ==> air start!
|
|
||||||
_notenough=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Not enough spots ==> Prepare airstart.
|
|
||||||
if _notenough then
|
|
||||||
|
|
||||||
if not self.SpawnUnControlled then
|
|
||||||
else
|
|
||||||
self:E(string.format("WARNING: Group %s has no parking spots at %s ==> No emergency air start or uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
if not SpawnTemplate.parked then
|
|
||||||
-- Translate the position of the Group Template to the Vec3.
|
|
||||||
|
|
||||||
SpawnTemplate.parked = true
|
|
||||||
|
|
||||||
for UnitID = 1, nunits do
|
|
||||||
self:F('Before Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y)
|
|
||||||
|
|
||||||
-- Template of the current unit.
|
|
||||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
|
||||||
|
|
||||||
-- Tranlate position and preserve the relative position/formation of all aircraft.
|
|
||||||
local SX = UnitTemplate.x
|
|
||||||
local SY = UnitTemplate.y
|
|
||||||
local BX = SpawnTemplate.route.points[1].x
|
|
||||||
local BY = SpawnTemplate.route.points[1].y
|
|
||||||
local TX = PointVec3.x + (SX-BX)
|
|
||||||
local TY = PointVec3.z + (SY-BY)
|
|
||||||
|
|
||||||
if spawnonground then
|
|
||||||
|
|
||||||
-- Ships and FARPS seem to have a build in queue.
|
|
||||||
if spawnonship or spawnonfarp or spawnonrunway then
|
|
||||||
|
|
||||||
self:T(string.format("Group %s spawning at farp, ship or runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
|
||||||
|
|
||||||
-- Spawn on ship. We take only the position of the ship.
|
|
||||||
SpawnTemplate.units[UnitID].x = PointVec3.x --TX
|
|
||||||
SpawnTemplate.units[UnitID].y = PointVec3.z --TY
|
|
||||||
SpawnTemplate.units[UnitID].alt = PointVec3.y
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
self:T(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID]))
|
|
||||||
|
|
||||||
-- Get coordinates of parking spot.
|
|
||||||
SpawnTemplate.units[UnitID].x = parkingspots[UnitID].x
|
|
||||||
SpawnTemplate.units[UnitID].y = parkingspots[UnitID].z
|
|
||||||
SpawnTemplate.units[UnitID].alt = parkingspots[UnitID].y
|
|
||||||
|
|
||||||
--parkingspots[UnitID]:MarkToAll(string.format("Group %s spawning at airbase %s on parking spot id %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), parkingindex[UnitID]))
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
self:T(string.format("Group %s spawning in air at %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
|
||||||
|
|
||||||
-- Spawn in air as requested initially. Original template orientation is perserved, altitude is already correctly set.
|
|
||||||
SpawnTemplate.units[UnitID].x = TX
|
|
||||||
SpawnTemplate.units[UnitID].y = TY
|
|
||||||
SpawnTemplate.units[UnitID].alt = PointVec3.y
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Parking spot id.
|
|
||||||
UnitTemplate.parking = nil
|
|
||||||
UnitTemplate.parking_id = nil
|
|
||||||
if parkingindex[UnitID] then
|
|
||||||
UnitTemplate.parking = parkingindex[UnitID]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:T2(string.format("Group %s unit number %d: Parking = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking)))
|
|
||||||
self:T2(string.format("Group %s unit number %d: Parking ID = %s",self.SpawnTemplatePrefix, UnitID, tostring(UnitTemplate.parking_id)))
|
|
||||||
self:T2('After Translation SpawnTemplate.units['..UnitID..'].x = '..SpawnTemplate.units[UnitID].x..', SpawnTemplate.units['..UnitID..'].y = '..SpawnTemplate.units[UnitID].y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set gereral spawnpoint position.
|
|
||||||
SpawnPoint.x = PointVec3.x
|
|
||||||
SpawnPoint.y = PointVec3.z
|
|
||||||
SpawnPoint.alt = PointVec3.y
|
|
||||||
|
|
||||||
SpawnTemplate.x = PointVec3.x
|
|
||||||
SpawnTemplate.y = PointVec3.z
|
|
||||||
|
|
||||||
SpawnTemplate.uncontrolled = true
|
|
||||||
|
|
||||||
-- Spawn group.
|
|
||||||
local GroupSpawned = self:SpawnWithIndex( SpawnIndex, true )
|
|
||||||
|
|
||||||
-- When spawned in the air, we need to generate a Takeoff Event.
|
|
||||||
if Takeoff == GROUP.Takeoff.Air then
|
|
||||||
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
|
||||||
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 5 )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if we accidentally spawned on the runway. Needs to be schedules, because group is not immidiately alive.
|
|
||||||
if Takeoff~=SPAWN.Takeoff.Runway and Takeoff~=SPAWN.Takeoff.Air and spawnonairport then
|
|
||||||
SCHEDULER:New(nil, AIRBASE.CheckOnRunWay, {SpawnAirbase, GroupSpawned, 75, true} , 1.0)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self:SetSpawnIndex()
|
self:SetSpawnIndex()
|
||||||
|
|||||||
@ -549,12 +549,15 @@ function AIRBASE:GetParkingSpotsTable(termtype)
|
|||||||
local spots={}
|
local spots={}
|
||||||
for _,_spot in pairs(parkingdata) do
|
for _,_spot in pairs(parkingdata) do
|
||||||
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then
|
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then
|
||||||
|
self:I({_spot=_spot})
|
||||||
local _free=_isfree(_spot)
|
local _free=_isfree(_spot)
|
||||||
local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos)
|
local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos)
|
||||||
table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
|
table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:I({ spots = spots } )
|
||||||
|
|
||||||
return spots
|
return spots
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -704,6 +707,8 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||||
local _termid=parkingspot.TerminalID
|
local _termid=parkingspot.TerminalID
|
||||||
|
|
||||||
|
self:I({_termid=_termid})
|
||||||
|
|
||||||
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) then
|
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) then
|
||||||
|
|
||||||
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
|
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
|
||||||
@ -783,7 +788,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
|
|
||||||
--_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied)))
|
--_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied)))
|
||||||
if occupied then
|
if occupied then
|
||||||
self:T(string.format("%s: Parking spot id %d occupied.", airport, _termid))
|
self:I(string.format("%s: Parking spot id %d occupied.", airport, _termid))
|
||||||
else
|
else
|
||||||
self:I(string.format("%s: Parking spot id %d free.", airport, _termid))
|
self:I(string.format("%s: Parking spot id %d free.", airport, _termid))
|
||||||
if nvalid<_nspots then
|
if nvalid<_nspots then
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user