Spawn improvements

COORDINATE:
- Improved GetClosestParkingSpot functions.
- Improved ScanObject function.
SPAWN:
- Improved SpawnAtAirbase function
RAT:
- Improved spawn function
- Added some takeoff type user functions.
UTILS:
- Added clock vs second functions
- Added split function
AIRBASE:
- Added checkonrunway function
- Other improvemetns.
This commit is contained in:
funkyfranky
2018-06-28 00:20:48 +02:00
parent 08ea3cd219
commit a7afb43ab6
5 changed files with 531 additions and 226 deletions

View File

@@ -294,15 +294,18 @@ do -- COORDINATE
--- Returns if the 2 coordinates are at the same 2D position.
-- @param #COORDINATE self
-- @param #number radius Scan radius in meters.
-- @param #number radius (Optional) Scan radius in meters. Default 100 m.
-- @param #boolean scanunits (Optional) If true scan for units. Default true.
-- @param #boolean scanstatics (Optional) If true scan for static objects. Default true.
-- @param #boolean scanscenery (Optional) If true scan for scenery objects. Default false.
-- @return True if units were found.
-- @return True if statics were found.
-- @return True if scenery objects were found.
-- @return Unit objects found.
-- @return Static objects found.
-- @return Scenery objects found.
function COORDINATE:ScanObjects(radius)
self:T(string.format("Scanning in radius %.1f m.", radius))
function COORDINATE:ScanObjects(radius, scanunits, scanstatics, scanscenery)
self:F(string.format("Scanning in radius %.1f m.", radius))
local SphereSearch = {
id = world.VolumeType.SPHERE,
@@ -312,6 +315,30 @@ do -- COORDINATE
}
}
-- Defaults
radius=radius or 100
if scanunits==nil then
scanunits=true
end
if scanstatics==nil then
scanstatics=true
end
if scanscenery==nil then
scanscenery=false
end
--{Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY}
local scanobjects={}
if scanunits then
table.insert(scanobjects, Object.Category.UNIT)
end
if scanstatics then
table.insert(scanobjects, Object.Category.STATIC)
end
if scanscenery then
table.insert(scanobjects, Object.Category.SCENERY)
end
-- Found stuff.
local Units = {}
local Statics = {}
@@ -352,7 +379,7 @@ do -- COORDINATE
end
-- Search the world.
world.searchObjects({Object.Category.UNIT, Object.Category.STATIC, Object.Category.SCENERY}, SphereSearch, EvaluateZone)
world.searchObjects(scanobjects, SphereSearch, EvaluateZone)
for _,unit in pairs(Units) do
self:T(string.format("Scan found unit %s", unit:getName()))
@@ -361,7 +388,7 @@ do -- COORDINATE
self:T(string.format("Scan found static %s", static:getName()))
end
for _,scenery in pairs(Scenery) do
self:T(string.format("Scan found scenery %s", scenery:getName()))
self:T(string.format("Scan found scenery %s", scenery:getTypeName()))
end
return gotunits, gotstatics, gotscenery, Units, Statics, Scenery
@@ -1021,22 +1048,28 @@ do -- COORDINATE
--- Gets the nearest parking spot.
-- @param #COORDINATE self
-- @param #boolean free (Optional) Only look for free parking spots. By default the closest parking spot is returned regardless of whether it is free or not.
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at that airbase.
-- @param Wrapper.Airbase#Terminaltype terminaltype Type of the terminal.
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at this airbase.
-- @param Wrapper.Airbase#Terminaltype terminaltype (Optional) Type of the terminal. Default any execpt valid spawn points on runway.
-- @param #boolean free (Optional) If true, returns the closest free spot. If false, returns the closest occupied spot. If nil, returns the closest spot regardless of free or occupied.
-- @return Core.Point#COORDINATE Coordinate of the nearest parking spot.
-- @return #number Distance to closest parking spot.
function COORDINATE:GetClosestParkingSpot(free, airbase, terminaltype)
-- @return #number Terminal ID.
-- @return #number Distance to closest parking spot in meters.
function COORDINATE:GetClosestParkingSpot(airbase, terminaltype, free)
-- Get airbase table.
local airbases={}
if airbase then
table.insert(airbases,airbase)
else
airbases=AIRBASE:GetAllAirbases()
airbases=AIRBASE.GetAllAirbases()
end
-- Init.
local _closest=nil --Core.Point#COORDINATE
local _termID=nil
local _distmin=nil
-- Loop over all airbases.
for _,_airbase in pairs(airbases) do
local mybase=_airbase --Wrapper.Airbase#AIRBASE
@@ -1044,44 +1077,51 @@ do -- COORDINATE
for _,_spot in pairs(parkingdata) do
-- Get coordinate if it matches the requirements.
local _coord=nil --Core.Point#COORDINATE
if (free and _spot.Free) or free==nil then
if (terminaltype and _spot.TerminalType==terminaltype) or terminaltype==nil then
_coord=_spot.Coordinate
end
end
-- Compare distance to closest one found so far.
if _coord then
-- Check for parameters.
if (free==true and _spot.Free==true) or (free==false and _spot.Free==false) or free==nil then
local _coord=_spot.Coordinate --Core.Point#COORDINATE
local _dist=self:Get2DDistance(_coord)
if _distmin==nil then
_closest=_coord
_distmin=_dist
else
local _dist=self:Get2DDistance(_coord)
_termID=_spot.TerminalID
else
if _dist<_distmin then
_distmin=_dist
_closest=_coord
_termID=_spot.TerminalID
end
end
end
end
end
end
return _closest, _distmin
return _closest, _termID, _distmin
end
--- Gets the nearest free parking spot.
-- @param #COORDINATE self
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at that airbase.
-- @param Wrapper.Airbase#Terminaltype terminaltype Type of the terminal.
-- @param Wrapper.Airbase#Terminaltype terminaltype (Optional) Type of the terminal.
-- @return #COORDINATE Coordinate of the nearest free parking spot.
-- @return #number Distance to closest free parking spot.
-- @return #number Terminal ID.
-- @return #number Distance to closest free parking spot in meters.
function COORDINATE:GetClosestFreeParkingSpot(airbase, terminaltype)
return self:GetClosestParkingSpot(true, airbase, terminaltype)
return self:GetClosestParkingSpot(airbase, terminaltype, true)
end
--- Gets the nearest occupied parking spot.
-- @param #COORDINATE self
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at that airbase.
-- @param Wrapper.Airbase#Terminaltype terminaltype (Optional) Type of the terminal.
-- @return #COORDINATE Coordinate of the nearest occupied parking spot.
-- @return #number Terminal ID.
-- @return #number Distance to closest occupied parking spot in meters.
function COORDINATE:GetClosestOccupiedParkingSpot(airbase, terminaltype)
return self:GetClosestParkingSpot(airbase, terminaltype, false)
end
--- Gets the nearest coordinate to a road.

View File

@@ -1218,7 +1218,8 @@ end
-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Wrapper.Airbase} where to spawn the group.
-- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot.
-- @param #number TakeoffAltitude (optional) The altitude above the ground.
-- @param #number TerminalType (optional) The terminal type the aircraft should be spawned at.
-- @param Wrapper.Airbase#AIRBASE.TerminalType TerminalType (optional) The terminal type the aircraft should be spawned at. See @{Wrapper.Airbase#AIRBASE.TerminalType}.
-- @param #boolean EmergencyAirSpawn (optional) If true (default), groups are spawned in air if there is no parking spot at the airbase. If false, nothing is spawned if no parking spot is available.
-- @return Wrapper.Group#GROUP that was spawned or nil when nothing was spawned.
-- @usage
-- Spawn_Plane = SPAWN:New( "Plane" )
@@ -1239,7 +1240,7 @@ end
--
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig )
--
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType ) -- R2.2, R2.4
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType, EmergencyAirSpawn ) -- R2.2, R2.4
self:F( { self.SpawnTemplatePrefix, SpawnAirbase, Takeoff, TakeoffAltitude, TerminalType } )
-- Get position of airbase.
@@ -1249,6 +1250,11 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Set take off type. Default is hot.
Takeoff = Takeoff or SPAWN.Takeoff.Hot
-- By default, groups are spawned in air if no parking spot is available.
if EmergencyAirSpawn==nil then
EmergencyAirSpawn=true
end
if self:_GetSpawnIndex( self.SpawnIndex + 1 ) then
-- Get group template.
@@ -1259,9 +1265,13 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Debug output
self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
-- Template group and unit.
-- Template group, unit and its attributes.
local TemplateGroup = GROUP:FindByName(self.SpawnTemplatePrefix)
local ishelo=TemplateGroup:GetUnit(1):HasAttribute("Helicopters")
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")
-- First waypoint of the group.
local SpawnPoint = SpawnTemplate.route.points[1]
@@ -1332,32 +1342,64 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- 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, spawnonship or spawnonfarp or spawnonrunway)
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, spawnonship or spawnonfarp or spawnonrunway)
else
if ishelo and termtype==nil then
-- Helo is spawned.
-- Try helo spots first.
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly)
nfree=#spots
if nfree<#SpawnTemplate.units then
-- Not enough helo ports. Let's try all terminal types.
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable)
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)
nfree=#spots
if nfree<#SpawnTemplate.units 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)
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)
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.
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype)
nfree=#spots
--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)
nfree=#spots
if nfree<#SpawnTemplate.units 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)
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)
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)
nfree=#spots
end
end
end
-- Get parking data.
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
self:T(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
for _,_spot in pairs(parkingdata) do
self:T(string.format("%s, Termin Index = %3d, Term Type = %03d, Free = %5s, TOAC = %5s, Term ID0 = %3d, Dist2Rwy = %4d",
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, #SpawnTemplate.units))
@@ -1371,7 +1413,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
end
else
if not self.SpawnUnControlled then
if EmergencyAirSpawn and not self.SpawnUnControlled then
self:E(string.format("WARNING: Group %s has no parking spots at %s ==> air start!", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
-- Not enough parking spots at the airport ==> Spawn in air.
@@ -1388,15 +1430,15 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
PointVec3.x=PointVec3.x+math.random(-500,500)
PointVec3.z=PointVec3.z+math.random(-500,500)
if ishelo then
PointVec3.y=PointVec3:GetLandHeight()+math.random(200,1200)
PointVec3.y=PointVec3:GetLandHeight()+math.random(100,1000)
else
-- Randomize position so that multiple AC wont be spawned on top even in air.
PointVec3.y=PointVec3:GetLandHeight()+math.random(500,5000)
PointVec3.y=PointVec3:GetLandHeight()+math.random(500,2500)
end
Takeoff=GROUP.Takeoff.Air
else
self:E(string.format("WARNING: Group %s has no parking spots at %s ==> Uncontrolled spawning ==> No spawn!", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
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
@@ -1475,23 +1517,26 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
-- Spawn group.
local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex )
-- 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() } , 1 )
end
end
return GroupSpawned
-- 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, 25, true} , 1.0)
end
return GroupSpawned
end
end
return nil
end
--- Will spawn a group from a Vec3 in 3D space.
-- This method is mostly advisable to be used if you want to simulate spawning units in the air, like helicopters or airplanes.
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.