diff --git a/Moose Development/Moose/Ops/ArmyGroup.lua b/Moose Development/Moose/Ops/ArmyGroup.lua index df52c7cc8..31c0aa727 100644 --- a/Moose Development/Moose/Ops/ArmyGroup.lua +++ b/Moose Development/Moose/Ops/ArmyGroup.lua @@ -375,7 +375,7 @@ function ARMYGROUP:onafterSpawned(From, Event, To) -- Update position. self:_UpdatePosition() - if self.ai then + if self.isAI then -- Set default ROE. self:SwitchROE(self.option.ROE) @@ -859,8 +859,8 @@ function ARMYGROUP:_InitGroup() self.isNaval=false self.isGround=true - -- Ships are always AI. - self.ai=true + -- Ground are always AI. + self.isAI=true -- Is (template) group late activated. self.isLateActivated=self.template.lateActivation diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 54d186a09..08bab7e77 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1690,6 +1690,13 @@ function AUFTRAG:GetPriority() return self.prio end +--- Get casualties, i.e. number of units that died during this mission. +-- @param #AUFTRAG self +-- @return #number Number of dead units. +function AUFTRAG:GetCasualties() + return self.Ncasualties or 0 +end + --- Check if mission is "urgent". -- @param #AUFTRAG self -- @return #boolean If `true`, mission is "urgent". diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index dc73d37e2..1267c8cb8 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -411,7 +411,7 @@ function FLIGHTGROUP:SetFlightControl(flightcontrol) table.insert(flightcontrol.flights, self) -- Update flight's F10 menu. - if self.ai==false then + if self.isAI==false then self:_UpdateMenu(0.5) end @@ -1055,7 +1055,7 @@ function FLIGHTGROUP:OnEventEngineStartup(EventData) -- TODO: could be that this element is part of a human flight group. -- Problem: when player starts hot, the AI does too and starts to taxi immidiately :( -- when player starts cold, ? - if self.ai then + if self.isAI then self:ElementEngineOn(element) else if element.ai then @@ -1462,7 +1462,7 @@ function FLIGHTGROUP:onafterSpawned(From, Event, To) -- Update position. self:_UpdatePosition() - if self.ai then + if self.isAI then -- Set ROE. self:SwitchROE(self.option.ROE) @@ -1537,7 +1537,7 @@ function FLIGHTGROUP:onafterParking(From, Event, To) self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.PARKING) -- Update player menu. - if not self.ai then + if not self.isAI then self:_UpdateMenu(0.5) end @@ -1562,7 +1562,7 @@ function FLIGHTGROUP:onafterTaxiing(From, Event, To) if self.flightcontrol and airbase and self.flightcontrol.airbasename==airbase:GetName() then -- Add AI flight to takeoff queue. - if self.ai then + if self.isAI then -- AI flights go directly to TAKEOFF as we don't know when they finished taxiing. self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.TAKEOFF) else @@ -1601,7 +1601,7 @@ end function FLIGHTGROUP:onafterAirborne(From, Event, To) self:T(self.lid..string.format("Flight airborne")) - if self.ai then + if self.isAI then self:_CheckGroupDone(1) else self:_UpdateMenu() @@ -1752,7 +1752,7 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n) --end -- Only AI flights. - if not self.ai then + if not self.isAI then allowed=false end @@ -1855,7 +1855,7 @@ end -- @param #number delay Delay in seconds. function FLIGHTGROUP:_CheckGroupDone(delay) - if self:IsAlive() and self.ai then + if self:IsAlive() and self.isAI then if delay and delay>0 then -- Delayed call. @@ -2114,7 +2114,7 @@ function FLIGHTGROUP:onafterRTB(From, Event, To, airbase, SpeedTo, SpeedHold, Sp end - if self.ai then + if self.isAI then local routeto=false if fc or world.event.S_EVENT_KILL then @@ -2294,7 +2294,7 @@ function FLIGHTGROUP:onafterHolding(From, Event, To) -- Set flight status to holding self.flightcontrol:SetFlightStatus(self, FLIGHTCONTROL.FlightStatus.HOLDING) - if not self.ai then + if not self.isAI then self:_UpdateMenu() end @@ -2641,10 +2641,10 @@ function FLIGHTGROUP:_InitGroup() self.tacan=UTILS.DeepCopy(self.tacanDefault) -- Is this purely AI? - self.ai=not self:_IsHuman(group) + self.isAI=not self:_IsHuman(group) -- Create Menu. - if not self.ai then + if not self.isAI then self.menu=self.menu or {} self.menu.atc=self.menu.atc or {} self.menu.atc.root=self.menu.atc.root or MENU_GROUP:New(self.group, "ATC") @@ -2680,7 +2680,7 @@ function FLIGHTGROUP:_InitGroup() text=text..string.format("Ceiling = %.1f feet\n", UTILS.MetersToFeet(self.ceiling)) text=text..string.format("Tanker type = %s\n", tostring(self.tankertype)) text=text..string.format("Refuel type = %s\n", tostring(self.refueltype)) - text=text..string.format("AI = %s\n", tostring(self.ai)) + text=text..string.format("AI = %s\n", tostring(self.isAI)) text=text..string.format("Helicopter = %s\n", tostring(self.group:IsHelicopter())) text=text..string.format("Elements = %d\n", #self.elements) text=text..string.format("Waypoints = %d\n", #self.waypoints) diff --git a/Moose Development/Moose/Ops/NavyGroup.lua b/Moose Development/Moose/Ops/NavyGroup.lua index 515aaf817..6c6f54d44 100644 --- a/Moose Development/Moose/Ops/NavyGroup.lua +++ b/Moose Development/Moose/Ops/NavyGroup.lua @@ -639,7 +639,7 @@ function NAVYGROUP:onafterSpawned(From, Event, To) -- Update position. self:_UpdatePosition() - if self.ai then + if self.isAI then -- Set default ROE. self:SwitchROE(self.option.ROE) @@ -1198,7 +1198,7 @@ function NAVYGROUP:_InitGroup() --self.isSubmarine=self.group:IsSubmarine() -- Ships are always AI. - self.ai=true + self.isAI=true -- Is (template) group late activated. self.isLateActivated=self.template.lateActivation diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index d9a889e0a..82c9def44 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -23,7 +23,7 @@ -- @field #boolean isLateActivated Is the group late activated. -- @field #boolean isUncontrolled Is the group uncontrolled. -- @field #table elements Table of elements, i.e. units of the group. --- @field #boolean ai If true, group is purely AI. +-- @field #boolean isAI If true, group is purely AI. -- @field #boolean isAircraft If true, group is airplane or helicopter. -- @field #boolean isNaval If true, group is ships or submarine. -- @field #boolean isGround If true, group is some ground unit. @@ -262,12 +262,18 @@ OPSGROUP.TaskType={ --- Laser and IR spot data. -- @type OPSGROUP.Spot +-- @field #boolean CheckLOS If true, check LOS to target. +-- @field #boolean IRon If true, turn IR pointer on. +-- @field #number dt Update time interval in seconds. -- @field DCS#Spot Laser Laser spot. -- @field DCS#Spot IR Infra-red spot. -- @field #number Code Laser code. --- @field Wrapper.Positionable#POSITIONABLE Target The target. +-- @field Wrapper.Group#GROUP TargetGroup The target group. +-- @field Wrapper.Positionable#POSITIONABLE TargetUnit The current target unit. -- @field Core.Point#COORDINATE Coordinate where the spot is pointing. -- @field #boolean On If true, the laser is on. +-- @field #OPSGROUP.Element element The element of the group that is lasing. +-- @field DCS#Vec3 vec3 The 3D positon vector of the laser (and IR) spot. -- @field Core.Timer#TIMER timer Spot timer. --- Ammo data. @@ -496,19 +502,42 @@ function OPSGROUP:SetDetection(Switch) return self end ---- Set detection on or off. --- If detection is on, detected targets of the group will be evaluated and FSM events triggered. +--- Set LASER parameters. -- @param #OPSGROUP self -- @param #number Code Laser code. Default 1688. +-- @param #boolean CheckLOS Check if lasing unit has line of sight to target coordinate. -- @param #boolean IROff If true, then dont switch on the additional IR pointer. -- @param #number UpdateTime Time interval in seconds the beam gets up for moving targets. Default every 0.5 sec. -- @return #OPSGROUP self -function OPSGROUP:SetLaser(Code, IROff, UpdateTime) +function OPSGROUP:SetLaser(Code, CheckLOS, IROff, UpdateTime) self.spot.Code=Code or 1688 - self.spot.IRoff=IROff + self.spot.CheckLOS=CheckLOS + self.spot.IRon=not IROff + self.spot.dt=UpdateTime or 0.5 return self end +--- Get LASER code. +-- @param #OPSGROUP self +-- @return #number Current Laser code. +function OPSGROUP:GetLaserCode() + return self.spot.Code +end + +--- Get current LASER coordinate, i.e. where the beam is pointing at if the LASER is on. +-- @param #OPSGROUP self +-- @return Core.Point#COORDINATE Current position where the LASER is pointing at. +function OPSGROUP:GetLaserCoordinate() + return self.spot.Coordinate +end + +--- Get current target of the LASER. This can be a STATIC or UNIT object. +-- @param #OPSGROUP self +-- @return Wrapper.Positionable#POSITIONABLE Current target object. +function OPSGROUP:GetLaserTarget() + return self.spot.TargetUnit +end + --- Define a SET of zones that trigger and event if the group enters or leaves any of the zones. -- @param #OPSGROUP self -- @param Core.Set#SET_ZONE CheckZonesSet Set of zones. @@ -2984,8 +3013,15 @@ function OPSGROUP:onafterLaserOn(From, Event, To, Target) if target:IsAlive() then - self.spot.Target=Target - coord=Target:GetCoordinate() + if target:IsInstanceOf("GROUP") then + self.spot.TargetGroup=target + self.spot.TargetUnit=target:GetHighestThreat() + else + self.spot.TargetUnit=target + end + + -- Current coordinate + coord=self.spot.TargetUnit:GetCoordinate() else self:E("WARNING: LASER target is not alive!") @@ -3003,8 +3039,7 @@ function OPSGROUP:onafterLaserOn(From, Event, To, Target) if element then -- Debug message. - self:T(self.lid.."Switching LASER on") - + self:I(self.lid.."Switching LASER on") -- Start timer that calls the update twice per sec. self.spot.timer:Start(nil, 0.5) @@ -3023,11 +3058,12 @@ function OPSGROUP:onafterLaserOn(From, Event, To, Target) -- Create laser and IR beams. self.spot.Laser=Spot.createLaser(DCSunit, {x=0, y=offsetY, z=0}, self.spot.vec3, self.spot.Code or 1688) - self.spot.IR=Spot.createInfraRed(DCSunit, {x=0, y=offsetY, z=0}, self.spot.vec3) + if self.spot.IRon then + self.spot.IR=Spot.createInfraRed(DCSunit, {x=0, y=offsetY, z=0}, self.spot.vec3) + end -- Laser is on. self.spot.On=true - end end @@ -3091,16 +3127,16 @@ function OPSGROUP:_UpdateLaser() --´- -- Check if we have a POSITIONABLE to lase. - if self.spot.Target then + if self.spot.TargetUnit then --- -- Lasing a possibly moving target --- - if self.spot.Target:IsAlive() then + if self.spot.TargetUnit:IsAlive() then -- Get current target position. - local vec3=self.spot.Target:GetVec3() + local vec3=self.spot.TargetUnit:GetVec3() -- Calculate distance local dist=UTILS.VecDist3D(vec3, self.spot.vec3) @@ -3116,22 +3152,39 @@ function OPSGROUP:_UpdateLaser() -- Set the new laser target point. self.spot.Laser:setPoint(vec3) - self.spot.IR:setPoint(vec3) + if self.spot.IRon then + self.spot.IR:setPoint(vec3) + end end else - -- Switch laser off. - self:T(self.lid.."Target is not alive any more ==> switching LASER off") - self:LaserOff() + if self.spot.TargetGroup and self.spot.TargetGroup:IsAlive() then + + -- Get first alive unit in the group. + local unit=self.spot.TargetGroup:GetHighestThreat() + + if unit then + self:I(self.lid.."Switching to target other target unit in the group") + self.spot.TargetUnit=unit + else + -- Switch laser off. + self:T(self.lid.."Target is not alive any more ==> switching LASER off") + self:LaserOff() + end + + else - end + -- Switch laser off. + self:T(self.lid.."Target is not alive any more ==> switching LASER off") + self:LaserOff() + + end + end end - end - end @@ -3360,7 +3413,7 @@ end -- @param #number delay Delay in seconds. function OPSGROUP:_CheckGroupDone(delay) - if self:IsAlive() and self.ai then + if self:IsAlive() and self.isAI then if delay and delay>0 then -- Delayed call. diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 34172a162..c028703ec 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -2169,6 +2169,40 @@ function GROUP:GetThreatLevel() return threatlevelMax end +--- Get the unit in the group with the highest threat level, which is still alive. +-- @param #GROUP self +-- @return Wrapper.Unit#UNIT The most dangerous unit in the group. +-- @return #number Threat level of the unit. +function GROUP:GetHighestThreat() + + -- Get units of the group. + local units=self:GetUnits() + + if units then + + local threat=nil ; local maxtl=0 + for _,_unit in pairs(units or {}) do + local unit=_unit --Wrapper.Unit#UNIT + + if unit and unit:IsAlive() then + + -- Threat level of group. + local tl=unit:GetThreatLevel() + + -- Check if greater the current threat. + if tl>maxtl then + maxtl=tl + threat=unit + end + end + end + + return threat, maxtl + end + + return nil, nil +end + --- Returns true if the first unit of the GROUP is in the air. -- @param Wrapper.Group#GROUP self