mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-12 16:57:50 +00:00
Ops
This commit is contained in:
@@ -15,10 +15,12 @@
|
||||
-- @type AIRWING
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||
-- @field #string sid Class id string for output to DCS log file.
|
||||
-- @field #string carriername The name of the carrier unit.
|
||||
-- @field #string wid Class id string for output to DCS log file.
|
||||
-- @field #string warehousename The name of the warehouse unit/static.
|
||||
-- @field #table menu Table of menu items.
|
||||
-- @field #table squadrons Table of squadrons.
|
||||
-- @field #table missionqueue Mission queue table.
|
||||
-- @field #table missioncounter Running index counting the added missions.
|
||||
-- @extends Functional.Warehouse#WAREHOUSE
|
||||
|
||||
--- Be surprised!
|
||||
@@ -34,57 +36,49 @@
|
||||
-- @field #AIRWING
|
||||
AIRWING = {
|
||||
ClassName = "AIRWING",
|
||||
sid = nil,
|
||||
carriername = nil,
|
||||
wid = nil,
|
||||
warehousename = nil,
|
||||
menu = nil,
|
||||
squadrons = nil,
|
||||
taskqueue = {},
|
||||
missionqueue = {},
|
||||
missioncounter = nil,
|
||||
}
|
||||
|
||||
--- Squadron data.
|
||||
-- @type AIRWING.Squadron
|
||||
-- @field #string name Name of the squadron.
|
||||
-- @field #table assets Assets of the squadron.
|
||||
-- @field #table tasks Task(s) of the squadron.
|
||||
-- @field #table capabilities Mission types that the squadron can do.
|
||||
-- @field #string livery Livery of the squadron.
|
||||
-- @field DCS#Coalition.Side coalition Coalition side.
|
||||
-- @field #number threadlevel Thread level of intruder.
|
||||
-- @field #string threadtext Thread text.
|
||||
-- @field #number category Group category.
|
||||
-- @field #string categoryname Group category name.
|
||||
-- @field #string typename Type name of group.
|
||||
-- @field #table menu The squadron menu entries.
|
||||
|
||||
--- Squadron asset.
|
||||
-- @type AIRWING.SquadronAsset
|
||||
-- @field #boolean assigned Assigned to mission.
|
||||
-- @field #AIRWING.Missiondata mission The assigned mission.
|
||||
-- @field Ops.FlightGroup#FLIGHTGROUP flightgroup The flightgroup object.
|
||||
-- @extends Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
|
||||
--- Mission types.
|
||||
-- @type AIRWING.MissionType
|
||||
-- @extends Ops.FlightGroup#FLIGHTGROUP.MissionType
|
||||
|
||||
--- Mission data.
|
||||
-- @type AIRWING.Mission
|
||||
-- @field #string type Mission type.
|
||||
-- @type AIRWING.Missiondata
|
||||
-- @field #string squadname Name of the assigned squadron.
|
||||
-- @field #number nassets Number of required assets.
|
||||
-- @field #string status Mission status.
|
||||
-- @extends Ops.FlightGroup#FLIGHTGROUP.Mission
|
||||
|
||||
--- AIRWING class version.
|
||||
-- @field #string version
|
||||
AIRWING.version="0.0.5"
|
||||
AIRWING.version="0.1.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Add squadrons to warehouse.
|
||||
-- DONE: Add squadrons to warehouse.
|
||||
-- TODO: Make special request to transfer squadrons to anther airwing (or warehouse).
|
||||
-- TODO: Build mission queue.
|
||||
-- TODO: Find way to start missions.
|
||||
-- TODO: Check if missions are accomplished.
|
||||
-- TODO: Paylods as assets.
|
||||
-- TODO: Cargo as assets.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -111,7 +105,7 @@ function AIRWING:New(warehousename, airwingname)
|
||||
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.sid=string.format("AIRWING %s |", airwingname)
|
||||
self.wid=string.format("AIRWING %s |", airwingname)
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
@@ -119,10 +113,7 @@ function AIRWING:New(warehousename, airwingname)
|
||||
|
||||
self:AddTransition("*", "AddMission", "*") -- Add a new mission.
|
||||
|
||||
self:AddTransition("*", "RequestCAP", "*") -- Request CAP flight.
|
||||
self:AddTransition("*", "RequestIntercept", "*") -- Request Intercept.
|
||||
self:AddTransition("*", "RequestCAS", "*") -- Request CAS.
|
||||
self:AddTransition("*", "RequestSEAD", "*") -- Request SEAD.
|
||||
self:AddTransition("*", "RequestMission", "*") -- Request CAP flight.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
@@ -154,18 +145,6 @@ function AIRWING:New(warehousename, airwingname)
|
||||
-- @param #AIRWING self
|
||||
-- @param #number delay Delay in seconds.
|
||||
|
||||
|
||||
--- Triggers the FSM event "RequestCAP".
|
||||
-- @function [parent=#AIRWING] RequestCAP
|
||||
-- @param #AIRWING self
|
||||
-- @param Core.Point#COORDINATE coordinate
|
||||
-- @param #number altitude Altitude
|
||||
-- @param #number leg Race track length.
|
||||
-- @param #number heading Heading in degrees.
|
||||
-- @param #number speed Speed in knots.
|
||||
-- @param #AIRWING.Squadron squadron Explicitly request a specific squadron.
|
||||
|
||||
|
||||
-- Debug trace.
|
||||
if true then
|
||||
self.Debug=true
|
||||
@@ -245,11 +224,11 @@ end
|
||||
|
||||
--- Check if there is a squadron that can execute a given mission type. Optionally, the number of required assets can be specified.
|
||||
-- @param #AIRWING self
|
||||
-- @param #AIRWING.Squaron Squadron The Squadron.
|
||||
-- @param #AIRWING.Squadron Squadron The Squadron.
|
||||
-- @param #string MissionType Type of mission.
|
||||
-- @param #number Nassets Number of required assets for the mission. Use *nil* or 0 for none. Then only the general capability is checked.
|
||||
-- @return #boolean If true, Squadron can do that type of mission. Available assets are not checked.
|
||||
-- @return #number Number of available assets.
|
||||
-- @return #number Number of available assets that dont have a mission assigned.
|
||||
function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets)
|
||||
|
||||
local cando=false
|
||||
@@ -272,12 +251,12 @@ function AIRWING:SquadronCanMission(Squadron, MissionType, Nassets)
|
||||
for _,_asset in pairs(Squadron.assets) do
|
||||
local asset=_asset --#AIRWING.SquadronAsset
|
||||
|
||||
-- TODO: Check if on mission etc.
|
||||
if not asset.spawned then
|
||||
-- Check if has already a mission assigned.
|
||||
if asset.mission==nil then
|
||||
n=n+1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -322,6 +301,49 @@ function AIRWING:CanMission(MissionType, Nassets)
|
||||
return Can, N
|
||||
end
|
||||
|
||||
--- Create a CAP mission.
|
||||
-- @param #AIRWING self
|
||||
-- @param #number Altitude Orbit altitude in feet. Default 10000 ft.
|
||||
-- @param #number SpeedOrbit Orbit speed in knots. Default 350 kts.
|
||||
-- @param #number Heading Heading in degrees. Default 270° (East to West).
|
||||
-- @param #number Leg Length of race-track in NM. Default 10 NM.
|
||||
-- @return #AIRWING.MissionCAP The CAP mission table.
|
||||
function AIRWING:CreateMissionCAP(Altitude, SpeedOrbit, Heading, Leg)
|
||||
|
||||
local mission={} --#AIRWING.Missiondata
|
||||
|
||||
mission.type=FLIGHTGROUP.MissionType.CAP
|
||||
mission.altitude=UTILS.FeetToMeters(Altitude or 10000)
|
||||
mission.speedOrbit=UTILS.KnotsToMps(SpeedOrbit or 350)
|
||||
mission.heading=Heading or 270
|
||||
mission.leg=UTILS.NMToMeters(Leg or 10)
|
||||
|
||||
mission.waypoint=1
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- Add mission to queue.
|
||||
-- @param #AIRWING self
|
||||
-- @param AIRWING.Missiondata Mission for this group.
|
||||
-- @param Core.Zone#ZONE Zone The mission zone.
|
||||
-- @param #number WaypointIndex The waypoint index.
|
||||
-- @param #string ClockStart Time the mission is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added.
|
||||
-- @param #string ClockStop Time the mission is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
||||
-- @param #number Prio Priority of the mission, i.e. a number between 1 and 100. Default 50.
|
||||
-- @param #string Name Mission name. Default "Aerial Refueling #00X", where "#00X" is a running mission counter index starting at "#001".
|
||||
-- @return #AIRWING.Missiondata The mission table.
|
||||
function AIRWING:AddMission(Mission, Zone, WaypointIndex, ClockStart, ClockStop, Prio, Name)
|
||||
|
||||
-- TODO: need to check that this call increases the correct mission counter and adds it to the mission queue.
|
||||
local mission=FLIGHTGROUP.AddMission(self, Zone, WaypointIndex, ClockStart, ClockStop, Prio, Name, Mission)
|
||||
|
||||
-- Mission needs the correct MID.
|
||||
mission.MID=self.missioncounter
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Start & Status
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -334,7 +356,7 @@ function AIRWING:onafterStart(From, Event, To)
|
||||
self:GetParent(self).onafterStart(self, From, Event, To)
|
||||
|
||||
-- Info.
|
||||
self:I(self.sid..string.format("Starting AIRWING v%s %s (%s)", AIRWING.version, self.alias, self.warehousename))
|
||||
self:I(self.wid..string.format("Starting AIRWING v%s %s (%s)", AIRWING.version, self.alias, self.warehousename))
|
||||
|
||||
-- Add F10 radio menu.
|
||||
self:_SetMenuCoalition()
|
||||
@@ -356,7 +378,7 @@ function AIRWING:onafterAirwingStatus(From, Event, To)
|
||||
|
||||
-- Info text.
|
||||
local text=string.format("State %s", fsmstate)
|
||||
self:I(self.sid..text)
|
||||
self:I(self.wid..text)
|
||||
|
||||
local text="Squadrons:"
|
||||
for i,_squadron in pairs(self.squadrons) do
|
||||
@@ -387,16 +409,18 @@ function AIRWING:onafterAirwingStatus(From, Event, To)
|
||||
|
||||
end
|
||||
end
|
||||
self:I(self.sid..text)
|
||||
self:I(self.wid..text)
|
||||
|
||||
--------------
|
||||
-- Mission ---
|
||||
--------------
|
||||
|
||||
-- Get next mission.
|
||||
local mission=self:_GetNextMission()
|
||||
|
||||
|
||||
-- Request mission execution.
|
||||
if mission then
|
||||
|
||||
if mission.type==AIRWING.MissionType.CAP then
|
||||
self:RequestCAP(coordinate,altitude,leg,heading,speed,squadron)
|
||||
end
|
||||
|
||||
self:RequestMission(mission)
|
||||
end
|
||||
|
||||
self:__AirwingStatus(-30)
|
||||
@@ -408,7 +432,7 @@ end
|
||||
function AIRWING:_GetNextMission()
|
||||
|
||||
-- Number of missions.
|
||||
local Nmissions=#self.Qmissions
|
||||
local Nmissions=#self.missionqueue
|
||||
|
||||
-- Treat special cases.
|
||||
if Nmissions==0 then
|
||||
@@ -419,16 +443,17 @@ function AIRWING:_GetNextMission()
|
||||
local function _sort(a, b)
|
||||
local taskA=a --#AIRWING.Mission
|
||||
local taskB=b --#AIRWING.Mission
|
||||
--TODO: probably sort by prio first and then by time as only missions for T>Tstart are executed. That would ensure that the highest prio mission is carried ot first!
|
||||
return (taskA.Tstart<taskB.Tstart) or (taskA.Tstart==taskB.Tstart and taskA.prio<taskB.prio)
|
||||
end
|
||||
table.sort(self.Qmissions, _sort)
|
||||
table.sort(self.missionqueue, _sort)
|
||||
|
||||
-- Current time.
|
||||
local time=timer.getAbsTime()
|
||||
|
||||
-- Look for first task that is not accomplished.
|
||||
for _,_mission in pairs(self.Qmissions) do
|
||||
local mission=_mission --#AIRWING.Mission
|
||||
for _,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --#AIRWING.Missiondata
|
||||
|
||||
-- Check that mission is still scheduled, time has passed and enough assets are available.
|
||||
if mission.status==AIRWING.MissionStatus.SCHEDULED and time>=mission.Tstart and self:CanMission(mission.type, mission.nassets) then
|
||||
@@ -498,10 +523,49 @@ end
|
||||
function AIRWING:onafterAddMission(From, Event, To, Mission)
|
||||
|
||||
-- Add Mission to queue.
|
||||
table.insert(self.Qmission, Mission)
|
||||
table.insert(self.missionqueue, Mission)
|
||||
|
||||
end
|
||||
|
||||
--- On after "RequestMission" event.
|
||||
-- @param #AIRWING self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #AIRWING.Missiondata Mission The requested mission.
|
||||
function AIRWING:onafterRequestMission(From, Event, To, Mission)
|
||||
|
||||
--TODO: request descriptor/attribute for given mission type! AWACS, Tankers, Fighters.
|
||||
--TODO: also check that mission prio is same as warehouse prio (small=high or the other way around).
|
||||
self:AddRequest(self, WAREHOUSE.Descriptor.ATTRIBUTE, GROUP.Attribute.AIR_FIGHTER, Mission.nassets, nil, nil, Mission.prio, tostring(Mission.mid))
|
||||
|
||||
end
|
||||
|
||||
--- On after "AssetSpawned" event triggered when an asset group is spawned into the cruel world.
|
||||
-- @param #AIRWING self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Wrapper.Group#GROUP group The group spawned.
|
||||
-- @param #AIRWING.SquadronAsset asset The asset that was spawned.
|
||||
-- @param Functional.Warehouse#WAREHOUSE.Pendingitem request The request of the dead asset.
|
||||
function AIRWING:onafterAssetSpawned(From, Event, To, group, asset, request)
|
||||
|
||||
-- Call parent warehouse function first.
|
||||
self:GetParent(self).onafterAssetSpawned(self, From, Event, To, group, asset, request)
|
||||
|
||||
local mid=tonumber(request.assignment)
|
||||
|
||||
-- Set mission.
|
||||
asset.mission=self:GetMissionByID(mid)
|
||||
|
||||
-- Create flightgroup.
|
||||
asset.flightgroup=FLIGHTGROUP:New(group:GetName())
|
||||
|
||||
-- Add mission to flightgroup queue.
|
||||
asset.flightgroup:AddMission(asset.mission)
|
||||
|
||||
end
|
||||
|
||||
--- On after "SelfRequest" event.
|
||||
-- @param #AIRWING self
|
||||
@@ -514,83 +578,24 @@ function AIRWING:onafterSelfRequest(From, Event, To, groupset, request)
|
||||
|
||||
-- Call parent warehouse function first.
|
||||
self:GetParent(self).onafterSelfRequest(self, From, Event, To, groupset, request)
|
||||
|
||||
local mid=tonumber(request.assignment)
|
||||
|
||||
local mission=self:GetMissionByID(mid)
|
||||
|
||||
|
||||
for _,_asset in pairs(request.assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
local a=asset.cargobay
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
end
|
||||
|
||||
if request.assignment==AIRWING.Task.CAP then
|
||||
|
||||
for _,_group in pairs(groupset:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
for _,_group in pairs(groupset:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
local fg=FLIGHTGROUP:New(group:GetName())
|
||||
|
||||
fg:AddMission(request.mission)
|
||||
|
||||
--self:LaunchCAP(group, coordinate, altitude, leg, speed, heading)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Request CAP.
|
||||
-- @param #AIRWING self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Point#COORDINATE coordinate
|
||||
-- @param #number altitude Altitude
|
||||
-- @param #number leg Race track length.
|
||||
-- @param #number heading Heading in degrees.
|
||||
-- @param #number speed Speed in knots.
|
||||
-- @param #AIRWING.Squadron squadron Explicitly request a specific squadron.
|
||||
function AIRWING:onafterRequestCAP(From, Event, To, coordinate, altitude, leg, heading, speed, squadron)
|
||||
|
||||
local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, false)
|
||||
|
||||
if n>0 then
|
||||
|
||||
self:AddRequest(self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, AIRWING.Task.CAP)
|
||||
|
||||
else
|
||||
MESSAGE:New("No CAP planes currently available", 5, "AIRWING"):ToCoalition(self:GetCoalition())
|
||||
self:__RequestCAP(-30, coordinate, altitude, leg, heading, speed, squadron)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Launch a CAP flight.
|
||||
-- @param #AIRWING self
|
||||
-- @param Ops.FlightGroup#FLIGHTGROUP flightgroup Flight group.
|
||||
-- @param Core.Point#COORDINATE capcoord Coordinate of CAP.
|
||||
-- @param #number alt Altitude in feet. Default 20000 ft.
|
||||
-- @param #number leg Length of race track pattern leg. Default 15 NM.
|
||||
-- @param #number heading Heading of race track in degrees. Default 180° i.e. from North to South.
|
||||
-- @param #number speed Speed in knots.
|
||||
function AIRWING:LaunchCAP(flightgroup, capcoord, alt, leg, heading, speed)
|
||||
|
||||
alt=UTILS.FeetToMeters(alt or 20000)
|
||||
|
||||
speed=speed or 350
|
||||
leg=leg or 15
|
||||
|
||||
-- Task orbit.
|
||||
local taskOrbit=flightgroup.group:TaskOrbit(capcoord, alt, UTILS.KnotsToMps(speed+50), capcoord:Translate(UTILS.NMToMeters(leg), heading))
|
||||
|
||||
flightgroup:AddWaypointAir(capcoord, 2, speed)
|
||||
flightgroup:AddTaskWaypoint(taskOrbit, 2, "Orbit", 50, 60*60)
|
||||
|
||||
|
||||
--TODO: flightcontrol would start up the aircraft.
|
||||
flightgroup:StartUncontrolled(5)
|
||||
|
||||
end
|
||||
|
||||
--- Create a new task name.
|
||||
-- @param #AIRWING self
|
||||
-- @param #string task Task of type @{#AIRWING.Task}.
|
||||
@@ -604,77 +609,6 @@ function AIRWING:_NewTaskName(task)
|
||||
return taskname
|
||||
end
|
||||
|
||||
|
||||
--- Request Intercept.
|
||||
-- @param #AIRWING self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Group#GROUP bandits Group of bandits to intercept.
|
||||
-- @param #AIRWING.Squadron squadron Explicitly request a specific squadron.
|
||||
function AIRWING:onafterRequestIntercept(From, Event, To, bandits, squadron)
|
||||
|
||||
local n=self:GetNumberOfAssets(WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, false)
|
||||
|
||||
if n>0 then
|
||||
|
||||
self:__AddRequest(1, self, WAREHOUSE.Descriptor.ASSIGNMENT, squadron.name, 1, nil, nil, nil, AIRWING.Task.INTERCEPT)
|
||||
|
||||
function self:OnAfterSelfRequest(From,Event,To,Groupset,Request)
|
||||
local request=Request --Functional.Warehouse#WAREHOUSE.Pendingitem
|
||||
local groupset=Groupset --Core.Set#SET_GROUP
|
||||
|
||||
if Request.assignment==AIRWING.Task.INTERCEPT then
|
||||
|
||||
for _,_group in pairs(groupset:GetSet()) do
|
||||
local group=_group --Wrapper.Group#GROUP
|
||||
|
||||
self:LaunchIntercept(group)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
MESSAGE:New("No INTERCEPT fighters currently available", 5, "AIRWING"):ToCoalition(self:GetCoalition())
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Launch a flight group to intercept an intruder.
|
||||
-- @param #AIRWING self
|
||||
-- @param Wrapper.Group#GROUP group Interceptor flight group.
|
||||
-- @param Wrapper.Group#GROUP bandits Bandit group.
|
||||
function AIRWING:LaunchIntercept(group, bandit)
|
||||
|
||||
-- Task orbit.
|
||||
local tasks={}
|
||||
|
||||
for _,unit in pairs(bandit:GetUnits()) do
|
||||
tasks[#tasks+1]=group:TaskAttackUnit(unit)
|
||||
end
|
||||
|
||||
local speed=group:GetSpeedMax()
|
||||
local altitude=bandit:GetAltitude()
|
||||
|
||||
-- Create waypoints.
|
||||
local wp={}
|
||||
wp[1]=self:GetCoordinate():WaypointAirTakeOffParking()
|
||||
wp[2]=self:GetCoordinate():SetAltitude(altitude):WaypointAirTurningPoint(COORDINATE.WaypointAltType.BARO, speed, {tasks}, "Intercept")
|
||||
|
||||
-- Start uncontrolled group.
|
||||
group:StartUncontrolled()
|
||||
|
||||
--airboss:SetExcludeAI()
|
||||
|
||||
-- Route group
|
||||
group:Route(wp)
|
||||
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Misc Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -761,7 +695,7 @@ function AIRWING:ReportSquadrons()
|
||||
|
||||
end
|
||||
|
||||
self:I(self.sid..text)
|
||||
self:I(self.wid..text)
|
||||
MESSAGE:New(text, 10, "AIRWING", true):ToCoalition(self:GetCoalition())
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user