This commit is contained in:
Frank
2020-03-25 16:43:34 +01:00
parent e675c991c4
commit 130e089d1c
7 changed files with 281 additions and 212 deletions
@@ -5539,7 +5539,7 @@ function WAREHOUSE:_SpawnAssetGroundNaval(alias, asset, request, spawnzone, aiof
end
if asset.skill then
unit.skill= asset.skill
end
end
end
@@ -5677,6 +5677,13 @@ function WAREHOUSE:_SpawnAssetAircraft(alias, asset, request, parking, uncontrol
if asset.payload then
unit.payload=asset.payload.pylons
end
if asset.modex then
unit.onboard_num=asset.modex[i]
end
if asset.callsign then
unit.callsign=asset.callsign[i]
end
end
+5
View File
@@ -1091,6 +1091,11 @@ function AIRWING:onafterNewAsset(From, Event, To, asset, assignment)
local text=string.format("Adding asset to squadron %s: assignment=%s, type=%s, attribute=%s", squad.name, assignment, asset.unittype, asset.attribute)
self:I(self.lid..text)
-- Create callsign and modex.
squad:GetCallsign(asset)
squad:GetModex(asset)
asset.terminalType=AIRBASE.TerminalType.OpenBig
-- Add asset to squadron.
+170 -191
View File
@@ -119,19 +119,20 @@ FLIGHTCONTROL = {
--- FlightControl class version.
-- @field #string version
FLIGHTCONTROL.version="0.2.4"
FLIGHTCONTROL.version="0.2.5"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Accept and forbit parking spots.
-- TODO: Add FARPS?
-- TODO: Add helos.
-- TODO: Talk me down option.
-- TODO: ATIS option.
-- TODO: ATC voice overs.
-- TODO: Check runways and clean up.
-- TODO: Interface with FLIGHTGROUP.
-- DONE: Interface with FLIGHTGROUP.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Constructor
@@ -382,7 +383,9 @@ function FLIGHTCONTROL:OnEventBirth(EventData)
-- We delay this, to have all elements of the group in the game.
self:ScheduleOnce(0.1, self._CreateFlightGroup, self, EventData.IniGroup)
if EventData.IniUnit:IsAir() then
self:ScheduleOnce(0.1, self._CreateFlightGroup, self, EventData.IniGroup)
end
end
@@ -1081,96 +1084,118 @@ function FLIGHTCONTROL:_InitParkingSpots()
for _,_spot in pairs(parkingdata) do
local spot=_spot --Wrapper.Airbase#AIRBASE.ParkingSpot
--TODO: reserve client spots.
--TODO: scan spot for objects.
-- Mark position.
local text=string.format("ID=%d, Terminal=%d, Free=%s, Reserved=%s, Client=%s, Dist=%.1f", spot.TerminalID, spot.TerminalType, tostring(spot.Free), tostring(spot.Reserved), tostring(spot.ClientSpot), spot.DistToRwy)
local text=string.format("Parking ID=%d, Terminal=%d: Free=%s, Client=%s, Dist=%.1f", spot.TerminalID, spot.TerminalType, tostring(spot.Free), tostring(spot.ClientSpot), spot.DistToRwy)
self:I(self.lid..text)
-- Set spot to occupied.
if spot.Free then
self:SetParkingFree(spot)
else
self:SetParkingOccupied(spot, "unknown")
end
--TODO: scan spot for objects.
-- Add to table.
self.parking[spot.TerminalID]=spot
-- Increase counter
self.Nparkingspots=self.Nparkingspots+1
end
end
--- Get parking spot by its Terminal ID.
-- @param #FLIGHTCONTROL self
-- @param #number TerminalID
-- @return Wrapper.Airbase#AIRBASE Parking spot data table.
function FLIGHTCONTROL:GetParkingSpotByID(TerminalID)
return self.parking[TerminalID]
end
--- Set parking spot to FREE and update F10 marker.
-- @param #FLIGHTCONTROL self
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot The parking spot data table.
function FLIGHTCONTROL:SetParkingFree(spot)
spot.Status=AIRBASE.SpotStatus.FREE
spot.OccupiedBy=nil
spot.ReservedBy=nil
self:UpdateParkingMarker(spot)
end
--- Set parking spot to RESERVED and update F10 marker.
-- @param #FLIGHTCONTROL self
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot The parking spot data table.
-- @param #string unitname Name of the unit occupying the spot. Default "unknown".
function FLIGHTCONTROL:SetParkingReserved(spot, unitname)
spot.Status=AIRBASE.SpotStatus.RESERVED
spot.ReservedBy=unitname or "unknown"
self:UpdateParkingMarker(spot)
end
--- Set parking spot to OCCUPIED and update F10 marker.
-- @param #FLIGHTCONTROL self
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot The parking spot data table.
-- @param #string unitname Name of the unit occupying the spot. Default "unknown".
function FLIGHTCONTROL:SetParkingOccupied(spot, unitname)
spot.Status=AIRBASE.SpotStatus.OCCUPIED
spot.OccupiedBy=unitname or "unknown"
self:UpdateParkingMarker(spot)
end
--- Get free parking spots.
-- @param #FLIGHTCONTROL self
-- @param #number terminal Terminal type or nil.
-- @return #number Number of free spots. Total if terminal=nil or of the requested terminal type.
-- @return #table Table of free parking spots of data type #FLIGHCONTROL.ParkingSpot.
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot The parking spot data table.
function FLIGHTCONTROL:UpdateParkingMarker(spot)
if spot.MarkerID then
spot.Coordinate:RemoveMark(spot.MarkerID)
end
local text=string.format("Spot %d (type %d) status=%s", spot.TerminalID, spot.TerminalType, spot.Status)
if spot.OccupiedBy then
text=text..string.format("Occupied by %s", spot.OccupiedBy)
end
if spot.ReservedBy then
text=text..string.format("Reserved for %s", spot.ReservedBy)
end
if spot.ClientSpot then
text=text..string.format("Client %s", spot.ClientSpot)
end
spot.MarkerID=spot.Coordinate:MarkToAll(text, true)
end
--- Check if parking spot is free.
-- @param #FLIGHTCONTROL self
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot Parking spot data.
-- @return #boolean If true, parking spot is free.
function FLIGHTCONTROL:IsParkingFree(spot)
return spot.Status==AIRBASE.SpotStatus.FREE
end
--- Get free parking spots.
--- Check if a parking spot is reserved by a flight group.
-- @param #FLIGHTCONTROL self
-- @param #number terminal Terminal type or nil.
-- @return #number Number of free spots. Total if terminal=nil or of the requested terminal type.
-- @return #table Table of free parking spots of data type #FLIGHCONTROL.ParkingSpot.
function FLIGHTCONTROL:_GetFreeParkingSpots(terminal)
local freespots={}
local n=0
for _,_parking in pairs(self.parking) do
local parking=_parking --#FLIGHTCONTROL.ParkingSpot
if parking.Free and parking.TOAC==false and not parking.Reserved then
if terminal==nil or terminal==parking.terminal then
n=n+1
table.insert(freespots, parking)
end
end
end
return n,freespots
end
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot Parking spot to check.
-- @return #string Name of element or nil.
function FLIGHTCONTROL:IsParkingOccupied(spot)
--- Update parking spots.
-- @param #FLIGHTCONTROL self
function FLIGHTCONTROL:_UpdateParkingSpots()
-- Parking spots of airbase.
local parkingdata=self.airbase:GetParkingSpotsTable()
for _,_parking in pairs(self.parking) do
local parking=_parking --#FLIGHTCONTROL.ParkingSpot
if parking.markerid then
parking.Coordinate:RemoveMark(parking.markerid)
parking.markerid=nil
end
if spot.Status==AIRBASE.SpotStatus.OCCUPIED then
return tostring(spot.OccupiedBy)
else
return false
end
-- Loop over all spots.
local message="Parking Spots:"
for _,_spot in pairs(parkingdata) do
local spot=_spot --Wrapper.Airbase#AIRBASE.ParkingSpot
-- Parking.
local parking=self.parking[spot.TerminalID] --#FLIGHTCONTROL.ParkingSpot
-- Check if any known flight has reserved this spot.
local reserved=self:IsParkingReserved(spot)
-- Message text.
--local text=string.format("ID=%03d, Terminal=%03d, Free=%s, TOAC=%s, reserved=%s", parking.TerminalID, parking.TerminalType, tostring(parking.Free), tostring(parking.TOAC), tostring(reserved))
local text=string.format("ID=%03d, Terminal=%03d, Free=%s, TOAC=%s, reserved=%s", spot.TerminalID, spot.TerminalType, tostring(spot.Free), tostring(spot.TOAC), tostring(reserved))
-- Place marker on non-free spots.
if parking.Free==false or parking.TOAC or reserved~=nil then
parking.markerid=parking.Coordinate:MarkToAll(text)
message=message.."\n"..text
end
end
-- Debug message.
self:I(self.lid..message)
end
--- Check if a parking spot is reserved by a flight group.
@@ -1179,9 +1204,10 @@ end
-- @return #string Name of element or nil.
function FLIGHTCONTROL:IsParkingReserved(spot)
local park=self.parking[spot.TerminalID] --Wrapper.Airbase#AIRBASE.ParkingSpot
if park.Reserved then
return tostring(park.Reserved)
if spot.Status==AIRBASE.SpotStatus.RESERVED then
return tostring(spot.ReservedBy)
else
return false
end
-- Init all elements as NOT parking anywhere.
@@ -1200,6 +1226,30 @@ function FLIGHTCONTROL:IsParkingReserved(spot)
return nil
end
--- Get free parking spots.
-- @param #FLIGHTCONTROL self
-- @param #number terminal Terminal type or nil.
-- @return #number Number of free spots. Total if terminal=nil or of the requested terminal type.
-- @return #table Table of free parking spots of data type #FLIGHCONTROL.ParkingSpot.
function FLIGHTCONTROL:_GetFreeParkingSpots(terminal)
local freespots={}
local n=0
for _,_parking in pairs(self.parking) do
local parking=_parking --Wrapper.Airbase#AIRBASE.ParkingSpot
if self:IsParkingFree(parking) then
if terminal==nil or terminal==parking.terminal then
n=n+1
table.insert(freespots, parking)
end
end
end
return n,freespots
end
--- Get closest parking spot.
-- @param #FLIGHTCONTROL self
-- @param Core.Point#COORDINATE coordinate Reference coordinate.
@@ -1214,7 +1264,7 @@ function FLIGHTCONTROL:GetClosestParkingSpot(coordinate, terminaltype, free)
for TerminalID, Spot in pairs(self.parking) do
local spot=Spot --Wrapper.Airbase#AIRBASE.ParkingSpot
if (not free) or free==true and not (self:IsParkingReserved(spot) or spot.Reserved) then
if (not free) or (free==true and not (self:IsParkingReserved(spot) or self:IsParkingOccupied(spot))) then
if terminaltype==nil or terminaltype==spot.TerminalType then
-- Get distance from coordinate to spot.
@@ -1637,10 +1687,7 @@ function FLIGHTCONTROL:_CreateFlightGroup(group)
if flight.homebase and flight.homebase:GetName()==self.airbasename then
flight:SetFlightControl(self)
end
-- Add to known flights.
--table.insert(self.flights, flight)
return flight
end
@@ -1746,32 +1793,6 @@ function FLIGHTCONTROL:_CheckFlights()
--TODO: check parking?
-- NOTE: This is now done in FLIGHTGROUP!
-- Check if parking flights started to taxi.
for _,_flight in pairs(self.Qparking) do
local flight=_flight --Ops.FlightGroup#FLIGHTGROUP
for _,_element in pairs(flight.elements) do
local element=_element --Ops.FlightGroup#FLIGHTGROUP.Element
if element.parking then
-- Get distance to assigned parking spot.
local dist=element.unit:GetCoordinate():Get2DDistance(element.parking.Coordinate)
-- If distance >10 meters or velocity of unit is >0, we consider the unit as taxiing.
-- TODO: Check distance threshold! If element is taxiing, the parking spot is free again.
-- When the next plane is spawned on this spot, collisions should be avoided!
if dist>10 or element.unit:GetVelocityMPS()>0 then
if element.status==FLIGHTGROUP.ElementStatus.ENGINEON then
self.flight:ElementTaxiing(element)
end
end
else
self:E(self.lid..string.format("Element %s is in PARKING queue but has no parking spot assigned!", element.name))
end
end
end
end
--- Check status of all registered flights and do some sanity checks.
@@ -1807,64 +1828,6 @@ function FLIGHTCONTROL:_CheckParking()
end
--- Scan airbase zone for units, statics and scenery.
-- @param #FLIGHTCONTROL self
-- @return Core.Set#SET_UNIT Set of scanned units.
-- @return Core.Set#SET_STATIC Set of scanned static objects.
function FLIGHTCONTROL:_CheckAirbase()
-- Airbase position.
local coord=self:GetCoordinate()
-- Scan radius = 5 NM.
local RCCZ=UTILS.NMToMeters(1)
self.scenery=self.scenery or {}
local scanscenery=true
if #self.scenery>0 then
scanscenery=false
end
-- Debug info.
self:T(self.lid..string.format("Scanning airbase zone. Radius=%.1f NM.", UTILS.MetersToNM(RCCZ)))
-- Scan units in carrier zone.
local _,_,_,unitscan,staticscan,sceneryscan=coord:ScanObjects(RCCZ, true, true, scanscenery)
local su=SET_UNIT:New():FilterActive(true)
for _,_unit in pairs(unitscan) do
local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive() and unit:InAir()==false then
su:AddUnit(unit)
end
end
local setstatic=SET_STATIC:New()
for _,static in pairs(staticscan) do
local static=STATIC:Find(static)
setstatic:AddStatic(static)
static:GetCoordinate():MarkToAll("Static")
end
if scanscenery then
for _,scen in pairs(sceneryscan) do
--local static=SCENERY:
local s=SCENERY:Register(scen:getName(), scen)
--s:GetCoordinate():MarkToAll("Scenery")
table.insert(self.scenery, s)
end
end
-- Debug info.
local text=string.format("Scan found: units=%d, statics=%d, scenery=%d", su:Count(), setstatic:Count(), #self.scenery)
self:I(self.lid..text)
return su,setstatic
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Routing Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1915,35 +1878,51 @@ function FLIGHTCONTROL:_LandAI(flight, parking)
pland:MarkToAll(string.format("Landing: d=%d m, h=%d m", x2, h2))
end
-- Give signal to land.
flight.flaghold:Set(1)
-- Get group template.
local Template=flight.group:GetTemplate()
-- Set route points.
Template.route.points=wp
for i,unit in pairs(Template.units) do
local spot=parking[i] --Wrapper.Airbase#AIRBASE.ParkingSpot
local respawn=false
local element=flight:GetElementByName(unit.name)
if element then
--element.parking=spot
unit.parking_landing=spot.TerminalID
local text=string.format("FF Reserving parking spot %d for unit %s", spot.TerminalID, tostring(unit.name))
self:I(self.lid..text)
self.parking[spot.TerminalID].Reserved=element.name
else
env.info("FF error could not get element to assign parking!")
end
end
if respawn then
-- Debug message.
MESSAGE:New(string.format("Respawning group %s", flight.groupname)):ToAll()
--Respawn the group.
flight.group=flight.group:Respawn(Template, true)
-- Get group template.
local Template=flight.group:GetTemplate()
-- Set route points.
Template.route.points=wp
for i,unit in pairs(Template.units) do
local spot=parking[i] --Wrapper.Airbase#AIRBASE.ParkingSpot
local element=flight:GetElementByName(unit.name)
if element then
-- Set the parking spot at the destination airbase.
unit.parking_landing=spot.TerminalID
local text=string.format("FF Reserving parking spot %d for unit %s", spot.TerminalID, tostring(unit.name))
self:I(self.lid..text)
-- Set parking to RESERVED.
self:SetParkingReserved(spot, element.name)
else
env.info("FF error could not get element to assign parking!")
end
end
-- Debug message.
MESSAGE:New(string.format("Respawning group %s", flight.groupname)):ToAll()
--Respawn the group.
flight:Respawn(Template)
--flight.group=flight.group:Respawn(Template, true)
else
-- Give signal to land.
flight:ClearToLand()
end
-- Route the group.
--flight.group:Route(wp, 1)
+9 -17
View File
@@ -1992,18 +1992,15 @@ function FLIGHTGROUP:onafterElementTaxiing(From, Event, To, Element)
-- Get terminal ID.
local TerminalID=Element.parking and tostring(Element.parking.TerminalID) or "N/A"
-- Remove marker.
if self.flightcontrol and Element.parking then
local parking=self.flightcontrol.parking[Element.parking.TerminalID] --Wrapper.Airbase#AIRBASE.ParkingSpot
if parking and parking.MarkerID then
parking.Coordinate:RemoveMark(parking.MarkerID)
end
end
-- Debug info.
self:T(self.lid..string.format("Element taxiing %s. Parking spot %s is now free", Element.name, TerminalID))
-- Set parking to FREE.
if self.flightcontrol and Element.parking then
self.flightcontrol:SetParkingFree(Element.parking)
end
-- Not parking any more.
Element.parking=nil
@@ -2075,15 +2072,10 @@ function FLIGHTGROUP:onafterElementArrived(From, Event, To, Element, airbase, Pa
if Parking then
if self.flightcontrol then
local spot=self.flightcontrol.parking[Parking.TerminalID] --Wrapper.Airbase#AIRBASE.ParkingSpot
self:T(self.lid..string.format("Element arrived %s at %s on parking spot %s reserved for %s", Element.name, Parking.AirbaseName, Parking.TerminalID, tostring(spot.Reserved)))
if spot.Reserved then
if spot.Reserved==Element.name then
spot.Reserved=nil
else
self:E(self.lid..string.format("WARNING: Parking spot was not reserved for this element!"))
end
end
-- Set parking spot to OCCUPIED.
self.flightcontrol:SetParkingOccupied(Element.parking, Element.name)
end
end
+3 -2
View File
@@ -85,8 +85,9 @@ INTEL.version="0.0.3"
--- Create a new INTEL object and start the FSM.
-- @param #INTEL self
-- @param Core.Set#SET_GROUP DetectionSet Set of detection groups.
-- @param #number Coalition Coalition side. Can also be passed as a string "red", "blue" or "neutral".
-- @return #INTEL self
function INTEL:New(DetectionSet)
function INTEL:New(DetectionSet, Coalition)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #INTEL
@@ -499,7 +500,7 @@ end
-- @param #INTEL.DetectedItem Contact Detected contact.
function INTEL:onafterNewContact(From, Event, To, Contact)
self:I(self.lid..string.format("NEW contact %s", Contact.groupname))
table.insert(self.ContactsUnknown, Contact)
table.insert(self.ContactsUnknown, Contact)
end
--- On after "LostContact" event.
+72
View File
@@ -23,6 +23,10 @@
-- @field #table missiontypes Mission types the squadron can perform.
-- @field #string livery Livery of the squadron.
-- @field #number skill Skill of squadron members.
-- @field #number modex Modex.
-- @field #number modexcounter Counter to incease modex number for assets.
-- @field #string callsignName Callsign name.
-- @field #number callsigncounter Counter to increase callsign names for new assets.
-- @field Ops.AirWing#AIRWING airwing The AIRWING object the squadron belongs to.
-- @field #number Ngroups Number of asset flight groups this squadron has.
-- @field #number engageRange Engagement range in meters.
@@ -52,6 +56,10 @@ SQUADRON = {
missiontypes = {},
livery = nil,
skill = nil,
modex = nil,
modexcounter = 0,
callsignName = nil,
callsigncounter= 11,
airwing = nil,
Ngroups = nil,
engageRange = nil,
@@ -238,6 +246,15 @@ function SQUADRON:SetEngagementRange(EngageRange)
return self
end
--- Set call sign.
-- @param #SQUADRON self
-- @param #string Callsign
-- @return #SQUADRON self
function SQUADRON:SetCallsign(Callsign, Index)
self.callsignName=Callsign
return self
end
--- Set airwing.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING Airwing The airwing.
@@ -272,6 +289,61 @@ function SQUADRON:DelAsset(Asset)
return self
end
--- Create a callsign for the asset.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
-- @return #SQUADRON self
function SQUADRON:GetCallsign(Asset)
if self.callsignName then
Asset.callsign={}
for i=1,Asset.nunits do
local callsign={}
callsign[1]=self.callsignName
callsign[2]=self.callsigncounter / 10
callsign[3]=self.callsigncounter % 10
if callsign[3]==0 then
callsign[3]=1
self.callsigncounter=self.callsigncounter+2
else
self.callsigncounter=self.callsigncounter+1
end
Asset.callsign[i]=callsign
--TODO: there is also a table entry .name, which is a string.
end
end
end
--- Create a modex for the asset.
-- @param #SQUADRON self
-- @param Ops.AirWing#AIRWING.SquadronAsset Asset The airwing asset.
-- @return #SQUADRON self
function SQUADRON:GetModex(Asset)
if self.callsignName then
Asset.modex={}
for i=1,Asset.nunits do
Asset.modex[i]=tostring(self.modex+self.modexcounter)
self.modexcounter=self.modexcounter+1
end
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+14 -1
View File
@@ -300,6 +300,17 @@ AIRBASE.PersianGulf = {
["Tunb_Kochak"] = "Tunb Kochak",
}
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
-- @type AIRBASE.SpotStatus
-- @field #string FREE Spot is free.
-- @field #string OCCUPIED Spot is occupied.
-- @field #string RESERVED Spot is reserved.
AIRBASE.SpotStatus = {
FREE="Free",
OCCUPIED="Occupied",
RESERVED="Reserved",
}
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
-- @type AIRBASE.ParkingSpot
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
@@ -311,8 +322,10 @@ AIRBASE.PersianGulf = {
-- @field #number DistToRwy Distance to runway in meters. Currently bugged and giving the same number as the TerminalID.
-- @field #string AirbaseName Name of the airbase.
-- @field #number MarkerID Numerical ID of marker placed at parking spot.
-- @field #boolean Reserved If true, parking spot is reserved for an aircraft.
-- @field #boolean ClientSpot If true, a client unit sits at this parking spot (spawned or not).
-- @field #string Status Status of spot e.g. AIRBASE.SpotStatus.FREE.
-- @field #string OccupiedBy Name of the aircraft occupying the spot or "unknown". Can be nil if spot is not occupied.
-- @field #string ReservedBy Name of the aircraft for which this spot is reserved. Can be nil if spot is not reserved.
--- Terminal Types of parking spots. See also https://wiki.hoggitworld.com/view/DCS_func_getParking
--