diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index e834f8d4d..098cbab22 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -33,6 +33,7 @@ -- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached. -- @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. -- @extends Ops.OpsGroup#OPSGROUP --- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge @@ -49,6 +50,7 @@ ARMYGROUP = { ClassName = "ARMYGROUP", formationPerma = nil, + engage = {}, } --- Army group element. @@ -61,6 +63,11 @@ ARMYGROUP = { -- @field #number width Width of element in meters. -- @field #number height Height of element in meters. +--- Target +-- @type ARMYGROUP.Target +-- @field Ops.Target#TARGET Target The target. +-- @field Core.Point#COORDINATE Coordinate Last known coordinate of the target. + --- Army Group version. -- @field #string version ARMYGROUP.version="0.3.0" @@ -103,6 +110,13 @@ function ARMYGROUP:New(Group) self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards. self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate. + + self:AddTransition("*", "Retreat", "Retreating") -- + self:AddTransition("Retreating", "Retreated", "Holding") -- + + self:AddTransition("Cruising", "EngageTarget", "Engaging") -- Engage a target + self:AddTransition("Holding", "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. self:AddTransition("Rearm", "Rearming", "Rearming") -- Group has arrived at the rearming coodinate and is waiting to be fully rearmed. @@ -311,6 +325,11 @@ function ARMYGROUP:onafterStatus(From, Event, To) -- Check if group got stuck. self:_CheckStuck() + -- Update engagement. + if self:IsEngaging() then + self:_UpdateEngageTarget() + end + if self.verbose>=1 then -- Get number of tasks and missions. @@ -321,11 +340,12 @@ function ARMYGROUP:onafterStatus(From, Event, To) local alarm=self:GetAlarmstate() local speed=UTILS.MpsToKnots(self.velocity) local speedEx=UTILS.MpsToKnots(self:GetExpectedSpeed()) - local formation=self.option.Formation or "unknown" + local formation=self.option.Formation or "unknown" + 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", - fsmstate, roe, alarm, nTaskTot, nMissions, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), tostring(self.passedfinalwp), speed, speedEx, self.heading) + 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) self:I(self.lid..text) end @@ -506,7 +526,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation) end end - if not self.passedfinalwp then + if self:IsEngaging() or not self.passedfinalwp then -- Debug info. self:T(self.lid..string.format("Updateing route: WP %d-->%d (%d/%d), Speed=%.1f knots, Formation=%s", @@ -632,6 +652,85 @@ function ARMYGROUP:onafterRearming(From, Event, To) 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:onafterEngageTarget(From, Event, To, Target) + + if Target:IsInstanceOf("TARGET") then + self.engage.Target=Target + else + self.engage.Target=TARGET:New(Target) + end + + env.info("FF Engage Target "..self.engage.Target:GetName()) + + self.engage.Coordinate=UTILS.DeepCopy(self.engage.Target:GetCoordinate()) + + self:SwitchAlarmstate(ENUMS.AlarmState.Auto) + self:SwitchROE(ENUMS.ROE.WeaponFree) + + -- ID of current waypoint. + local uid=self:GetWaypointCurrent().uid + + -- Add waypoint after current. + self.engage.Waypoint=self:AddWaypoint(self.engage.Coordinate, nil, uid, Formation, true) + + -- Set if we want to resume route after reaching the detour waypoint. + self.engage.Waypoint.detour=1 + +end + +--- On after "EngageTarget" event. +-- @param #ARMYGROUP self +function ARMYGROUP:_UpdateEngageTarget() + + if self.engage.Target and self.engage.Target:IsAlive() then + + env.info("FF Update Engage Target "..self.engage.Target:GetName()) + + local vec3=self.engage.Target:GetCoordinate():GetVec3() + + local dist=UTILS.VecDist2D(vec3, self.engage.Coordinate:GetVec3()) + + if dist>100 then + + env.info("FF Update Engage Target Moved "..self.engage.Target:GetName()) + + self.engage.Coordinate:UpdateFromVec3(vec3) + + -- ID of current waypoint. + local uid=self:GetWaypointCurrent().uid + + -- Remove current waypoint + self:RemoveWaypointByID(self.engage.Waypoint.uid) + + -- Add waypoint after current. + self.engage.Waypoint=self:AddWaypoint(self.engage.Coordinate, nil, uid, Formation, true) + + -- Set if we want to resume route after reaching the detour waypoint. + self.engage.Waypoint.detour=0 + + end + + else + self:Disengage() + end + +end + +--- On after "Disengage" event. +-- @param #ARMYGROUP self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function ARMYGROUP:onafterDisengage(From, Event, To) + self:_CheckGroupDone(1) +end + --- On after "Rearmed" event. -- @param #ARMYGROUP self -- @param #string From From state. diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index bf6683de1..f032d03ae 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -1245,6 +1245,13 @@ function OPSGROUP:IsLasing() return self.spot.On end +--- Check if the group has currently switched a LASER on. +-- @param #OPSGROUP self +-- @return #boolean If true, LASER of the group is on. +function OPSGROUP:IsEngaging() + return self:is("Engaging") +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Waypoint Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -3909,6 +3916,11 @@ function OPSGROUP:_CheckGroupDone(delay) self:ScheduleOnce(delay, self._CheckGroupDone, self) else + if self:IsEngaging() then + self:UpdateRoute() + return + end + -- Get current waypoint. local waypoint=self:GetWaypoint(self.currentwp) @@ -4120,8 +4132,13 @@ function OPSGROUP:_CheckAmmoStatus() if ammo.Missiles==0 and self.ammo.Missiles>0 and not self.outofMissiles then self.outofMissiles=true self:OutOfMissiles() - end - + end + + -- Check if group is engaging. + if self:IsEngaging() and ammo.Total==0 then + self:Disengage() + end + end end @@ -4265,6 +4282,9 @@ function OPSGROUP:InitWaypoints() -- Coordinate of the waypoint. local coordinate=COORDINATE:New(wp.x, wp.alt, wp.y) + -- Strange! + wp.speed=wp.speed or 0 + -- Speed at the waypoint. local speedknots=UTILS.MpsToKnots(wp.speed) @@ -4423,6 +4443,10 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid) -- Trigger Rearming event. opsgroup:Rearming() + elseif opsgroup:IsEngaging() then + + -- Nothing to do really. + else -- Trigger DetourReached event. diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index a89f023a5..969d01e6a 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -244,6 +244,19 @@ function TARGET:AddObject(Object) end +--- Check if TARGET is alive. +-- @param #TARGET self +-- @param #boolean If true, target is alive. +function TARGET:IsAlive() + return self:Is("Alive") +end + +--- Check if TARGET is dead. +-- @param #TARGET self +-- @param #boolean If true, target is dead. +function TARGET:IsDead() + return self:Is("Dead") +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Start & Status @@ -302,7 +315,7 @@ function TARGET:onafterStatus(From, Event, To) end -- Log output verbose=1. - if self.verbose>=1 then + if self.verbose>=0 then local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.Ntargets0, self:GetLife(), self:GetLife0(), self:GetDamage()) if damaged then text=text.." Damaged!" @@ -311,7 +324,7 @@ function TARGET:onafterStatus(From, Event, To) end -- Log output verbose=2. - if self.verbose>=2 then + if self.verbose>=0 then local text="Target:" for i,_target in pairs(self.targets) do local target=_target --#TARGET.Object @@ -349,7 +362,8 @@ end -- @param #TARGET.Object Target Target object. function TARGET:onafterObjectDestroyed(From, Event, To, Target) - self:T(self.lid..string.format("Object %s destroyed", Target.Name)) + -- Debug message. + self:I(self.lid..string.format("Object %s destroyed", Target.Name)) -- Set target status. Target.Status=TARGET.ObjectStatus.DEAD @@ -405,16 +419,20 @@ function TARGET:OnEventUnitDeadOrLost(EventData) if EventData and EventData.IniUnitName then -- Debug info. - --self:T3(self.lid..string.format("EVENT: Unit %s dead or lost!", EventData.IniUnitName)) + self:I(self.lid..string.format("EVENT: Unit %s dead or lost!", EventData.IniUnitName)) -- Get target. local target=self:GetTargetByName(EventData.IniUnitName) + + if not target then + target=self:GetTargetByName(EventData.IniGroupName) + end -- Check if this is one of ours. if target and target.Status==TARGET.ObjectStatus.ALIVE then -- Debug message. - self:T3(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", target.Name)) + self:I(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", target.Name)) -- Trigger object destroyed event. self:ObjectDestroyed(target) @@ -684,7 +702,11 @@ function TARGET:GetTargetVec3(Target) if object and object:IsAlive() then - return object:GetVec3() + return object:GetVec3() + + else + + return nil end @@ -1007,7 +1029,7 @@ function TARGET:CountTargets() -- No target we can check! else - self:E(self.lid.."ERROR unknown target type") + self:E(self.lid.."ERROR: Unknown target type! Cannot count targets") end end