This commit is contained in:
2025-09-12 15:20:28 +08:00
commit 3257a14c32
449 changed files with 388780 additions and 0 deletions

View File

@@ -0,0 +1,510 @@
# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
// converted BRAWLER v7.5 aslct7.f and akshn7.f
// Replicates the missile fire 7,3,1,x alternative behavior
include_once BrawlerScriptUtil.txt
behavior weapon_decision_missile
script_debug_writes off
script_variables
WsfQuantumTaskerProcessor processor;
//**********************************************************************//
//** debugging parameters **//
//**********************************************************************//
bool mDrawSteering = false;
//**********************************************************************//
//** alternative parameters **//
//**********************************************************************//
// Flag used to enable/disable this alternative
// Takes the place of production rules
bool mAlternative7311Enabled = true;
// Alternative ID
int ilevel = 7;
int kalt = 3;
int icall = 1; // Weapon number, for missiles 1 - 6
int lcall = 1;
// Max/Min range for a SRM (meters)
double mMaxRange = 25000 * Math.M_PER_FT();
double mMinRange = 4000 * Math.M_PER_FT();
// Maximum angle a shot can be taken at (degrees)
double mMaxFiringAngle = 15.0;
// Percent range is reduced by for simple envelope
double mPercentRange = 0.2;
// Maximum number of missiles on a target
int mTargetSaturation = 1;
// Required track quality for a shot
double mRequiredTrackQuality = 0.8;
//**********************************************************************//
//********* VARIABLES BELOW THIS LINE ARE NOT FOR USER EDITING *********//
//**********************************************************************//
double grav = 32.17405; // From pcon.fi
end_script_variables
on_init
if (PROCESSOR.IsA_TypeOf("WSF_QUANTUM_TASKER_PROCESSOR"))
{
processor = (WsfQuantumTaskerProcessor)PROCESSOR;
}
end_on_init
// Replicates the checks done in canfirm.f
// Return true if the missile can be fired
// Sets the string to the fail reason
script bool canfirm(WsfLocalTrack target, string failMsg)
/*
cnfire = .false.
--MISSILE COMING OFF RAIL
if (lnchng) then
rsfail = 'MISL COMING OFF RAIL'
return
endif
--SWITCHOLOGY DELAYS
pswtch = (time .ge. timemf)
if (.not. pswtch)then
rsfail = 'SWITCHOLOGY'
return
endif
--CHECK IF TARGET IS IN ENVELOPE
--NOTE THAT SOME PPM... VARIABLES ARE RECALCULATED.
call mslenv_typ_mm(ppmiac,renv_typ)
call mslenv(iacid,xp(1,me),vp(1,me),ap(1,me),
1 alphap,xp(1,ppmiac),vp(1,ppmiac),ap(1,ppmiac),
2 ppmptr, rbep, rwep, ext_mle, .true., renv_typ, ppmrmn, ppmrmx,
3 ppmapt, ppmse, ppmaof, ppmenv, ppmtrk, ppmohr,l_config)
if (.not. ppmenv)then
rsfail = 'TGT NOT IN ENV'
return
endif
--Does pilot beleive that target is within max range (R<Rmax1)?
pinrng = prmax2(ppmiac,ppmrmx,1.,0.2)
pbinrg = (pinrng .gt. pr2lim)
if (.not.pbinrg)then
rsfail = 'LOW PROB. TGT IN RNG'
return
endif
if(lnchma.eq.0)then
rsfail = 'FAIL ALL FIRE MODES'
return
endif
cnfire = .true.
*/
// Not currently checking for another missile coming off the rail
// Not currently checking for switchology delays
// CHECK IF TARGET IS IN ENVELOPE
// Using a very simplified replacement of mslenv()
// that take a percentage of ange and a simple angle check
double range = PLATFORM.SlantRangeTo(target);
double absRelativeBearing = MATH.Fabs(PLATFORM.RelativeBearingTo(target));
if (range < (mMinRange + mMinRange * mPercentRange) ||
range > (mMaxRange - mMaxRange * mPercentRange) ||
absRelativeBearing >= mMaxFiringAngle )
{
#writeln("absRelativeBearing = ", absRelativeBearing, ", range = ", range);
#failMsg = "TGT NOT IN ENV";
target.SetAuxData("msg", "TGT NOT IN ENV");
return false;
}
// Does pilot beleive that target is within max range (R<Rmax1)?
// Using simplified version of prmax2
// and assuming short range missile with rmax = 25000 ft
double drng = (mMaxRange - PLATFORM.SlantRangeTo(target));
if (drng < 0.0)
{
#failMsg = "LOW PROB. TGT IN RNG";
target.SetAuxData("msg", "LOW PROB. TGT IN RNG");
return false;
}
// Not currently checking launch modes
// lnchma set if fctest() passes checks
return true;
end_script
// Replicates the checks done in shldfrm.f
// Return true if the missile should be fired
// Sets the string to the fail reason if any
script bool shldfrm(WsfLocalTrack target, string failMsg)
/*
C --CHECK THAT PILOT BELIEVES RANGE IS OK FOR TARGETING
pinrng = prmax2(ppmiac,ppmrmx,ppm_rpeak,0.2)
pbinrg = pinrng.ge.pr2lim
call pdset('PROB_IN_RANGE',pbinrg)
call mslenv_typ_mm(ppmiac,renv_typ)
C
C --CALCULATE tgleav
C --POSSIBLE PROJECTIONS
C -- ATTACKER TARGET
C --(1) CONSTANT VELOCITY XEUAN CONSTANT VELOCITY vecinc
C --(2) CURRENT MANEUVER XEUA CURRENT MANEUVER XEUT
C --(3) CURRENT MANEUVER XEUA CONSTANT VELOCITY vecinc
C --(4) CONSTANT VELOCITY XEUAN CURRENT MANEUVER XEUT
C --LOGIC IS AS FOLLOWS:
C --IF CASE (1) (neither maneuver) IS IN ENVELOPE THEN
C -- IF CASE (2) (both maneuver) IS OUT OF ENVELOPE
C -- IF CASE (3) (atkr maneuvers) IS IN ENVELOPE
C -- IF CASE(4) (tgt maneuvers) IS OUT OF ENVELOPE
C -- ASSERT: TARGET AT FAULT
C
C CASE 1: CALCULATE INENVP_CC
if (ient.eq.sament) then
call xmit3(xp(1,me),xme)
call xmit3(vp(1,me),vme)
call xmit(9,rbep,rbeme)
call xmit(9,rwep,rweme)
else
call xmit3(xeuan,xme)
call xmit3(veuan,vme)
call xmit(9,rbeuan,rbeme)
call xmit(9,rweuan,rweme)
endif
call vecinc(xp(1,ppmiac),tproj3,vp(1,ppmiac),xtgt)
call xmit3(vp(1,ppmiac),vtgt)
call zero3(azero)
xtgt(3) = amin1(xtgt(3),-50.)
call mslenv(iacid,xme,vme,azero,alphap,xtgt,vtgt,azero,
1 misl(mslpp),rbeme,rweme,.false.,.true.,renv_typ,rmin_mm,
2 rmax_mm,aimp,se_mm,aof_mm,inenvp_cc,trkbl,ovrhoz,l_config)
C --"target leaving" CANNOT BE TRUE IF NOT IN ENVELOPE WHEN NEITHER
C --MANEUVERING
if(.not.inenvp_cc)then
tgleav = .false.
goto 200
endif
C
C --CASE 2: CALCULATE INENVP_MM
if (ient.eq.sament) then
C --USE SAME AS CASE 1 SINCE I CAN'T MANEUVER
continue
else
call xmit3(xeua,xme)
call xmit3(veua,vme)
call xmit(9,rbeua,rbeme)
call xmit(9,rweua,rweme)
endif
call xmit3(xeut(1,ppmiac),xtgt)
call xmit3(veut(1,ppmiac),vtgt)
call mslenv(iacid,xme,vme,azero,alphap,xtgt,vtgt,azero,
1 misl(mslpp),rbeme,rweme,.false.,.true.,renv_typ,rmin,rmax,
2 aimp,se,aof,inenvp_mm,trkbl,ovrhoz,l_config)
C --"target leaving" CANNOT BE TRUE IF STILL IN ENV. WHEN BOTH MANEUVER
if(inenvp_mm)then
tgleav = .false.
goto 200
endif
C
C --CASE 3: CALCULATE INENVP_MC
if (ient.eq.sament) then
C --USE SAME AS CASE 1 SINCE I CAN'T MANEUVER
continue
else
call xmit3(xeua,xme)
call xmit3(veua,vme)
call xmit(9,rbeua,rbeme)
call xmit(9,rweua,rweme)
endif
call vecinc(xp(1,ppmiac),tproj3,vp(1,ppmiac),xtgt)
call xmit3(vp(1,ppmiac),vtgt)
xtgt(3) = amin1(xtgt(3),-50.)
call mslenv(iacid,xme,vme,azero,alphap,xtgt,vtgt,azero,
1 misl(mslpp),rbeme,rweme,.false.,.true.,renv_typ,rmin,rmax,
2 aimp,se,aof,inenvp_mc,trkbl,ovrhoz,l_config)
if(.not.inenvp_mc)then
tgleav = .false.
goto 200
endif
C
C --CASE 4: CALCULATE INENVP_CM
if (ient.eq.sament) then
C --USE SAME AS CASE 1 SINCE I CAN'T MANEUVER
continue
else
call xmit3(xeuan,xme)
call xmit3(veuan,vme)
call xmit(9,rbeuan,rbeme)
call xmit(9,rweuan,rweme)
endif
call xmit3(xeut(1,ppmiac),xtgt)
call xmit3(veut(1,ppmiac),vtgt)
call mslenv(iacid,xme,vme,azero,alphap,xtgt,vtgt,azero,
1 misl(mslpp),rbeme,rweme,.false.,.true.,renv_typ,rmin,rmax,aimp,
2 se,aof,inenvp_cm,trkbl,ovrhoz,l_config)
tgleav = .not.inenvp_cm
C
200 continue
call pdset('TGT_LEAVING_ENV',tgleav)
C
C --Calculate current envelope level (WORSE)
elevnow= envlvl(rngnow(me,ppmiac),rdotme(ppmiac),ppmse,
1 ppmaof,ppmrmn,ppmrmx,ppm_rpeak,ppm_semax,aoffmx,
2 ppmtrk,ppmohr,'SHOOT ')
C
if (ient.ne.sament) then
elevprj= envlvl(rng(ppmiac),rngr(ppmiac),se_mm,aof_mm,rmin_mm,
1 rmax_mm,ppm_rpeak,ppm_semax,aoffmx,trkbl,ovrhoz,'SHOOT ')
if(lprnt) write(ioutp,2000) rmin_mm,rmax_mm,
1 rng(ppmiac),aimp,se_mm,aof_mm,elevprj
else
C --rng, rngr NOT SET FOR SAM, USE rngun, rngrun
elevprj= envlvl(rngun(ppmiac),rngrun(ppmiac),se_mm,aof_mm,
1 rmin_mm,rmax_mm,ppm_rpeak,ppm_semax,aoffmx,trkbl,ovrhoz,
2 'SHOOT ')
if(lprnt) write(ioutp,2000) rmin_mm,rmax_mm,
1 rngun(ppmiac),aimp,se_mm,aof_mm,elevprj
endif
C --CHECK PROJECTION -- IS LEVEL DECREASING?
worse = (elevnow.ge.elevprj)
call pdset('SHOT_WORSENING',worse)
10 continue
C
C --Check if target is too near beam for successful semi-active
C -- missile shot
lbeam = beamsht()
call pdset('SA_BEAM_SHOT',lbeam)
C
C --If positive target ID required to fire, has ID been
C --established?
needid = (irel(ppmiac).eq.0) .and. (id_mode.ne.bvr_id_md)
call pdset('SURE_BAD_GUY',.not.needid)
C
C --check for fratricide risk
call set_hldcod(mslpp,ppmiac,hldcode,pp_skrs,pp_undes,lfrshot)
lfrat = lbit(hldcode,2)
call pdset('FRAT_RISK',lfrat)
C
C --CHECK IF FRIEND HAS A BETTER SHOT
lfrnd = lbit(hldcode,1)
call pdset('FRND_BETTER_SHOT',lfrnd)
C
C --Is target already engaged with max number of missiles/target?
other_tgtd = 0
do 100 igg=1,ngg
iacf = listf(igg)
acidf = iacidt(iacf)
if (iacid .eq. acidf)goto 100
C --Don't count another's selection if you have a much better
C --shot, since he will wait for you to shoot
if (.not.lfrshot(iacf)) goto 100
C --Don't count another's selection if you have selected the
C --same target earlier! RMK 9 Apr 92
C --(Cant use others_tgt(iacid) here since not set until akshn7)
if (others_tgt(acidf).eq.ppmiac)then
C --However, we do need to use others_tgt(iacid) here, since
C --we need to use others_msgtim(iacid), which is only correct
C --if others_tgt(iacid) .eq. ppmiac
if(others_tgt(iacid).eq.ppmiac) then
C --I have selected this tgt previously
if (others_msgtim(acidf).lt.others_msgtim(iacid)) then
C --He selected this target earlier than I, so count him
other_tgtd = other_tgtd + 1
endif
else
C --I just changed to this target, so if anybody else has
C --sent me a message selecting him, they must have gotten
C --there first
other_tgtd = other_tgtd + 1
endif
endif
100 continue
110 continue
satur = ((nmhutl(ppmiac)+other_tgtd).ge.mxtgt_ac(ppmjid))
call pdset('TARGET_SATURATED',satur)
skr_lock = .false.
do 300 iseek = 1, mx_skr
if (skr_acquired(iseek)) then
skr_lock = .true.
goto 305
endif
300 continue
305 continue
call pdset('SEEKER_LOCK',skr_lock)
C
C --CHECK WEAPON QUALITY TRACK
C --no_trk indicates track not needed for this launch mode
no_trk = (lnchma .eq. ppsli) .or.
1 (lnchma .eq. ppslr) .or.
2 (lnchma .eq. pcguv) .or.
3 (lnchma .eq. pvtnhms)
if (.not.usewqt(iflite)) then
C --Flight does not require WQT
needwqt = .false.
elseif (no_trk) then
C --Using a luanch mode that is not cued from a track
needwqt = .false.
else
needwqt = .not.wpnqual
endif
400 continue
C
C --FIRING LOGIC:
lfire =
1 .not.(needid.or.satur.or.lfrat.or.lfrnd.or.lbeam.or.needwqt)
2 .and.(pbinrg.or.(worse.and..not.tgleav))
if(lfire)then
rsfail = ' '
else
if(needid)then
rsfail = 'NEED ID'
elseif(satur)then
rsfail = 'MXTGT_AC LIMIT'
elseif(lfrat)then
rsfail = 'FRATRICIDE RISK'
elseif(lfrnd)then
rsfail = 'FRND HAS BETTER SHOT'
elseif(lbeam)then
rsfail = 'TGT TOO NEAR BEAM'
elseif(.not.(pbinrg.or.(worse.and..not.tgleav)))then
rsfail = 'FAILED ENV LOGIC'
elseif (needwqt) then
rsfail = 'NO WEAPON QUAL TRK'
else
call nabort('SHLDFRM..unknown failure reason')
endif
endif
*/
// ONLY Checking target stauration and track quality for now
if (PLATFORM.WeaponsActiveFor(target.TrackId()) >= mTargetSaturation)
{
//lfire = true;
writeln_d(" ", PLATFORM.Name(), " shouldn't fire ", target.TargetName(), " saturated");
failMsg = "MXTGT_AC LIMIT";
return false;
}
if (target.TrackQuality() < mRequiredTrackQuality)
{
failMsg = "NO WEAPON QUAL TRK";
return false;
}
return true;
end_script
precondition
#writeln_d(PLATFORM.Name(), " precondition weapon_decision_missile, T=", TIME_NOW);
### Evaluate conditions that would prevent behavior alternative from running
if (!PROCESSOR.IsA_TypeOf("WSF_QUANTUM_TASKER_PROCESSOR"))
{
writeln_d("not a quantum tasker!");
return Failure("behavior not attached to a WSF_QUANTUM_TASKER_PROCESSOR");
}
// aslct7.f line 123 - 132
# --CHECK IF TARGET SELECTED
# if (ppmiac .eq. 0 .and. .not.dewvmsl)then
# rsfail = 'NO TARGET SELECTED'
# goto 800
# endif
# --CHECK IF WEAPON SELECTED
# if (ppmptr .eq. 0)then
# rsfail = 'NO WEAPON SELECTED'
# goto 800
# endif
WsfTaskList tasks = processor.TasksReceivedOfType("WEAPON");
if(tasks.Count() <= 0)
{
return Failure("no tasks");
}
// Assuming 1v1 and first and only task is the one we want
WsfLocalTrack targetTrack = PLATFORM.MasterTrackList().FindTrack(tasks.Entry(0).LocalTrackId());
if(tasks.Count() <= 0 || targetTrack.IsNull() || !targetTrack.IsValid())
{
writeln_d(" ", PLATFORM.Name(), " no target selected at time: ", TIME_NOW);
return Failure("no target selected");
}
// Weapon selection done in selwpn.f (called from aslct2.f)
// checks weapon inventory. Use a similar check here as a replacement
if (!PLATFORM.Weapon("srm").IsValid() || PLATFORM.Weapon("srm").QuantityRemaining() <= 0)
{
writeln_d(" ", PLATFORM.Name(), " no weapon selected at time: ", TIME_NOW);
return Failure("no weapon selected");
}
// aslct7() calls canfir().
// canfir.f checks production rules and GCI inhibit
// just doing a simple flag for now
if (!mAlternative7311Enabled)
{
writeln_d("behavior not enabled!");
return Failure("behavior alternative not enabled");
}
//canfir.f calls canfirm()
string msg = "";
if (!canfirm(targetTrack, msg))
{
msg = targetTrack.AuxDataString("msg");
writeln_d(" ", PLATFORM.Name(), " couldn't fire at time: ", TIME_NOW, " ", msg);
return Failure(msg);
}
// aslct7 line 199 - 205
// if undamaged calls shldfr().
// if we are damaged skip checks and fire now
if (PLATFORM.DamageFactor() <= 0.0)
{
// shldfr.f just calls the specific weapon type
if (!shldfrm(targetTrack, msg))
{
writeln_d(" ", PLATFORM.Name(), " shouldn't fire at time: ", TIME_NOW, " ", msg);
return Failure(msg);
}
}
// aslct7 creates and alternative to evaluate.
// The alternative has no projection and always
// evaluates to 1, so skip that processing
// All conditions pass, weapon can fire
return true;
end_precondition
execute
// Replicates akshn7.f
// We don't need to do all the bookeeping that BRAWLER
// does. Just launch the weapon.
WsfTaskList tasks = processor.TasksReceivedOfType("WEAPON");
// Assuming 1v1 and first and only task is the one we want
WsfLocalTrack targetTrack = PLATFORM.MasterTrackList().FindTrack(tasks.Entry(0).LocalTrackId());
//Assuming weapon name, checked in precondition
WsfWeapon weapon = PLATFORM.Weapon("srm");
bool launched = weapon.FireSalvo(targetTrack, 1); // Always firing one for now
if (!launched)
{
writeln_d(" ", PLATFORM.Name(), " could NOT fire at track: ", targetTrack.TargetName(), " at time: ", TIME_NOW);
}
end_execute
end_behavior