diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 8509928fb..3c370915f 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -216,7 +216,7 @@ -- One way to determin which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}(). -- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file. -- --- ## Empoying Selected Weapons +-- ## Employing Selected Weapons -- -- If an ARTY group carries multiple weapons, which can be used for artillery task, a certain weapon type can be selected to attack the target. -- This is done via the *weapontype* parameter of the @{#ARTY.AssignTargetCoord}(..., *weapontype*, ...) function. @@ -674,11 +674,13 @@ ARTY.id="ARTY | " --- Arty script version. -- @field #string version -ARTY.version="1.0.6" +ARTY.version="1.0.7" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list: +-- TODO: Add hit event and make the arty group relocate. +-- TODO: Handle rearming for ships. How? -- DONE: Delete targets from queue user function. -- DONE: Delete entire target queue user function. -- DONE: Add weapon types. Done but needs improvements. @@ -697,11 +699,9 @@ ARTY.version="1.0.6" -- DONE: Add command move to make arty group move. -- DONE: remove schedulers for status event. -- DONE: Improve handling of special weapons. When winchester if using selected weapons? --- TODO: Handle rearming for ships. How? -- DONE: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location. -- DONE: Add set commands via markers. E.g. set rearming place. -- DONE: Test stationary types like mortas ==> rearming etc. --- TODO: Add hit event and make the arty group relocate. -- DONE: Add illumination and smoke. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -4253,101 +4253,116 @@ end -- @param #ARTY self function ARTY:_CheckTargetsInRange() + local targets2delete={} + for i=1,#self.targets do local _target=self.targets[i] self:T3(ARTY.id..string.format("Before: Target %s - in range = %s", _target.name, tostring(_target.inrange))) -- Check if target is in range. - local _inrange,_toofar,_tooclose=self:_TargetInRange(_target) + local _inrange,_toofar,_tooclose,_remove=self:_TargetInRange(_target) self:T3(ARTY.id..string.format("Inbetw: Target %s - in range = %s, toofar = %s, tooclose = %s", _target.name, tostring(_target.inrange), tostring(_toofar), tostring(_tooclose))) - -- Init default for assigning moves into range. - local _movetowards=false - local _moveaway=false + if _remove then - if _target.inrange==nil then - - -- First time the check is performed. We call the function again and send a message. - _target.inrange,_toofar,_tooclose=self:_TargetInRange(_target, self.report or self.Debug) + -- The ARTY group is immobile and not cargo but the target is not in range! + table.insert(targets2delete, _target.name) - -- Send group towards/away from target. - if _toofar then - _movetowards=true - elseif _tooclose then - _moveaway=true - end + else - elseif _target.inrange==true then - - -- Target was in range at previous check... - - if _toofar then --...but is now too far away. - _movetowards=true - elseif _tooclose then --...but is now too close. - _moveaway=true - end - - elseif _target.inrange==false then - - -- Target was out of range at previous check. + -- Init default for assigning moves into range. + local _movetowards=false + local _moveaway=false - if _inrange then - -- Inform coalition that target is now in range. - local text=string.format("%s, target %s is now in range.", self.alias, _target.name) - self:T(ARTY.id..text) - MESSAGE:New(text,10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) - end - - end - - -- Assign a relocation command so that the unit will be in range of the requested target. - if self.autorelocate and (_movetowards or _moveaway) then - - -- Get current position. - local _from=self.Controllable:GetCoordinate() - local _dist=_from:Get2DDistance(_target.coord) + if _target.inrange==nil then - if _dist<=self.autorelocatemaxdist then - - local _tocoord --Core.Point#COORDINATE - local _name="" - local _safetymargin=500 - - if _movetowards then + -- First time the check is performed. We call the function again and send a message. + _target.inrange,_toofar,_tooclose=self:_TargetInRange(_target, self.report or self.Debug) - -- Target was in range on previous check but now we are too far away. - local _waytogo=_dist-self.maxrange+_safetymargin - local _heading=self:_GetHeading(_from,_target.coord) - _tocoord=_from:Translate(_waytogo, _heading) - _name=string.format("%s, relocation to within max firing range of target %s", self.alias, _target.name) - - elseif _moveaway then - - -- Target was in range on previous check but now we are too far away. - local _waytogo=_dist-self.minrange+_safetymargin - local _heading=self:_GetHeading(_target.coord,_from) - _tocoord=_from:Translate(_waytogo, _heading) - _name=string.format("%s, relocation to within min firing range of target %s", self.alias, _target.name) - + -- Send group towards/away from target. + if _toofar then + _movetowards=true + elseif _tooclose then + _moveaway=true end - - -- Send info message. - MESSAGE:New(_name.." assigned.", 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) - - -- Assign relocation move. - self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true) + + elseif _target.inrange==true then + + -- Target was in range at previous check... + + if _toofar then --...but is now too far away. + _movetowards=true + elseif _tooclose then --...but is now too close. + _moveaway=true + end + + elseif _target.inrange==false then + + -- Target was out of range at previous check. + if _inrange then + -- Inform coalition that target is now in range. + local text=string.format("%s, target %s is now in range.", self.alias, _target.name) + self:T(ARTY.id..text) + MESSAGE:New(text,10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + end + end + + -- Assign a relocation command so that the unit will be in range of the requested target. + if self.autorelocate and (_movetowards or _moveaway) then + + -- Get current position. + local _from=self.Controllable:GetCoordinate() + local _dist=_from:Get2DDistance(_target.coord) + + if _dist<=self.autorelocatemaxdist then + + local _tocoord --Core.Point#COORDINATE + local _name="" + local _safetymargin=500 + + if _movetowards then + + -- Target was in range on previous check but now we are too far away. + local _waytogo=_dist-self.maxrange+_safetymargin + local _heading=self:_GetHeading(_from,_target.coord) + _tocoord=_from:Translate(_waytogo, _heading) + _name=string.format("%s, relocation to within max firing range of target %s", self.alias, _target.name) + elseif _moveaway then + + -- Target was in range on previous check but now we are too far away. + local _waytogo=_dist-self.minrange+_safetymargin + local _heading=self:_GetHeading(_target.coord,_from) + _tocoord=_from:Translate(_waytogo, _heading) + _name=string.format("%s, relocation to within min firing range of target %s", self.alias, _target.name) + + end + + -- Send info message. + MESSAGE:New(_name.." assigned.", 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug) + + -- Assign relocation move. + self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true) + + end + + end + + -- Update value. + _target.inrange=_inrange + + self:T3(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange))) end - - -- Update value. - _target.inrange=_inrange - - self:T3(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange))) - end + + -- Remove targets not in range. + for _,targetname in pairs(targets2delete) do + self:RemoveTarget(targetname) + end + end --- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times. @@ -4728,6 +4743,7 @@ end -- @return #boolean True if target is in range, false otherwise. -- @return #boolean True if ARTY group is too far away from the target, i.e. distance > max firing range. -- @return #boolean True if ARTY group is too close to the target, i.e. distance < min finring range. +-- @return #boolean True if target should be removed since ARTY group is immobile and not cargo. function ARTY:_TargetInRange(target, message) self:F3(target) @@ -4763,11 +4779,13 @@ function ARTY:_TargetInRange(target, message) end -- Remove target if ARTY group cannot move, e.g. Mortas. No chance to be ever in range - unless they are cargo. + local _remove=false if not (self.ismobile or self.iscargo) and _inrange==false then - self:RemoveTarget(target.name) + --self:RemoveTarget(target.name) + _remove=true end - return _inrange,_toofar,_tooclose + return _inrange,_toofar,_tooclose,_remove end --- Get the weapon type name, which should be used to attack the target. diff --git a/Moose Development/Moose/Functional/CarrierTrainer.lua b/Moose Development/Moose/Functional/CarrierTrainer.lua index d9607ebcb..f44b7d2c7 100644 --- a/Moose Development/Moose/Functional/CarrierTrainer.lua +++ b/Moose Development/Moose/Functional/CarrierTrainer.lua @@ -125,6 +125,7 @@ CARRIERTRAINER.Difficulty={ --- Checkpoint parameters triggering the next step in the pattern. -- @type CARRIERTRAINER.Checkpoint +-- @field #string name Name of checkpoint. -- @field #number Xmin Minimum allowed longitual distance to carrier. -- @field #number Xmax Maximum allowed longitual distance to carrier. -- @field #number Zmin Minimum allowed latitudal distance to carrier. @@ -317,7 +318,7 @@ function CARRIERTRAINER:_InitNewPlayer(unitname) playerData.unit = UNIT:FindByName(unitname) playerData.client = CLIENT:FindByName(playerData.unit.UnitName, nil, true) playerData.callsign = playerData.unit:GetCallsign() - playerData.totalScore = 0 + playerData.totalscore = 0 playerData.passes = 0 playerData.collectedResultString = "" @@ -364,11 +365,6 @@ end -- @param Wrapper.Unit#UNIT unit Player unit. -- @return #number Relative heading in degrees. function CARRIERTRAINER:_GetRelativeHeading(unit) - --local a=self.carrier:GetVec3() - --local b=unit:GetVec3() - --local c={x=b.x-a.x, y=0, z=b.z-a.z} - --local headingCarrier=self.carrier:GetHeading() - --local headingPlayer=unit:GetHeading() local vC=self.carrier:GetOrientationX() local vP=unit:GetOrientationX() @@ -395,7 +391,7 @@ function CARRIERTRAINER:_CheckPlayerStatus() if unit:IsAlive() then - self:_SendMessageToPlayer("current step "..self:_StepName(playerData.step),1,playerData) + --self:_SendMessageToPlayer("current step "..self:_StepName(playerData.step),1,playerData) --self:_DetailedPlayerStatus(playerData) if unit:IsInZone(self.giantZone) then @@ -437,36 +433,6 @@ function CARRIERTRAINER:_CheckPlayerStatus() end - - ---- Check limits for reaching next step. --- @param #CARRIERTRAINER self --- @param #number X X position of player unit. --- @param #number Z Z position of player unit. --- @param #CARRIERTRAINER.Checkpoint check Checkpoint. --- @return #boolean If true, checkpoint condition for next step was reached. -function CARRIERTRAINER:_CheckLimits(X, Z, check) - - local next=true - if check.LimitXmin and Xcheck.LimitXmax then - next=false - elseif check.LimitZmin and Zcheck.LimitZmax then - next=false - end - - self:E({X=X, Z=Z, check=check}) - - local text=string.format("next=%s : X=%d Xmin=%s Xmax=%s ||| Z=%d Zmin=%s Zmax=%s", - tostring(next), X, tostring(check.LimitXmin), tostring(check.LimitXmax), Z, tostring(check.LimitZmin), tostring(check.LimitZmax)) - MESSAGE:New(text,1):ToAllIf(self.Debug) - - return next -end - --- Get name of the current pattern step. -- @param #CARRIERTRAINER self -- @param #number step Step @@ -600,7 +566,9 @@ function CARRIERTRAINER:_AbortPattern(playerData, X, Z, posData) self:_SendMessageToPlayer(toofartext.." Abort approach!", 15, playerData ) - MESSAGE:New(string.format("Abort: X=%d Xmin=%s, Xmax=%s | Z=%d Zmin=%s Zmax=%s", X, tostring(posData.Xmin), tostring(posData.Xmax), Z, tostring(posData.Zmin), tostring(posData.Zmax)), 60):ToAllIf(self.Debug) + local text=string.format("Abort: X=%d Xmin=%s, Xmax=%s | Z=%d Zmin=%s Zmax=%s", X, tostring(posData.Xmin), tostring(posData.Xmax), Z, tostring(posData.Zmin), tostring(posData.Zmax)) + self:E(self.lid..text) + MESSAGE:New(text, 60):ToAllIf(self.Debug) self:_AddToSummary(playerData, "Approach aborted.") @@ -658,9 +626,10 @@ end function CARRIERTRAINER:_InitStennis() -- Upwind leg + self.Upwind.name="Upwind" self.Upwind.Xmin=-4000 -- TODO Should be withing 4 km behind carrier. Why? self.Upwind.Xmax=nil - self.Upwind.Zmin=-1200 + self.Upwind.Zmin=0 self.Upwind.Zmax=1200 self.Upwind.LimitXmin=0 self.Upwind.LimitXmax=nil @@ -671,11 +640,12 @@ function CARRIERTRAINER:_InitStennis() self.Upwind.Distance=nil -- Early break + self.BreakEarly.name="Early Break" self.BreakEarly.Xmin=-500 self.BreakEarly.Xmax=nil self.BreakEarly.Zmin=-3700 self.BreakEarly.Zmax=1500 - self.BreakEarly.LimitXmin=nil + self.BreakEarly.LimitXmin=0 self.BreakEarly.LimitXmax=nil self.BreakEarly.LimitZmin=-370 --0.2 NM self.BreakEarly.LimitZmax=nil @@ -684,32 +654,35 @@ function CARRIERTRAINER:_InitStennis() self.BreakEarly.Distance=nil -- Late break + self.BreakLate.name="Late Break" self.BreakLate.Xmin=-500 self.BreakLate.Xmax=nil self.BreakLate.Zmin=-3700 self.BreakLate.Zmax=1500 - self.BreakLate.LimitXmin=nil - self.BreakLate.LimitXmax=nil + self.BreakLate.LimitXmin=0 + self.BreakLate.LimitXmax=10000 self.BreakLate.LimitZmin=-1470 --0.8 NM - self.BreakLate.LimitZmax=nil + self.BreakLate.LimitZmax=10000 self.BreakLate.Altitude=UTILS.FeetToMeters(800) self.BreakLate.AoA=8.1 self.BreakLate.Distance=nil -- Abeam position + self.Abeam.name="Abeam Position" self.Abeam.Xmin=nil self.Abeam.Xmax=nil self.Abeam.Zmin=-3700 self.Abeam.Zmax=-1000 self.Abeam.LimitXmin=-200 - self.Abeam.LimitXmax=nil - self.Abeam.LimitZmin=nil - self.Abeam.LimitZmax=nil + self.Abeam.LimitXmax=10000 + self.Abeam.LimitZmin=0 + self.Abeam.LimitZmax=10000 self.Abeam.Altitude=UTILS.FeetToMeters(600) self.Abeam.AoA=8.1 self.Abeam.Distance=nil -- At the ninety + self.Ninety.name="Ninety" self.Ninety.Xmin=-3700 self.Ninety.Xmax=0 self.Ninety.Zmin=-3700 @@ -723,6 +696,7 @@ function CARRIERTRAINER:_InitStennis() self.Abeam.Distance=nil -- Wake position + self.Wake.name="Wake" self.Wake.Xmin=-4000 self.Wake.Xmax=0 self.Wake.Zmin=-2000 @@ -736,10 +710,12 @@ function CARRIERTRAINER:_InitStennis() self.Wake.Distance=nil -- In the groove + self.Groove.name="Groove" self.Groove.Xmin=-4000 self.Groove.Xmax=100 -- Landing trap + self.Trap.name="Trap" self.Trap.Xmin=-3000 self.Trap.Xmax=nil self.Trap.Zmin=-2000 @@ -749,6 +725,50 @@ function CARRIERTRAINER:_InitStennis() end +--- Check limits for reaching next step. +-- @param #CARRIERTRAINER self +-- @param #number X X position of player unit. +-- @param #number Z Z position of player unit. +-- @param #CARRIERTRAINER.Checkpoint check Checkpoint. +-- @return #boolean If true, checkpoint condition for next step was reached. +function CARRIERTRAINER:_CheckLimits(X, Z, check) + + --[[ + local next=true + if check.LimitXmin and Xcheck.LimitXmax then + next=false + elseif check.LimitZmin and Zcheck.LimitZmax then + next=false + end + + + local next = ((check.LimitXmin and math.abs(X)>=math.abs(check.LimitXmin)) or check.LimitXmin==nil) and + ((check.LimitXmax and math.abs(X)<=math.abs(check.LimitXmax)) or check.LimitXmax==nil) and + ((check.LimitZmin and math.abs(Z)>=math.abs(check.LimitZmin)) or check.LimitZmin==nil) and + ((check.LimitZmax and math.abs(Z)<=math.abs(check.LimitZmax)) or check.LimitZmax==nil) + ]] + + local nextXmin=check.LimitXmin==nil or (check.LimitXmin and (check.LimitXmin<0 and X<=check.LimitXmin or check.LimitXmin>=0 and X>=check.LimitXmin)) + local nextXmax=check.LimitXmax==nil or (check.LimitXmax and (check.LimitXmax<0 and X>=check.LimitXmax or check.LimitXmax>=0 and X<=check.LimitXmax)) + local nextZmin=check.LimitZmin==nil or (check.LimitZmin and (check.LimitZmin<0 and Z<=check.LimitZmin or check.LimitZmin>=0 and Z>=check.LimitZmin)) + local nextZmax=check.LimitZmax==nil or (check.LimitZmax and (check.LimitZmax<0 and Z>=check.LimitZmax or check.LimitZmax>=0 and Z<=check.LimitZmax)) + + local next=nextXmin and nextXmax and nextZmin and nextZmax + + --self:E({next=next, X=X, Z=Z, check=check}) + + local text=string.format("step=%s: next=%s: X=%d Xmin=%s Xmax=%s ||| Z=%d Zmin=%s Zmax=%s", + check.name, tostring(next), X, tostring(check.LimitXmin), tostring(check.LimitXmax), Z, tostring(check.LimitZmin), tostring(check.LimitZmax)) + self:E(self.lid..text) + MESSAGE:New(text,1):ToAllIf(self.Debug) + + return next +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- CARRIER TRAINING functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1325,16 +1345,18 @@ function CARRIERTRAINER:_AltitudeCheck(playerData, checkpoint, altitude) local score local hint local steptext=self:_StepName(playerData.step) + + if _error>badscore then score = -10 hint = string.format("You're high %s. ", steptext) elseif _error>lowscore then score = -5 hint = string.format("You're slightly high %s. ", steptext) - elseif _errorlowscore then score = -5 hint = string.format("You're slightly too far from the boat.") - elseif _errorlowscore then --Slightly slow score = -5 hint = "You're slightly slow." - elseif _error