mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Suppression Fire
This commit is contained in:
parent
cbc0579c79
commit
a575dfea7d
@ -1,120 +1,303 @@
|
||||
---
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--- **Functional** - Suppress fire of ground units when they get hit.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- When ground units get hit by (suppressive) enemy fire, they will not be able to shoot back for a certain amount of time.
|
||||
--
|
||||
-- The implementation is based on an idea and script by MBot. See DCS forum threat https://forums.eagle.ru/showthread.php?t=107635 for details.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- # 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 AI_Suppression
|
||||
|
||||
--- @type AI_Suppression
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--- AI_Suppression class
|
||||
-- @type AI_Suppression
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number Tsuppress_min Minimum time in seconds the group gets suppressed.
|
||||
-- @field #number Tsuppress_max Maximum time in seconds the group gets suppressed.
|
||||
-- @field #number life Relative life in precent of the group.
|
||||
-- @field #number Tsuppress Time in seconds the groups is suppressed. Randomly chosen between Tsuppress_min and Tsuppress_max.
|
||||
-- @field #number Thit Last time the unit was hit.
|
||||
-- @field #number Nhit Number of times the unit was hit since it last was in state "CombatReady".
|
||||
-- @field Core.Zone#ZONE Zone_Retreat Zone into which a group retreats.
|
||||
-- @field #number LifeMin Life of group in percent at which the group will be ordered to retreat.
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
--
|
||||
|
||||
--TODO: Figure out who was shooting and move away from him.
|
||||
---# AI_Suppression class, extends @{Core.Fsm#FSM_CONTROLLABLE}
|
||||
-- Mimic suppressive fire and make ground units take cover.
|
||||
--
|
||||
-- ## Some Example...
|
||||
--
|
||||
-- @field AI_Suppression
|
||||
AI_Suppression={
|
||||
ClassName = "AI_Suppression",
|
||||
Tsuppress_min = 5,
|
||||
Tsuppress_max = 20,
|
||||
Tsuppress = nil,
|
||||
Thit = nil,
|
||||
Nhit = 0,
|
||||
Zone_Retreat = nil,
|
||||
LifeMin = 10,
|
||||
}
|
||||
|
||||
--- Some ID to identify who we are in output of the DCS.log file.
|
||||
-- @field #string id
|
||||
AI_Suppression.id="SFX | "
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--TODO: Figure out who was shooting and move away from him <== not possible.
|
||||
--TODO: Move behind a scenery building if there is one nearby.
|
||||
--TODO: Retreat to a given zone or point.
|
||||
--TODO:
|
||||
|
||||
-- @field AI_Suppression
|
||||
AI_Suppression={}
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Creates a new AI_suppression object
|
||||
--- Creates a new AI_suppression object.
|
||||
-- @param #AI_Suppression self
|
||||
-- @param Wrapper.Group#GROUP Group The GROUP object for which suppression should be applied.
|
||||
-- @return #AI_Suppression
|
||||
function AI_Suppression:New(Group)
|
||||
env.info("Suppression Fire for group "..Group:GetName())
|
||||
env.info("Suppression fire for group "..Group:GetName())
|
||||
|
||||
-- Check that we actually have a ground group.
|
||||
if Group:IsGround()==false then
|
||||
env.error("Suppression fire group "..Group:GetName().." has to be a GROUND group!")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Inherits from FSM_CONTROLLABLE
|
||||
local self=BASE:Inherit(self, FSM_CONTROLLABLE:New()) -- #AI_Suppression
|
||||
|
||||
-- Set the controllable for the FSM.
|
||||
self:SetControllable(Group)
|
||||
|
||||
self.life=self.Controllable:GetLife()
|
||||
|
||||
self.Tsuppressed=0
|
||||
|
||||
-- Time the group is suppressed after being hit.
|
||||
self.Tsuppress=40
|
||||
|
||||
-- Group is initially in state CombatReady.
|
||||
self:SetStartState("CombatReady")
|
||||
|
||||
self:AddTransition("*", "Status", "*")
|
||||
-- Transitions:
|
||||
---------------
|
||||
|
||||
-- Transition from anything to "Suppressed" after event "Hit".
|
||||
self:AddTransition("*", "Hit", "Suppressed")
|
||||
|
||||
-- Transition from "Suppressed" back to "CombatReady after the unit had time to recover.
|
||||
self:AddTransition("Suppressed", "Recovered", "CombatReady")
|
||||
|
||||
self:AddTransition("*", "Hit", "TakeCover")
|
||||
-- Transition from "Suppressed" to "TakeCover" after event "Hit".
|
||||
--self:AddTransition("Suppressed", "Hit", "TakeCover")
|
||||
|
||||
-- Handle the event hit.
|
||||
-- Transition from anything to "Retreating" after e.g. being severely damaged.
|
||||
self:AddTransition("*", "Retreat", "Retreating")
|
||||
|
||||
-- Transition from anything to "Dead" after group died.
|
||||
self:AddTransition("*", "Died", "Dead")
|
||||
|
||||
|
||||
-- Handle DCS event hit.
|
||||
self:HandleEvent(EVENTS.Hit, self.OnEventHit)
|
||||
|
||||
-- Handle the event dead.
|
||||
-- Handle DCS event dead.
|
||||
self:HandleEvent(EVENTS.Dead, self.OnEventDead)
|
||||
|
||||
--self:AddTransition("Suppressed", "Status", "CombatReady")
|
||||
-- return self
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Set minimum and (optionally) maximum time a unit is suppressed each time it gets hit.
|
||||
-- @param #AI_Suppression self
|
||||
-- @param #number Tmin Minimum time in seconds.
|
||||
-- @param #number Tmax (Optional) Maximum suppression time. If no value is given, the is set to Tmin.
|
||||
function AI_Suppression:SetSuppressionTime(Tmin, Tmax)
|
||||
self.Tsuppress_min=Tmin
|
||||
self.Tsuppress_max=Tmax or Tmin
|
||||
env.info(AI_Suppression.id..string.format("Min suppression time %d seconds.", self.Tsuppress_min))
|
||||
env.info(AI_Suppression.id..string.format("Max suppression time %d seconds.", self.Tsuppress_max))
|
||||
end
|
||||
|
||||
--- Set the zone to which a group retreats after being damaged too much.
|
||||
-- @param #AI_Suppression self
|
||||
-- @param Core.Zone#ZONE zone MOOSE zone object.
|
||||
function AI_Suppression:SetRetreatZone(zone)
|
||||
self.Zone_Retreat=zone
|
||||
env.info(AI_Suppression.id..string.format("Retreat zone for group %s is %s.", self.Controllable:GetName(), self.Zone_Retreat:GetName()))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Before "Hit" event. (Of course, this is not really before the group got hit.)
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnBeforeHit(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnBeforeHit: From %s, Event %s, To %s", From, Event, To))
|
||||
-- Increase Hit counter.
|
||||
self.Nhit=self.Nhit+1
|
||||
env.info(AI_Suppression.id..string.format("Group has just been hit %d times.", self.Nhit))
|
||||
end
|
||||
|
||||
--- After "Hit" event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnAfterHit(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnAfterHit: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- Nothing to do yet. Just monitoring the event.
|
||||
-- This should go into Suppressed state.
|
||||
end
|
||||
|
||||
|
||||
--- Before "Recovered" event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnBeforeRecovered(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnBeforeRecovered: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- Current time.
|
||||
local Tnow=timer.getTime()
|
||||
|
||||
-- Here I need to figure our how to correctly go back to "CombatReady".
|
||||
-- Problem is that another "Hit" event might occur while the group is recovering.
|
||||
-- If that happens the time to recover should be reset.
|
||||
-- Only after a unit has not been hit for X seconds.
|
||||
-- We can return false if the recovery should not be executed!
|
||||
|
||||
env.info(AI_Suppression.id..string.format("OnBeforeRecover: Time: %d - Time over: %d", Tnow, self.TsuppressionOver))
|
||||
|
||||
-- Recovery is only possible if enough time since the last hit has passed.
|
||||
if Tnow > self.TsuppressionOver then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Before status event.
|
||||
--- After "Recovered" event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnBeforeStatus()
|
||||
return self.CheckStatus
|
||||
function AI_Suppression:OnAfterRecovered(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnAfterRecovered: From %s, Event %s, To %s", From, Event, To))
|
||||
MESSAGE:New("Group has recovered.", 30):ToAll()
|
||||
-- Nothing to do yet. Just monitoring the event.
|
||||
end
|
||||
|
||||
--- After status event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnBeforeStatus()
|
||||
self:__Status(10)
|
||||
end
|
||||
|
||||
--- After hit event.
|
||||
--- Before "Retreat" event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnAfterHit(From, Event, To)
|
||||
|
||||
end
|
||||
|
||||
--- After hit event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnAfterRecover(From, Event, To)
|
||||
local Tnow=timer.getTime()
|
||||
if Tnow-self.Tsuppressed > self.Tsuppress then
|
||||
self:CombatReady()
|
||||
function AI_Suppression:OnBeforeRetreat(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnBeforeRetreat: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- Retreat is only possible if a zone has been defined by the user.
|
||||
if self.Zone_Retreat==nil then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- After hit event.
|
||||
--- After "Retreat" event.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnAfterRetreat(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnAfterHit: From %s, Event %s, To %s", From, Event, To))
|
||||
local text=string.format("Group %s is retreating to zone %s.", self.Controllable:GetName(), self.Zone_Retreat:GetName())
|
||||
MESSAGE:New(text, 30):ToAll()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Entering "CombatReady" state. The group will be able to fight back.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnEnterCombatReady(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnEnterCombatReady: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- Group can fight again.
|
||||
self.Controllable:OptionROEOpenFire()
|
||||
|
||||
end
|
||||
|
||||
--- Entering suppressed state.
|
||||
--- Leaving "CombatReady" state.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnLeaveCombatReady(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnLeaveCombatReady: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- Nothing to do yet. Just monitoring the event
|
||||
end
|
||||
|
||||
|
||||
--- Entering "Suppressed" state. Group will not fight but hold their weapons.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnEnterSuppressed(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnEnterSuppressed: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- Current time.
|
||||
local Tnow=timer.getTime()
|
||||
|
||||
-- Group will hold their weapons.
|
||||
self.Controllable:OptionROEHoldFire()
|
||||
|
||||
-- Get randomized time the unit is suppressed.
|
||||
self.Tsuppress=math.random(self.Tsuppress_min, self.Tsuppress_max)
|
||||
|
||||
-- Recovery will be in Tsuppress seconds.
|
||||
self:__Recover(self.Tsuppress)
|
||||
-- Time at which the suppression is over.
|
||||
self.TsuppressionOver=Tnow+self.Tsuppress
|
||||
|
||||
|
||||
if From=="CombatReady" then
|
||||
-- Recovery event will be called in Tsuppress seconds. (We add one second to be sure the time has really passed when recovery is checked.)
|
||||
self:__Recover(self.Tsuppress+1)
|
||||
|
||||
|
||||
elseif From=="Suppressed" then
|
||||
|
||||
else
|
||||
-- Get life of group in %.
|
||||
self.life=self:_GetLife(self.Controllable)
|
||||
|
||||
-- If life is below threshold, the group is ordered to retreat (if a zone has been specified).
|
||||
if self.life < self.LifeMin then
|
||||
self:Retreat()
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Entering "Retreating" state. Group will be send to a zone.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnEnterRetreating(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnEnterRetreating: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
--- @param #AI_Suppression self
|
||||
--TODO: Here we need to set the ALARM STATE to GREEN. Then the unit can move even if it is under fire.
|
||||
--self.Controllable:OptionROEOpenFire()
|
||||
|
||||
--TODO: Route the group to a zone.
|
||||
|
||||
end
|
||||
|
||||
--- Leaving "Retreating" state.
|
||||
-- @param #AI_Suppression self
|
||||
function AI_Suppression:OnLeaveRetreating(From, Event, To)
|
||||
env.info(AI_Suppression.id..string.format("OnLeaveRetreating: From %s, Event %s, To %s", From, Event, To))
|
||||
|
||||
-- TODO: Here we need to set the ALARM STATE back to AUTO.
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Handle the DCS event hit.
|
||||
-- @param #AI_Suppression self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_Suppression:OnEventHit(EventData)
|
||||
self:E({"EventHit", EventData })
|
||||
@ -122,18 +305,38 @@ function AI_Suppression:OnEventHit(EventData)
|
||||
|
||||
if EventData.IniDCSUnit then
|
||||
|
||||
--self:Hit()
|
||||
-- Call "Hit" event.
|
||||
self:Hit()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_Suppression self
|
||||
--- Handle the DCS event dead.
|
||||
-- @param #AI_Suppression self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_Suppression:OnEventDead(EventData)
|
||||
self:E({"EventHit", EventData })
|
||||
self:E({"EventDead", EventData })
|
||||
env.info("Deadevent")
|
||||
if EventData.IniDCSUnit then
|
||||
--blabla
|
||||
--self:Died()
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Get (relative) life of first unit of a group.
|
||||
-- @param #AI_Suppression self
|
||||
-- @param Wrapper.Group#GROUP group Group of unit.
|
||||
-- @return #number Life of unit in percent.
|
||||
function AI_Suppression:_GetLife(group)
|
||||
local life=0.0
|
||||
if group and group:IsAlive() then
|
||||
local unit=group:GetUnit(1)
|
||||
if unit then
|
||||
life=unit:GetLife()/unit:GetLife0()*100
|
||||
end
|
||||
end
|
||||
return life
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Loading…
x
Reference in New Issue
Block a user