This commit is contained in:
Frank
2020-11-13 23:26:56 +01:00
parent f3d9b9c5be
commit 1e0a0f8dc5
5 changed files with 279 additions and 16 deletions

View File

@@ -34,6 +34,8 @@
-- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations.
-- @field #boolean isMobile If true, group is mobile.
-- @field #ARMYGROUP.Target engage Engage target.
-- @field #boolean retreatOnOutOfAmmo If true, the group will automatically retreat when out of ammo. Needs a retreat zone!
-- @field Core.Set#SET_ZONE retreatZones Set of retreat zones.
-- @extends Ops.OpsGroup#OPSGROUP
--- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge
@@ -70,12 +72,13 @@ ARMYGROUP = {
--- Army Group version.
-- @field #string version
ARMYGROUP.version="0.3.0"
ARMYGROUP.version="0.4.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Retreat.
-- TODO: Suppression of fire.
-- TODO: Check if group is mobile.
-- TODO: F10 menu.
@@ -102,6 +105,7 @@ function ARMYGROUP:New(Group)
self:SetDefaultAlarmstate()
self:SetDetection()
self:SetPatrolAdInfinitum(false)
self:SetRetreatZones()
-- Add FSM transitions.
-- From State --> Event --> To State
@@ -112,10 +116,11 @@ function ARMYGROUP:New(Group)
self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate.
self:AddTransition("*", "Retreat", "Retreating") --
self:AddTransition("Retreating", "Retreated", "Holding") --
self:AddTransition("Retreating", "Retreated", "Retreated") --
self:AddTransition("Cruising", "EngageTarget", "Engaging") -- Engage a target
self:AddTransition("Holding", "EngageTarget", "Engaging") -- Engage a target
self:AddTransition("OnDetour", "EngageTarget", "Engaging") -- Engage a target
self:AddTransition("Engaging", "Disengage", "Cruising") -- Engage a target
self:AddTransition("*", "Rearm", "Rearm") -- Group is send to a coordinate and waits until ammo is refilled.
@@ -258,6 +263,24 @@ function ARMYGROUP:AddTaskAttackGroup(TargetGroup, WeaponExpend, WeaponType, Clo
return task
end
--- Define a set of possible retreat zones.
-- @param #ARMYGROUP self
-- @param Core.Set#SET_ZONE RetreatZoneSet The retreat zone set. Default is an empty set.
-- @return #ARMYGROUP self
function ARMYGROUP:SetRetreatZones(RetreatZoneSet)
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
return self
end
--- Add a zone to the retreat zone set.
-- @param #ARMYGROUP self
-- @param Core.Zone#ZONE_BASE RetreatZone The retreat zone.
-- @return #ARMYGROUP self
function ARMYGROUP:AddRetreatZone(RetreatZone)
self.retreatZones:AddZone(RetreatZone)
return self
end
--- Check if the group is currently holding its positon.
-- @param #ARMYGROUP self
-- @return #boolean If true, group was ordered to hold.
@@ -279,6 +302,20 @@ function ARMYGROUP:IsOnDetour()
return self:Is("OnDetour")
end
--- Check if the group is ready for combat. I.e. not reaming, retreating, retreated, out of ammo or engaging.
-- @param #ARMYGROUP self
-- @return #boolean If true, group is on a combat ready.
function ARMYGROUP:IsCombatReady()
local combatready=true
if self:IsRearming() or self:IsRetreating() or self.outofAmmo or self:IsEngaging() or self:is("Retreated") or self:IsDead() or self:IsStopped() or self:IsInUtero() then
combatready=false
end
return combatready
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -325,6 +362,9 @@ function ARMYGROUP:onafterStatus(From, Event, To)
-- Check if group got stuck.
self:_CheckStuck()
-- Check damage of elements and group.
self:_CheckDamage()
-- Update engagement.
if self:IsEngaging() then
self:_UpdateEngageTarget()
@@ -344,8 +384,8 @@ function ARMYGROUP:onafterStatus(From, Event, To)
local ammo=self:GetAmmoTot()
-- Info text.
local text=string.format("%s [ROE-AS=%d-%d T/M=%d/%d]: Wp=%d/%d-->%d (final %s), Speed=%.1f (%d), Heading=%03d, Ammo=%d",
fsmstate, roe, alarm, nTaskTot, nMissions, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), tostring(self.passedfinalwp), speed, speedEx, self.heading, ammo.Total)
local text=string.format("%s [ROE-AS=%d-%d T/M=%d/%d]: Wp=%d/%d-->%d (final %s), Life=%.1f, Speed=%.1f (%d), Heading=%03d, Ammo=%d",
fsmstate, roe, alarm, nTaskTot, nMissions, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), tostring(self.passedfinalwp), self.life or 0, speed, speedEx, self.heading, ammo.Total)
self:I(self.lid..text)
end
@@ -596,6 +636,13 @@ end
-- @param #number ResumeRoute If true, resume route after detour point was reached. If false, the group will stop at the detour point and wait for futher commands.
function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation, ResumeRoute)
for _,_wp in pairs(self.waypoints) do
local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint
if wp.detour then
self:RemoveWaypointByID(wp.uid)
end
end
-- Speed in knots.
Speed=Speed or self:GetSpeedCruise()
@@ -652,6 +699,103 @@ function ARMYGROUP:onafterRearming(From, Event, To)
end
--- On before "Retreat" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE_BASE Zone (Optional) Zone where to retreat. Default is the closest retreat zone.
-- @param #number Formation (Optional) Formation of the group.
function ARMYGROUP:onbeforeRetreat(From, Event, To, Zone, Formation)
if not Zone then
local a=self:GetVec2()
local distmin=math.huge
local zonemin=nil
for _,_zone in pairs(self.retreatZones:GetSet()) do
local zone=_zone --Core.Zone#ZONE_BASE
local b=zone:GetVec2()
local dist=UTILS.VecDist2D(a, b)
if dist<distmin then
distmin=dist
zonemin=zone
end
end
if zonemin then
self:__Retreat(0.1, zonemin, Formation)
end
return false
end
return true
end
--- On after "Retreat" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE_BASE Zone (Optional) Zone where to retreat. Default is the closest retreat zone.
-- @param #number Formation (Optional) Formation of the group.
function ARMYGROUP:onafterRetreat(From, Event, To, Zone, Formation)
-- ID of current waypoint.
local uid=self:GetWaypointCurrent().uid
local Coordinate=Zone:GetRandomCoordinate()
-- Add waypoint after current.
local wp=self:AddWaypoint(Coordinate, nil, uid, Formation, true)
-- Set if we want to resume route after reaching the detour waypoint.
wp.detour=0
end
--- On after "Retreated" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function ARMYGROUP:onafterRetreated(From, Event, To)
-- Get current position.
local pos=self:GetCoordinate()
-- Create a new waypoint.
local wp=pos:WaypointGround(0)
-- Create new route consisting of only this position ==> Stop!
self:Route({wp})
end
--- On after "EngageTarget" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP Group the group to be engaged.
function ARMYGROUP:onbeforeEngageTarget(From, Event, To, Target)
local ammo=self:GetAmmoTot()
if ammo.Total==0 then
env.info("FF cannot engage because no ammo!")
return false
end
return true
end
--- On after "EngageTarget" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
@@ -1031,11 +1175,13 @@ function ARMYGROUP:_InitGroup()
element.categoryname=element.unit:GetCategoryName()
element.size, element.length, element.height, element.width=unit:GetObjectSize()
element.ammo0=self:GetAmmoUnit(unit, false)
element.life0=unit:GetLife0()
element.life=element.life0
-- Debug text.
if self.verbose>=2 then
local text=string.format("Adding element %s: status=%s, skill=%s, category=%s (%d), size: %.1f (L=%.1f H=%.1f W=%.1f)",
element.name, element.status, element.skill, element.categoryname, element.category, element.size, element.length, element.height, element.width)
local text=string.format("Adding element %s: status=%s, skill=%s, life=%.3f category=%s (%d), size: %.1f (L=%.1f H=%.1f W=%.1f)",
element.name, element.status, element.skill, element.life, element.categoryname, element.category, element.size, element.length, element.height, element.width)
self:I(self.lid..text)
end