mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
1217 lines
44 KiB
Lua
1217 lines
44 KiB
Lua
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--- **Functional** - Control artillery units.
|
|
--
|
|
-- 
|
|
--
|
|
-- ====
|
|
--
|
|
-- The ARTY class can be used to easily assign targets for artillery units. Multiple targets can be assigned.
|
|
--
|
|
--
|
|
-- ====
|
|
--
|
|
-- # Demo Missions
|
|
--
|
|
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
--
|
|
-- ====
|
|
--
|
|
-- # YouTube Channel
|
|
--
|
|
-- ### [MOOSE YouTube Channel](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
|
--
|
|
-- ### Contributions: **Sven van de Velde ([FlightControl](https://forums.eagle.ru/member.php?u=89536))**
|
|
--
|
|
-- ====
|
|
-- @module Arty
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- ARTY class
|
|
-- @type ARTY
|
|
-- @field #string ClassName Name of the class.
|
|
-- @field #boolean Debug Write Debug messages to DCS log file and send Debug messages to all players.
|
|
-- @field #table targets Targets assigned.
|
|
-- @field #table currentTarget Holds the current target, if there is one assigned.
|
|
-- @field #number Nammo0 Initial amount total ammunition (shells+rockets+missiles) of the whole group.
|
|
-- @field #number Nshells0 Initial amount of shells of the whole group.
|
|
-- @field #number Nrockets0 Initial amount of rockets of the whole group.
|
|
-- @field #number Nmissiles0 Initial amount of missiles of the whole group.
|
|
-- @field Core.Scheduler#SCHEDULER TargetQueueSched Scheduler updating the target queue and calling OpenFire event.
|
|
-- @field #number TargetQueueUpdate Interval between updates of the target queue.
|
|
-- @field Core.Scheduler#SCHEDULER CheckRearmedSched Scheduler checking whether reaming of the ARTY group is complete.
|
|
-- @field #table DCSdesc DCS descriptors of the ARTY group.
|
|
-- @field #string Type Type of the ARTY group.
|
|
-- @field #number IniGroupStrength Inital number of units in the ARTY group.
|
|
-- @field #boolean IsArtillery If true, ARTY group has attribute "Artillery".
|
|
-- @field #number Speed Max speed of ARTY group.
|
|
-- @field Wrapper.Unit#UNIT RearmingUnit Unit designated to rearm the ARTY group.
|
|
-- @field #boolean report Arty group sends messages about their current state or target to its coaliton.
|
|
-- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells.
|
|
-- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets.
|
|
-- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles.
|
|
-- @field #number Nshots Number of shots fired on current target.
|
|
-- @field #number WaitForShotTime Max time in seconds to wait until fist shot event occurs after target is assigned. If time is passed without shot, the target is deleted.
|
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
|
--
|
|
|
|
---# ARTY class, extends @{Core.Fsm#FSM_CONTROLLABLE}
|
|
-- Artillery class..
|
|
--
|
|
-- ## Target aquisition...
|
|
--
|
|
-- 
|
|
--
|
|
-- The arty process can be described as follows.
|
|
--
|
|
-- ### Submenu
|
|
--
|
|
-- @field #ARTY
|
|
ARTY={
|
|
ClassName = "ARTY",
|
|
Debug = true,
|
|
targets = {},
|
|
currentTarget = nil,
|
|
Nammo0=0,
|
|
Nshells0=0,
|
|
Nrockets0=0,
|
|
Nmissiles0=0,
|
|
TargetQueueSched=nil,
|
|
TargetQueueUpdate=5,
|
|
CheckRearmedSched=nil,
|
|
DCSdesc=nil,
|
|
Type=nil,
|
|
IniGroupStrength=0,
|
|
IsArtillery=nil,
|
|
RearmingUnit=nil,
|
|
report=true,
|
|
ammoshells={"weapons.shells"},
|
|
ammorockets={"weapons.nurs"},
|
|
ammomissiles={"weapons.missiles"},
|
|
Nshots=0,
|
|
WaitForShotTime=300,
|
|
}
|
|
|
|
--- Weapong type ID. http://wiki.hoggit.us/view/DCS_enum_weapon_flag
|
|
-- @list WeaponType
|
|
ARTY.WeaponType={
|
|
Auto=1073741822,
|
|
UnguidedAny=805339120,
|
|
UnguidedCannon=805306368,
|
|
UnguidedRockets=30720,
|
|
GuidedAny=268402702,
|
|
GuidedMissile=268402688,
|
|
CruiseMissile=2097152,
|
|
}
|
|
|
|
--- Some ID to identify who we are in output of the DCS.log file.
|
|
-- @field #string id
|
|
ARTY.id="ARTY | "
|
|
|
|
--- Range script version.
|
|
-- @field #number version
|
|
ARTY.version="0.3.0"
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- TODO list:
|
|
-- DONE: Delete targets from queue user function.
|
|
-- TODO: Delete entire target queue user function.
|
|
-- TODO: Add weapon types.
|
|
-- DONE: Add user defined rearm weapon types.
|
|
-- TODO: Check if target is in range. Maybe this requires a data base with the ranges of all arty units. Pfff...
|
|
-- TODO: Make ARTY move to reaming position.
|
|
-- TODO: Check that right reaming vehicle is specified. Blue M818, Red Ural-375. Are there more?
|
|
-- TODO: Check if ARTY group is still alive.
|
|
-- TODO: Handle dead events.
|
|
-- TODO: Abort firing task if no shooting event occured with 5(?) minutes. Something went wrong then. Min/max range for example.
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Creates a new ARTY object.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Group#GROUP group The GROUP object for which artillery tasks should be assigned.
|
|
-- @return #ARTY ARTY object.
|
|
-- @return nil If group does not exist or is not a ground group.
|
|
function ARTY:New(group)
|
|
BASE:F2(group)
|
|
|
|
-- Inherits from FSM_CONTROLLABLE
|
|
local self=BASE:Inherit(self, FSM_CONTROLLABLE:New()) -- #ARTY
|
|
|
|
-- Check that group is present.
|
|
if group then
|
|
self:T(ARTY.id..string.format("ARTY script version %s. Added group %s.", ARTY.version, group:GetName()))
|
|
else
|
|
self:E(ARTY.id.."ERROR: Requested ARTY group does not exist! (Has to be a MOOSE group.)")
|
|
return nil
|
|
end
|
|
|
|
-- Check that we actually have a GROUND group.
|
|
if group:IsGround()==false and group:IsShip()==false then
|
|
self:E(ARTY.id..string.format("ERROR: ARTY group %s has to be a GROUND or SHIP group!", group:GetName()))
|
|
return nil
|
|
end
|
|
|
|
-- Set the controllable for the FSM.
|
|
self:SetControllable(group)
|
|
|
|
-- Get DCS descriptors of group.
|
|
local DCSgroup=Group.getByName(group:GetName())
|
|
local DCSunit=DCSgroup:getUnit(1)
|
|
self.DCSdesc=DCSunit:getDesc()
|
|
|
|
-- DCS descriptors.
|
|
self:T3(ARTY.id.."DCS descriptors for group "..group:GetName())
|
|
for id,desc in pairs(self.DCSdesc) do
|
|
self:T3({id=id, desc=desc})
|
|
end
|
|
|
|
-- Set speed to maximum in km/h.
|
|
self.Speed=self.DCSdesc.speedMax*3.6
|
|
|
|
-- Displayed name (similar to type name below)
|
|
self.DisplayName=self.DCSdesc.displayName
|
|
|
|
-- Is this infantry or not.
|
|
self.IsArtillery=DCSunit:hasAttribute("Artillery")
|
|
|
|
-- Type of group.
|
|
self.Type=group:GetTypeName()
|
|
|
|
-- Initial group strength.
|
|
self.IniGroupStrength=#group:GetUnits()
|
|
|
|
-- Set ROE and Alarm State.
|
|
--self:SetDefaultROE("Free")
|
|
--self:SetDefaultAlarmState("Auto")
|
|
|
|
-- Transitions
|
|
self:AddTransition("*", "Start", "CombatReady")
|
|
self:AddTransition("CombatReady", "OpenFire", "Firing")
|
|
self:AddTransition("Firing", "OpenFire", "Firing") -- Other target assigned
|
|
self:AddTransition("Firing", "CeaseFire", "CombatReady")
|
|
self:AddTransition("*", "Winchester", "OutOfAmmo")
|
|
self:AddTransition("OutOfAmmo", "Rearm", "Rearming")
|
|
self:AddTransition("Rearming", "Rearmed", "CombatReady")
|
|
--self:AddTransition("*", "Dead", "*")
|
|
|
|
return self
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Add a group of target(s) for the ARTY group.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Group#GROUP group Group of targets.
|
|
-- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50.
|
|
-- @param #number radius (Optional) Radius. Default is 100 m.
|
|
-- @param #number nshells (Optional) How many shells (or rockets) are fired on target per engagement. Default 5.
|
|
-- @param #number maxengage (Optional) How many times a target is engaged. Default 9999.
|
|
-- @param #string time Day time at which the target should be engaged. Passed as a string in format "08:13:45". Current task will be canceled.
|
|
-- @param #number weapontype Type of weapon to be used to attack this target. Default ARTY.WeaponType.Auto.
|
|
-- @return #string Name of the target. Can be used for further reference, e.g. deleting the target from the list.
|
|
-- @usage ARTY:AssignTargetGroup(GROUP:FindByName("Red Target"), 10, 250, 10, 2, "13:25:45")
|
|
function ARTY:AssignTargetGroup(group, prio, radius, nshells, maxengage, time, weapontype)
|
|
self:E({group=group, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage, time=time, weapontype=weapontype})
|
|
|
|
-- Set default values.
|
|
nshells=nshells or 5
|
|
radius=radius or 100
|
|
maxengage=maxengage or 9999
|
|
prio=prio or 50
|
|
prio=math.max( 1, prio)
|
|
prio=math.min(100, prio)
|
|
weapontype=weapontype or ARTY.WeaponType.Auto
|
|
|
|
-- Coordinate of target.
|
|
local coord=group:GetCoordinate()
|
|
local name=group:GetName()
|
|
|
|
-- Name of target defined my Lat/long in Degree Minute Second format.
|
|
--local name=coord:ToStringLLDMS()
|
|
|
|
-- Check if the name has already been used for another target. If so, the function returns a new unique name.
|
|
name=self:_CheckTargetName(name)
|
|
|
|
-- Time in seconds.
|
|
local _time=self:_ClockToSeconds(time)
|
|
|
|
-- Prepare target array.
|
|
local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage, time=_time, weapontype=weapontype}
|
|
|
|
-- Add to table.
|
|
table.insert(self.targets, _target)
|
|
|
|
-- Clock.
|
|
local _clock=self:_SecondsToClock(_target.time)
|
|
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("Added target %s, prio=%d, radius=%d, nshells=%d, maxengage=%d, time=%s, weapontype=%d", name, prio, radius, nshells, maxengage, _clock, weapontype))
|
|
end
|
|
|
|
|
|
--- Assign coordinates of a target for the ARTY group.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Point#COORDINATE coord Coordinates of the target.
|
|
-- @param #number prio (Optional) Priority of target. Number between 1 (high) and 100 (low). Default 50.
|
|
-- @param #number radius (Optional) Radius. Default is 100 m.
|
|
-- @param #number nshells (Optional) How many shells are fired on target per engagement. Default 5.
|
|
-- @param #number maxengage (Optional) How many times a target is engaged. Default 9999.
|
|
-- @return #string targetname Name of the target.
|
|
function ARTY:AssignTargetCoord(coord, prio, radius, nshells, maxengage)
|
|
self:E({coord=coord, prio=prio, radius=radius, nshells=nshells, maxengage=maxengage})
|
|
|
|
-- Set default values.
|
|
nshells=nshells or 5
|
|
radius=radius or 100
|
|
maxengage=maxengage or 9999
|
|
prio=prio or 50
|
|
prio=math.max( 1, prio)
|
|
prio=math.min(100, prio)
|
|
|
|
-- Coordinate and name.
|
|
local name=coord:ToStringLLDMS()
|
|
|
|
-- Prepare target array.
|
|
local _target={name=name, coord=coord, radius=radius, nshells=nshells, engaged=0, underfire=false, prio=prio, maxengage=maxengage}
|
|
|
|
-- Add to table.
|
|
table.insert(self.targets, _target)
|
|
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("Added target %s, radius=%d, nshells=%d, prio=%d, maxengage=%d.", name, prio, radius, nshells, maxengage))
|
|
|
|
return name
|
|
end
|
|
|
|
--- Assign a unit which is responsible for rearming the ARTY group. If the unit is too far away from the ARTY group it will be guided towards the ARTY group.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Unit#UNIT unit Unit that is supposed to rearm the ARTY group.
|
|
function ARTY:SetRearmingUnit(unit)
|
|
self:F({unit=unit})
|
|
self.RearmingUnit=unit
|
|
end
|
|
|
|
--- Delete target from target list.
|
|
-- @param #ARTY self
|
|
-- @param #string name Name of the target.
|
|
function ARTY:RemoveTarget(name)
|
|
self:F2(name)
|
|
local id=self:_GetTargetByName(name)
|
|
if id then
|
|
table.remove(self.targets, id)
|
|
end
|
|
end
|
|
|
|
--- Define shell types that are counted to determine the ammo amount the ARTY group has.
|
|
-- @param #ARTY self
|
|
-- @param #table tableofnames Table of shell type names.
|
|
function ARTY:SetShellTypes(tableofnames)
|
|
self:F2(tableofnames)
|
|
self.ammoshells={}
|
|
for _,_type in pairs(tableofnames) do
|
|
table.insert(self.ammoshells, _type)
|
|
end
|
|
end
|
|
|
|
--- Define rocket types that are counted to determine the ammo amount the ARTY group has.
|
|
-- @param #ARTY self
|
|
-- @param #table tableofnames Table of rocket type names.
|
|
function ARTY:SetRocketTypes(tableofnames)
|
|
self:F2(tableofnames)
|
|
self.ammorockets={}
|
|
for _,_type in pairs(tableofnames) do
|
|
table.insert(self.ammorockets, _type)
|
|
end
|
|
end
|
|
|
|
--- Define missile types that are counted to determine the ammo amount the ARTY group has.
|
|
-- @param #ARTY self
|
|
-- @param #table tableofnames Table of rocket type names.
|
|
function ARTY:SetMissileTypes(tableofnames)
|
|
self:F2(tableofnames)
|
|
self.ammomissiles={}
|
|
for _,_type in pairs(tableofnames) do
|
|
table.insert(self.ammomissiles, _type)
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- After "Start" event. Initialized ROE and alarm state. Starts the event handler.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function ARTY:onafterStart(Controllable, From, Event, To)
|
|
self:_EventFromTo("onafterStart", Event, From, To)
|
|
|
|
local text=string.format("Started ARTY for group %s.", Controllable:GetName())
|
|
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
|
|
-- Set the current ROE and alam state.
|
|
--self:_SetAlarmState(self.DefaultAlarmState)
|
|
--self:_SetROE(self.DefaultROE)
|
|
|
|
-- Get Ammo.
|
|
self.Nammo0, self.Nshells0, self.Nrockets0, self.Nmissiles0=self:_GetAmmo(self.Controllable)
|
|
|
|
local text=string.format("\n******************************************************\n")
|
|
text=text..string.format("Arty group = %s\n", Controllable:GetName())
|
|
text=text..string.format("Artillery attribute = %s\n", tostring(self.IsArtillery))
|
|
text=text..string.format("Type = %s\n", self.Type)
|
|
text=text..string.format("Number of units = %d\n", self.IniGroupStrength)
|
|
text=text..string.format("Max Speed [km/h] = %d\n", self.Speed)
|
|
text=text..string.format("Total ammo count = %d\n", self.Nammo0)
|
|
text=text..string.format("Number of shells = %d\n", self.Nshells0)
|
|
text=text..string.format("Number of rockets = %d\n", self.Nrockets0)
|
|
text=text..string.format("Number of missiles = %d\n", self.Nmissiles0)
|
|
text=text..string.format("******************************************************\n")
|
|
text=text..string.format("Targets:\n")
|
|
for _, target in pairs(self.targets) do
|
|
local _clock=self:_SecondsToClock(target.time)
|
|
local _weapon=self:_WeaponTypeName(target.weapontype)
|
|
text=text..string.format("- %s, prio=%3d, radius=%5d, nshells=%4d, maxengage=%3d, time=%s, weapon=%s\n", target.name, target.prio, target.radius, target.nshells, target.maxengage, _clock, _weapon)
|
|
end
|
|
text=text..string.format("******************************************************\n")
|
|
text=text..string.format("Shell types:\n")
|
|
for _,_type in pairs(self.ammoshells) do
|
|
text=text..string.format("- %s\n", _type)
|
|
end
|
|
text=text..string.format("Rocket types:\n")
|
|
for _,_type in pairs(self.ammorockets) do
|
|
text=text..string.format("- %s\n", _type)
|
|
end
|
|
text=text..string.format("Missile types:\n")
|
|
for _,_type in pairs(self.ammomissiles) do
|
|
text=text..string.format("- %s\n", _type)
|
|
end
|
|
text=text..string.format("******************************************************")
|
|
self:T(ARTY.id..text)
|
|
|
|
-- Add event handler.
|
|
self:HandleEvent(EVENTS.Shot, self._OnEventShot)
|
|
self:HandleEvent(EVENTS.Dead, self._OnEventDead)
|
|
|
|
-- Start scheduler to monitor task queue.
|
|
self.TargetQueueSched=SCHEDULER:New(nil, ARTY._TargetQueue, {self}, 5, self.TargetQueueUpdate)
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Eventhandler for shot event.
|
|
-- @param #ARTY self
|
|
-- @param Core.Event#EVENTDATA EventData
|
|
function ARTY:_OnEventShot(EventData)
|
|
self:F(EventData)
|
|
|
|
-- Weapon data.
|
|
local _weapon = EventData.Weapon:getTypeName() -- should be the same as Event.WeaponTypeName
|
|
local _weaponStrArray = self:_split(_weapon,"%.")
|
|
local _weaponName = _weaponStrArray[#_weaponStrArray]
|
|
|
|
-- Debug info.
|
|
self:T3(ARTY.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName)
|
|
self:T3(ARTY.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName)
|
|
self:T3(ARTY.id.."EVENT SHOT: Weapon type = ".._weapon)
|
|
self:T3(ARTY.id.."EVENT SHOT: Weapon name = ".._weaponName)
|
|
|
|
local group = EventData.IniGroup --Wrapper.Group#GROUP
|
|
|
|
if group and group:IsAlive() then
|
|
|
|
if EventData.IniGroupName == self.Controllable:GetName() then
|
|
|
|
if self.currentTarget then
|
|
|
|
-- Increase number of shots fired by this group on this target.
|
|
self.Nshots=self.Nshots+1
|
|
|
|
-- Debug output.
|
|
local text=string.format("Group %s fired shot %d of %d with weapon %s on target %s.", self.Controllable:GetName(), self.Nshots, self.currentTarget.nshells, _weaponName, self.currentTarget.name)
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
|
|
|
-- Get current ammo.
|
|
local _nammo,_nshells,_nrockets,_nmissiles=self:_GetAmmo(self.Controllable)
|
|
|
|
if _nammo==0 then
|
|
|
|
self:E(ARTY.id.."completely out of ammo")
|
|
self.Nshots=0
|
|
self:Winchester()
|
|
|
|
-- Current target is deallocated ==> return
|
|
return
|
|
end
|
|
|
|
-- Weapon type name for current target.
|
|
local _weapontype=self:_WeaponTypeName(self.currentTarget.weapontype)
|
|
self:E(ARTY.id..string.format("nammo=%d, nshells=%d, nrockets=%d, nmissiles=%d", _nammo, _nshells, _nrockets, _nmissiles))
|
|
self:E(ARTY.id..string.format("Weapontype = %s", _weapontype))
|
|
|
|
-- Special weapon type requested ==> Check if corresponding ammo is empty.
|
|
if self.currentTarget.weapontype==ARTY.WeaponType.UnguidedCannon and _nshells==0 then
|
|
|
|
self:E(ARTY.id.."cannons requested and shells empty")
|
|
self.Nshots=0
|
|
self:CeaseFire(self.currentTarget)
|
|
return
|
|
|
|
elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedRockets and _nrockets==0 then
|
|
|
|
self:E(ARTY.id.."rockets requested and rockets empty")
|
|
self.Nshots=0
|
|
self:CeaseFire(self.currentTarget)
|
|
return
|
|
|
|
elseif self.currentTarget.weapontype==ARTY.WeaponType.UnguidedAny and _nshells+_nrockets==0 then
|
|
|
|
self:E(ARTY.id.."unguided weapon requested and shells+rockets empty")
|
|
self.Nshots=0
|
|
self:CeaseFire(self.currentTarget)
|
|
return
|
|
|
|
elseif self.currentTarget.weapontype==ARTY.WeaponType.CruiseMissile and _nmissiles==0 then
|
|
|
|
self:E(ARTY.id.."cruise missiles requested and missiles empty")
|
|
self.Nshots=0
|
|
self:CeaseFire(self.currentTarget)
|
|
return
|
|
end
|
|
|
|
-- Check if number of shots reached max.
|
|
if self.Nshots >= self.currentTarget.nshells then
|
|
local text=string.format("Group %s stop firing on target %s.", self.Controllable:GetName(), self.currentTarget.name)
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
|
|
|
self.Nshots=0
|
|
self:CeaseFire(self.currentTarget)
|
|
end
|
|
|
|
else
|
|
self:E(ARTY.id..string.format("ERROR: No current target?!"))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Eventhandler for dead event.
|
|
-- @param #ARTY self
|
|
-- @param Core.Event#EVENTDATA EventData
|
|
function ARTY:_OnEventDead(EventData)
|
|
self:F(EventData)
|
|
end
|
|
|
|
--- Set task for firing at a coordinate.
|
|
-- @param #ARTY self
|
|
-- @param Core.Point#COORDINATE coord Coordinates to fire upon.
|
|
-- @param #number radius Radius around coordinate.
|
|
-- @param #number nshells Number of shells to fire.
|
|
-- @param #number weapontype Type of weapon to use.
|
|
function ARTY:_FireAtCoord(coord, radius, nshells, weapontype)
|
|
self:E({coord=coord, radius=radius, nshells=nshells})
|
|
|
|
-- Controllable.
|
|
local group=self.Controllable --Wrapper.Controllable#CONTROLLABLE
|
|
|
|
-- Set ROE to weapon free.
|
|
group:OptionROEOpenFire()
|
|
|
|
-- Get Vec2
|
|
local vec2=coord:GetVec2()
|
|
|
|
-- Get task.
|
|
local fire=group:TaskFireAtPoint(vec2, radius, nshells, weapontype)
|
|
|
|
-- Execute task.
|
|
group:SetTask(fire)
|
|
--group:PushTask(fire)
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Before "OpenFire" event.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #table target Array holding the target info.
|
|
-- @return #boolean If true proceed to onafterOpenfire.
|
|
function ARTY:onbeforeOpenFire(Controllable, From, Event, To, target)
|
|
self:_EventFromTo("onbeforeOpenFire", Event, From, To)
|
|
|
|
|
|
-- If this target has an attack time and it's prio is higher than the current task, we allow the transition.
|
|
if target.time~=nil and self.currentTarget~=nil and self.currentTarget.prio > target.prio then
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("Group %s current target %s has lower prio than new target %s with attack time.", self.Controllable:GetName(), self.currentTarget.name, target.name))
|
|
|
|
-- Reset current task.
|
|
--self.Controllable:ClearTasks()
|
|
|
|
-- Set number of shots counter to zero.
|
|
self.Nshots=0
|
|
|
|
-- Stop firing on current target.
|
|
self:CeaseFire(self.currentTarget)
|
|
|
|
-- Alow transition to onafterOpenfire.
|
|
return true
|
|
end
|
|
|
|
-- Check that group has no current target already.
|
|
if self.currentTarget then
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name))
|
|
|
|
-- Deny transition.
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--- After "OpenFire" event.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #table target Array holding the target info. _target={coord=coord, radius=radius, nshells=nshells, engaged=0, underattack=false}
|
|
function ARTY:onafterOpenFire(Controllable, From, Event, To, target)
|
|
self:_EventFromTo("onafterOpenFire", Event, From, To)
|
|
|
|
local _coord=target.coord --Core.Point#COORDINATE
|
|
|
|
--_coord:MarkToAll("Arty Target")
|
|
|
|
-- Get target array index.
|
|
local id=self:_GetTargetByName(target.name)
|
|
|
|
-- Target is now under fire and has been engaged once more.
|
|
if id then
|
|
-- Set under fire flag.
|
|
self.targets[id].underfire=true
|
|
-- Increase engaged counter
|
|
self.targets[id].engaged=self.targets[id].engaged+1
|
|
-- Clear the attack time.
|
|
self.targets[id].time=nil
|
|
-- Set current target.
|
|
self.currentTarget=target
|
|
end
|
|
|
|
-- Distance to target
|
|
local range=Controllable:GetCoordinate():Get2DDistance(target.coord)
|
|
|
|
-- Send message.
|
|
local text=string.format("%s, opening fire on target %s with %s shells. Distance %.1f km.", Controllable:GetName(), target.name, target.nshells, range/1000)
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report)
|
|
|
|
-- Start firing.
|
|
self:_FireAtCoord(target.coord, target.radius, target.nshells, target.weapontype)
|
|
|
|
-- Check that after a certain time a shot event occured.
|
|
--self.CheckShootingSched, self.CheckRearmedSchedID=SCHEDULER:New(nil, self._CheckShootingStarted, {self}, self.WaitForShotTime)
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Before "CeaseFire" event.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #table target Array holding the target info.
|
|
-- @return #boolean
|
|
function ARTY:onbeforeCeaseFire(Controllable, From, Event, To, target)
|
|
self:_EventFromTo("onbeforeCeaseFire", Event, From, To)
|
|
|
|
return true
|
|
end
|
|
|
|
--- After "CeaseFire" event.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param #table target Array holding the target info.
|
|
function ARTY:onafterCeaseFire(Controllable, From, Event, To, target)
|
|
self:_EventFromTo("onafterCeaseFire", Event, From, To)
|
|
|
|
-- Send message.
|
|
local text=string.format("%s, ceasing fire on target %s.", Controllable:GetName(), target.name)
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report)
|
|
|
|
-- ARTY group has no current target any more.
|
|
self.currentTarget=nil
|
|
|
|
-- Get target array index.
|
|
local id=self:_GetTargetByName(target.name)
|
|
|
|
-- Target is not under fire any more.
|
|
self.targets[id].underfire=false
|
|
|
|
-- If number of engagements has been reached, the target is removed.
|
|
if target.engaged >= target.maxengage then
|
|
self:RemoveTarget(target.name)
|
|
end
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- After "Winchester" event. Group is out of ammo.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function ARTY:onafterWinchester(Controllable, From, Event, To)
|
|
self:_EventFromTo("onafterWinchester", Event, From, To)
|
|
|
|
local text=string.format("Group %s is winchester (out of ammo)!", Controllable:GetName())
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
|
|
-- Send message.
|
|
local text=string.format("%s, winchester.", Controllable:GetName())
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report)
|
|
|
|
-- Remove current target.
|
|
if self.currentTarget then
|
|
local id=self:_GetTargetByName(self.currentTarget.name)
|
|
self.targets[id].underfire=false
|
|
self.currentTarget=nil
|
|
end
|
|
|
|
-- Init rearming.
|
|
self:Rearm()
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Before "Rearm" event. Check if a unit to rearm the ARTY group has been defined.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function ARTY:onbeforeRearm(Controllable, From, Event, To)
|
|
self:_EventFromTo("onbeforeRearm", Event, From, To)
|
|
|
|
if self.RearmingUnit and self.RearmingUnit:IsAlive() then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- After "Rearm" event. Send message if reporting is on. Route rearming unit to ARTY group.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function ARTY:onafterRearm(Controllable, From, Event, To)
|
|
self:_EventFromTo("onafterRearm", Event, From, To)
|
|
|
|
-- Send message.
|
|
local text=string.format("%s, %s, request rearming.", Controllable:GetName(), self.RearmingUnit:GetName())
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report)
|
|
|
|
-- Random point 20-100 m away from unit.
|
|
local coord=self.Controllable:GetCoordinate()
|
|
local vec2=coord:GetRandomVec2InRadius(20, 100)
|
|
local pops=COORDINATE:NewFromVec2(vec2)
|
|
|
|
-- Route unit to ARTY group.
|
|
self.RearmingUnit:RouteGroundOnRoad(pops, 50, 5)
|
|
|
|
-- Start scheduler to monitor ammo count until rearming is complete.
|
|
self.CheckRearmedSched=SCHEDULER:New(nil,self._CheckRearmed, {self}, 5, 10)
|
|
end
|
|
|
|
|
|
--- Check if ARTY group is reamed.
|
|
-- @param #ARTY self
|
|
function ARTY:_CheckRearmed()
|
|
self:F2()
|
|
|
|
-- Get current ammo.
|
|
local nammo,nshells,nrockets,nmissiles=self:_GetAmmo(self.Controllable)
|
|
|
|
-- Rearming --> Rearmed --> CombatReady
|
|
if nammo==self.Nammo0 then
|
|
self:Rearmed()
|
|
end
|
|
|
|
end
|
|
|
|
--- After "Rearmed" event. Send message if reporting is on and stop the scheduler.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function ARTY:onafterRearmed(Controllable, From, Event, To)
|
|
self:_EventFromTo("onafterRearmed", Event, From, To)
|
|
|
|
-- Send message.
|
|
local text=string.format("%s, rearming complete.", Controllable:GetName())
|
|
self:T(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToCoalitionIf(Controllable:GetCoalition(), self.report)
|
|
|
|
-- Stop scheduler.
|
|
self.CheckRearmedSched:Stop()
|
|
end
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Go through queue of assigned tasks.
|
|
-- @param #ARTY self
|
|
function ARTY:_TargetQueue()
|
|
self:F2()
|
|
|
|
-- Debug info
|
|
self:T(ARTY.id..string.format("Group %s, number of targets = %d", self.Controllable:GetName(), #self.targets))
|
|
|
|
-- We already have a target.
|
|
-- if self.currentTarget then
|
|
-- self:T(ARTY.id..string.format("Group %s already has a target %s.", self.Controllable:GetName(), self.currentTarget.name))
|
|
-- return
|
|
-- end
|
|
|
|
-- First check if there is a target with a certain time for attack.
|
|
for i=1,#self.targets do
|
|
local _target=self.targets[i]
|
|
if _target and _target.time then
|
|
if timer.getAbsTime() >= _target.time and _target.underfire==false then
|
|
|
|
-- Clock time format.
|
|
local _clock=self:_SecondsToClock(_target.time)
|
|
local _Cnow=self:_SecondsToClock(timer.getAbsTime())
|
|
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("Engaging timed target %s. Prio=%d, engaged=%d, time=%s, tnow=%s",_target.name,_target.prio,_target.engaged,_clock,_Cnow))
|
|
|
|
-- Call OpenFire event.
|
|
self:OpenFire(_target)
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Sort targets w.r.t. prio and number times engaged already.
|
|
self:_SortTargetQueuePrio()
|
|
|
|
-- Loop over all sorted targets.
|
|
for i=1,#self.targets do
|
|
|
|
local _target=self.targets[i]
|
|
|
|
if _target.underfire==false and _target.time==nil and _target.maxengage > _target.engaged then
|
|
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("Engaging target %s. Prio = %d, engaged = %d", _target.name, _target.prio, _target.engaged))
|
|
|
|
-- Call OpenFire event.
|
|
self:OpenFire(_target)
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--- Sort targets with respect to priority and number of times it was already engaged.
|
|
-- @param #ARTY self
|
|
function ARTY:_SortTargetQueuePrio()
|
|
self:F2()
|
|
|
|
-- Sort results table wrt times they have already been engaged.
|
|
local function _sort(a, b)
|
|
return (a.engaged < b.engaged) or (a.engaged==b.engaged and a.prio < b.prio)
|
|
end
|
|
table.sort(self.targets, _sort)
|
|
|
|
-- Debug output.
|
|
self:T2(ARTY.id.."Sorted targets wrt prio and number of engagements:")
|
|
for i=1,#self.targets do
|
|
self:T2(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged))
|
|
end
|
|
end
|
|
|
|
--- Sort targets with respect to engage time.
|
|
-- @param #ARTY self
|
|
function ARTY:_SortTargetQueueTime()
|
|
self:F2()
|
|
|
|
-- Sort targets w.r.t attack time.
|
|
local function _sort(a, b)
|
|
if a.time == nil and b.time == nil then
|
|
return false
|
|
end
|
|
if a.time == nil then
|
|
return false
|
|
end
|
|
if b.time == nil then
|
|
return true
|
|
end
|
|
return a.time < b.time
|
|
end
|
|
table.sort(self.targets, _sort)
|
|
|
|
-- Debug output.
|
|
self:T2(ARTY.id.."Sorted targets wrt time:")
|
|
for i=1,#self.targets do
|
|
self:T(ARTY.id..string.format("Target %s, prio=%d, engaged=%d", self.targets[i].name, self.targets[i].prio, self.targets[i].engaged))
|
|
end
|
|
|
|
end
|
|
|
|
--- Get the number of shells a unit or group currently has. For a group the ammo count of all units is summed up.
|
|
-- @param #ARTY self
|
|
-- @param Wrapper.Controllable#CONTROLLABLE controllable
|
|
-- @return Number of ALL shells left from the whole group.
|
|
function ARTY:_GetAmmo(controllable)
|
|
self:F2(controllable)
|
|
|
|
-- Get all units.
|
|
local units=controllable:GetUnits()
|
|
|
|
-- Init counter.
|
|
local nammo=0
|
|
local nshells=0
|
|
local nrockets=0
|
|
local nmissiles=0
|
|
|
|
for _,unit in pairs(units) do
|
|
|
|
if unit and unit:IsAlive() then
|
|
|
|
local ammotable=unit:GetAmmo()
|
|
self:T({ammotable=ammotable})
|
|
|
|
local name=unit:GetName()
|
|
|
|
if ammotable ~= nil then
|
|
|
|
local weapons=#ammotable
|
|
|
|
self:T2(ARTY.id..string.format("Number of weapons %d.", weapons))
|
|
self:T2(ammotable)
|
|
|
|
-- Loop over all weapons.
|
|
for w=1,weapons do
|
|
|
|
-- Number of current weapon.
|
|
local Nammo=ammotable[w]["count"]
|
|
|
|
-- Typename of current weapon
|
|
local Tammo=ammotable[w]["desc"]["typeName"]
|
|
|
|
-- Check for correct shell type.
|
|
local _gotshell=false
|
|
for _,_type in pairs(self.ammoshells) do
|
|
if string.match(Tammo, _type) then
|
|
_gotshell=true
|
|
end
|
|
end
|
|
|
|
-- Check for correct rocket type.
|
|
local _gotrocket=false
|
|
for _,_type in pairs(self.ammorockets) do
|
|
if string.match(Tammo, _type) then
|
|
_gotrocket=true
|
|
end
|
|
end
|
|
|
|
-- Check for correct missile type.
|
|
local _gotmissile=false
|
|
for _,_type in pairs(self.ammomissiles) do
|
|
if string.match(Tammo,_type) then
|
|
_gotmissile=true
|
|
end
|
|
end
|
|
|
|
|
|
-- We are specifically looking for shells or rockets here.
|
|
if _gotshell then
|
|
|
|
-- Add up all shells.
|
|
nshells=nshells+Nammo
|
|
|
|
-- Debug info.
|
|
local text=string.format("Unit %s has %d shells of type %s", name, Nammo, Tammo)
|
|
self:T2(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report)
|
|
|
|
elseif _gotrocket then
|
|
|
|
-- Add up all rockets.
|
|
nrockets=nrockets+Nammo
|
|
|
|
-- Debug info.
|
|
local text=string.format("Unit %s has %d rockets of type %s", name, Nammo, Tammo)
|
|
self:T2(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report)
|
|
|
|
elseif _gotmissile then
|
|
|
|
-- Add up all rockets.
|
|
nmissiles=nmissiles+Nammo
|
|
|
|
-- Debug info.
|
|
local text=string.format("Unit %s has %d missiles of type %s", name, Nammo, Tammo)
|
|
self:T2(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report)
|
|
|
|
else
|
|
|
|
-- Debug info.
|
|
local text=string.format("Unit %s has %d ammo of type %s", name, Nammo, Tammo)
|
|
self:T2(ARTY.id..text)
|
|
MESSAGE:New(text, 10):ToAllIf(self.Debug and not self.report)
|
|
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Total amount of ammunition.
|
|
nammo=nshells+nrockets+nmissiles
|
|
|
|
return nammo, nshells, nrockets, nmissiles
|
|
end
|
|
|
|
|
|
--- Check whether shooting started within a certain time (~5 min). If not, the current target is considered invalid and removed from the target list.
|
|
-- @param #ARTY self
|
|
function ARTY:_CheckShootingStarted()
|
|
self:F2()
|
|
|
|
if self.currentTarget and self.Nshots==0 then
|
|
|
|
-- Get name and id of target.
|
|
local name=self.currentTarget.name
|
|
local id=self:_GetTargetByName(name)
|
|
|
|
-- Debug info.
|
|
self:T(ARTY.id..string.format("No shot event after %d seconds. Removing current target %s from list.", self.WaitForShotTime, name))
|
|
|
|
-- CeaseFire.
|
|
self:CeaseFire(self.currentTarget)
|
|
|
|
-- Remove target from list.
|
|
self:RemoveTarget(name)
|
|
|
|
end
|
|
end
|
|
|
|
--- Get a target by its name.
|
|
-- @param #ARTY self
|
|
-- @param #string name Name of target.
|
|
-- @return #number Arrayindex of target.
|
|
function ARTY:_GetTargetByName(name)
|
|
self:F2(name)
|
|
|
|
for i=1,#self.targets do
|
|
local targetname=self.targets[i].name
|
|
if targetname==name then
|
|
self:T2(ARTY.id..string.format("Found target with name %s. Index = %d", name, i))
|
|
return i
|
|
end
|
|
end
|
|
|
|
self:E(ARTY.id..string.format("ERROR: Target with name %s could not be found!", name))
|
|
return nil
|
|
end
|
|
|
|
|
|
--- Get the weapon type name, which should be used to attack the target.
|
|
-- @param #ARTY self
|
|
-- @param #string name Desired target name.
|
|
-- @return #string Unique name, which is not already given for another target.
|
|
function ARTY:_CheckTargetName(name)
|
|
self:F2(name)
|
|
|
|
local newname=name
|
|
local counter=1
|
|
|
|
repeat
|
|
-- We assume the name is unique.
|
|
local unique=true
|
|
|
|
-- Loop over all targets already defined.
|
|
for _,_target in pairs(self.targets) do
|
|
|
|
-- Target name.
|
|
local _targetname=_target.name
|
|
|
|
if _targetname==newname then
|
|
-- Define new name = "name #01"
|
|
newname=string.format("%s #%02d", name, counter)
|
|
|
|
-- Increase counter.
|
|
counter=counter+1
|
|
|
|
-- Name is already used for another target ==> try again with new name.
|
|
unique=false
|
|
end
|
|
end
|
|
|
|
until (unique)
|
|
|
|
-- Debug output and return new name.
|
|
self:T(string.format("Original name %s, new name = %s", name, newname))
|
|
return newname
|
|
end
|
|
|
|
--- Get the weapon type name, which should be used to attack the target.
|
|
-- @param #ARTY self
|
|
-- @param #number tnumber Number of weapon type ARTY.WeaponType.XXX
|
|
-- @return #number tnumber of weapon type.
|
|
function ARTY:_WeaponTypeName(tnumber)
|
|
local name="unknown"
|
|
if tnumber==ARTY.WeaponType.Auto then
|
|
name="Auto (Cannon, Rockets, Missiles)"
|
|
elseif tnumber==ARTY.WeaponType.CruiseMissile then
|
|
name="Cruise Missile"
|
|
elseif tnumber==ARTY.WeaponType.GuidedAny then
|
|
name="Any Guided Missile"
|
|
elseif tnumber==ARTY.WeaponType.GuidedMissile then
|
|
name="Guided Missile"
|
|
elseif tnumber==ARTY.WeaponType.UnguidedAny then
|
|
name="Any Unguided Weapon (Cannon or Rockets)"
|
|
elseif tnumber==ARTY.WeaponType.UnguidedCannon then
|
|
name="Unguided Cannon"
|
|
elseif tnumber==ARTY.WeaponType.UnguidedRockets then
|
|
name="Unguided Rockets"
|
|
end
|
|
|
|
return name
|
|
end
|
|
|
|
--- Print event-from-to string to DCS log file.
|
|
-- @param #ARTY self
|
|
-- @param #string BA Before/after info.
|
|
-- @param #string Event Event.
|
|
-- @param #string From From state.
|
|
-- @param #string To To state.
|
|
function ARTY:_EventFromTo(BA, Event, From, To)
|
|
local text=string.format("%s: %s EVENT %s: %s --> %s", BA, self.Controllable:GetName(), Event, From, To)
|
|
self:T3(ARTY.id..text)
|
|
end
|
|
|
|
|
|
--- Split string. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua
|
|
-- @param #ARTY self
|
|
-- @param #string str Sting to split.
|
|
-- @param #string sep Speparator for split.
|
|
-- @return #table Split text.
|
|
function ARTY:_split(str, sep)
|
|
self:F3({str=str, sep=sep})
|
|
|
|
local result = {}
|
|
local regex = ("([^%s]+)"):format(sep)
|
|
for each in str:gmatch(regex) do
|
|
table.insert(result, each)
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
--- Convert time in seconds to hours, minutes and seconds.
|
|
-- @param #ARTY self
|
|
-- @param #number seconds Time in seconds.
|
|
-- @return #string Time in format Hours:minutes:seconds.
|
|
function ARTY:_SecondsToClock(seconds)
|
|
self:F3({seconds=seconds})
|
|
|
|
-- Seconds
|
|
local seconds = tonumber(seconds)
|
|
|
|
if seconds==nil then
|
|
return "00:00:00"
|
|
end
|
|
|
|
if seconds <= 0 then
|
|
return "00:00:00"
|
|
else
|
|
local hours = string.format("%02.f", math.floor(seconds/3600))
|
|
local mins = string.format("%02.f", math.floor(seconds/60 - (hours*60)))
|
|
local secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60))
|
|
return hours..":"..mins..":"..secs
|
|
--return hours, mins, secs
|
|
end
|
|
end
|
|
|
|
--- Convert clock time from hours, minutes and seconds to seconds.
|
|
-- @param #ARTY self
|
|
-- @param #string clock String of clock time. E.g., "06:12:35".
|
|
function ARTY:_ClockToSeconds(clock)
|
|
self:F3({clock=clock})
|
|
|
|
if clock==nil then
|
|
return nil
|
|
end
|
|
|
|
-- Split string by ":"
|
|
local tsplit=string.gmatch(clock, '([^:]+)')
|
|
|
|
-- Get time in seconds
|
|
local seconds=0
|
|
local i=1
|
|
for time in tsplit do
|
|
if i==1 then
|
|
-- Hours
|
|
seconds=seconds+tonumber(time)*60*60
|
|
elseif i==2 then
|
|
-- Minutes
|
|
seconds=seconds+tonumber(time)*60
|
|
elseif i==3 then
|
|
-- Seconds
|
|
seconds=seconds+tonumber(time)
|
|
end
|
|
i=i+1
|
|
end
|
|
|
|
self:T3(ARTY.id..string.format("Clock %s = %d seconds", clock, seconds))
|
|
return seconds
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |