Reduce Revenant's homing missile chance?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
Cabo_Fiambre
Posts: 54
Joined: Thu Aug 30, 2018 5:00 pm

Reduce Revenant's homing missile chance?

Post by Cabo_Fiambre »

I'm working on a project that modifies enemies attacks and the revenant has been modified to shoot two rockets instead of one to match the sprite but i've encountered that the chance of homing missiles is too high and it makes fighting them very frustrating. While i was investigating the matter i've found the function that manages the homing part. The thing is that i don't know exactly where to modify the code and i don't want to mess up. Can someone give me a hand with this and explain me how this code works?

I would really appreciate any help given! Thanks!

Code: Select all

void A_Tracer()
{
		// killough 1/18/98: this is why some missiles do not have smoke
		// and some do. Also, internal demos start at random gametics, thus
		// the bug in which revenants cause internal demos to go out of sync.
		//
		// killough 3/6/98: fix revenant internal demo bug by subtracting
		// levelstarttic from gametic:
		//
		// [RH] level.time is always 0-based, so nothing special to do here.

		if (level.time & 3)	return;
	
		// spawn a puff of smoke behind the rocket
		SpawnPuff ("BulletPuff", pos, angle, angle, 3);
		Actor smoke = Spawn ("RevenantTracerSmoke", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE);
	
		smoke.Vel.Z = 1.;
		smoke.tics -= random[Tracer](0, 3);
		if (smoke.tics < 1)
			smoke.tics = 1;

		// The rest of this function was identical with Strife's version, except for the angle being used.
		A_Tracer2(16.875);
Jarewill
 
 
Posts: 1853
Joined: Sun Jul 21, 2019 8:54 am

Re: Reduce Revenant's homing missile chance?

Post by Jarewill »

The only line needed to lower the chances of a tracer spawning is this one:

Code: Select all

if (level.time & 3)   return;
I'm not entirely sure what this means, because I'm really not experienced with this operator, but increasing the number from 3 to 5 seemed to make the tracers spawn less than usual.

Alternatively you can create 2 missile actors, one tracer and one non-tracer, and fire them separately from the Revenant's missile state.
A_Jump can be used to make random jumps, so it can jump to a tracer-firing state instead of normal-firing one with a chance.
User avatar
Rachael
Posts: 13960
Joined: Tue Jan 13, 2004 1:31 pm
Preferred Pronouns: She/Her
Contact:

Re: Reduce Revenant's homing missile chance?

Post by Rachael »

I think a non-source modification here would be far more desirable than having to alter the source directly. If you change the source then you are effectively locked to that version, for better or worse, and that can cause problems if operating systems continue to evolve to a point where today's version may no longer work.

GZDoom has the flexibility to do what you need from a modding standpoint, so modifying the source directly should be unnecessary. You will have to rewrite the homing fireball actor to accomplish it, but it's quite doable.
User avatar
Xtyfe
Posts: 1490
Joined: Fri Dec 14, 2007 6:29 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 11
Graphics Processor: nVidia with Vulkan support

Re: Reduce Revenant's homing missile chance?

Post by Xtyfe »

I might be able to chime in with something. What you're trying to achieve here is quite a bit similar to something I have done recently and I figured I'd share this.
Most of this code is not mine and came from help in another post viewtopic.php?f=122&t=70826

The Revenant fires an invisible projectile that fires the two missiles instead. The purpose of the invisible projectile is to keep both missiles in sync with each other. I found through play that this code made the Revenant way too aggressive and instead of going back to the vanilla A_Tracer function, I'd just make sure only one instance of seeker missiles was ever spawned at once. I modified the code to choose between a seeking and non-seeking variant. The seeking variant will tell the Revenant that it exists or has been destroyed. If a seeker missile exists, the Revenant will fire non-seeking missiles, if it has been destroyed, the Revenant will be free to fire seeking missiles again.

This code could be modified to allow a more chance-based method instead by using jump functions if desired.

Code: Select all

Class XtRevenant : Actor Replaces Revenant
{
	Default
	{
		Health 300;
		Radius 20;
		Height 56;
		Mass 200;
		Speed 10;
		PainChance 100;
		MeleeThreshold 196;
		BloodColor "820000";
		Species "Revenant";
		SeeSound "skeleton/sight";
		PainSound "skeleton/pain";
		DeathSound "skeleton/death";
		ActiveSound "skeleton/active";
		HitObituary "$OB_UNDEADHIT";
		Obituary "$OB_UNDEAD";
		Tag "$FN_REVEN";
		+FLOORCLIP
	}
	
	int missile_count;
	
	States
	{
	Spawn:
		SKEL AB 10 NoDelay A_Look ();
		Loop;
	See:
		SKEL AABBCCDDEEFF 2 A_Chase ();
		Loop;
	Melee:
		SKEL G 5
			{
				A_FaceTarget ();
				A_StartSound ("skeleton/swing", CHAN_WEAPON);
			}
		SKEL H 5 A_FaceTarget ();
		SKEL I 10 A_CustomMeleeAttack (Random (1, 10)*5, "skeleton/melee", "", "Melee", 1);
		Goto See;
	Missile:
		SKEL J 10 A_FaceTarget ();
		SKEL J 10 Bright
			{
				if (missile_count == 0)
				{
					A_SpawnProjectile ('XtRevenantTracerTracker', 60);
				}
				else if (missile_count >= 1)
				{
					A_SpawnProjectile ('XtRevenantTracerTrackerNoSeek', 60);
				}
			}
		SKEL K 10 A_FaceTarget ();
		Goto See;
	Pain:
		SKEL L 3;
		SKEL L 3 A_Pain;
		Goto See;
	Death:
		SKEL LM 5;
		SKEL N 5 A_Scream;
		SKEL O 5 A_NoBlocking;
		SKEL P 5;
		SKEL Q -1;
		Stop;
	Raise:
		SKEL QPONML 5;
		Goto See;
	}
}

Class XtRevenantTracerTracker : Actor
{
    XtRevenantTracer t1, t2;

    Default
    {
        Radius 1;
        Height 1;
        Projectile;
        Speed 10;
        +NOINTERACTION;
        +SEEKERMISSILE;
    }
	
    override void PostBeginPlay()
    {
        Super.PostBeginPlay();

        t1 = XtRevenantTracer (A_SpawnProjectile ('XtRevenantTracer', -1, -19, flags: CMF_TRACKOWNER));
        t2 = XtRevenantTracer (A_SpawnProjectile ('XtRevenantTracer', 1, 14, flags: CMF_TRACKOWNER));
	   
        bool ok = Tracer != null && t1 != null && t2 != null;

        // Set initial velocities

        double ang = Tracer != null ? AngleTo(Tracer, true) : Angle;

        if (t1 != null)
        {
            t1.Angle = ang;           
            t1.Vel.Z = Vel.Z;
            t1.VelFromAngle();
        }

        if (t2 != null)
        {
            t2.Angle = ang;
            t2.Vel.Z = Vel.Z;
            t2.VelFromAngle();
        }

        if (ok) // both missiles present and have tracer
        {
            t1.tracker = t2.tracker = self;
        }
        else
        {
			Destroy();
			return;
        }
    }

    override void Tick()
    {
        Super.Tick();

        if (t1 != null && t1.Tracer == Tracer && t2 != null && t2.Tracer == Tracer)
        {
            // Adjust the velocities of the tracked missiles
            // to match the velocity of this actor.
            t1.Angle = t2.Angle = Angle;
            t1.Vel = t2.Vel = Vel;
        }
        else
        {
			Destroy();
			return;
        }
    }
	
	States
    {
        Spawn:
            TNT1 A 4
				{
					XtRevenantTracer.DoSeek(self);
				}
            Loop;
    }
}

Class XtRevenantTracer : Actor
{

    XtRevenantTracerTracker tracker;

	Default
	{
		Radius 11;
		Height 8;
		Scale 0.5;
		Speed 10;
		MaxTargetRange 16;
		DamageFunction (Random(1, 8)*5);
		DamageType "Ballistic";
		Projectile;
		SeeSound "skeleton/attack";
		DeathSound "skeleton/tracex";
		RenderStyle "Add";
		Decal "RevenantScorch";
		+FORCEXYBILLBOARD
		+NOFORWARDFALL
		+SEEKERMISSILE
		+RANDOMIZE
		+ZDOOMTRANS
	}
	
	static void DoSeek(Actor source)
    {
        source.A_SeekerMissile (10, 30, SMF_LOOK | SMF_PRECISE, 64, 16);
    }
   
	override void PostBeginPlay()
    {
        Super.PostBeginPlay();

		let revmaster = XtRevenant(target);
		if (revmaster)
		{
			revmaster.missile_count += 1;
		}
    }
   
	override void OnDestroy()
	{
		let revmaster = XtRevenant(target);
		if (revmaster)
		{
			revmaster.missile_count -= 1;
		}
	}
   
    void A_XtRevenantTracerInFlight()
    {
        A_SpawnItemEx ('BulletPuff', 0, 0, 0, 0, 0, 0, 0, SXF_ORIGINATOR, 0, 0);
		
        if (GetAge() > 0 && (tracker == null || Tracer != tracker.Tracer))
        {
            DoSeek(self);
        }
    }
	
    States
    {
        Spawn:
            FATB AB 4 NoDelay Bright A_XtRevenantTracerInFlight ();
            Loop;
        Death:
            FBXP ABC 4 Bright;
            Stop;
    }
}

Class XtRevenantTracerTrackerNoSeek : Actor
{
    XtRevenantTracerNoSeek t1, t2;

    Default
    {
        Radius 1;
        Height 1;
        Projectile;
        Speed 10;
        +NOINTERACTION;
    }
	
    override void PostBeginPlay()
    {
        Super.PostBeginPlay();

        t1 = XtRevenantTracerNoSeek (A_SpawnProjectile ('XtRevenantTracerNoSeek', -1, -19, flags: CMF_TRACKOWNER));
        t2 = XtRevenantTracerNoSeek (A_SpawnProjectile ('XtRevenantTracerNoSeek', 1, 14, flags: CMF_TRACKOWNER));
	   
        bool ok = Tracer != null && t1 != null && t2 != null;

        // Set initial velocities

        double ang = Tracer != null ? AngleTo(Tracer, true) : Angle;

        if (t1 != null)
        {
            t1.Angle = ang;           
            t1.Vel.Z = Vel.Z;
            t1.VelFromAngle();
        }

        if (t2 != null)
        {
            t2.Angle = ang;
            t2.Vel.Z = Vel.Z;
            t2.VelFromAngle();
        }

        if (ok) // both missiles present and have tracer
        {
            t1.tracker = t2.tracker = self;
        }
        else
        {
			Destroy();
			return;
        }
    }

    override void Tick()
    {
        Super.Tick();

        if (t1 != null && t1.Tracer == Tracer && t2 != null && t2.Tracer == Tracer)
        {
            // Adjust the velocities of the tracked missiles
            // to match the velocity of this actor.
            t1.Angle = t2.Angle = Angle;
            t1.Vel = t2.Vel = Vel;
        }
        else
        {
			Destroy();
			return;
        }
    }
	
	States
    {
        Spawn:
            TNT1 A 4;
            Loop;
    }
}

Class XtRevenantTracerNoSeek : Actor
{

    XtRevenantTracerTrackerNoSeek tracker;

	Default
	{
		Radius 11;
		Height 8;
		Scale 0.5;
		Speed 10;
		MaxTargetRange 16;
		DamageFunction (Random(1, 8)*5);
		DamageType "Ballistic";
		Projectile;
		SeeSound "skeleton/attack";
		DeathSound "skeleton/tracex";
		RenderStyle "Add";
		Decal "RevenantScorch";
		+FORCEXYBILLBOARD
		+NOFORWARDFALL
		+RANDOMIZE
		+ZDOOMTRANS
	}	
    States
    {
        Spawn:
            FATB AB 4 NoDelay Bright A_SpawnItemEx ('BulletPuff', 0, 0, 0, 0, 0, 0, 0, SXF_ORIGINATOR, 0, 0);
            Loop;
        Death:
            FBXP ABC 4 Bright;
            Stop;
    }
}
User avatar
Snarboo
Posts: 2599
Joined: Tue Nov 29, 2005 4:37 am

Re: Reduce Revenant's homing missile chance?

Post by Snarboo »

I'm not sure which implementation you're using, but according to the wiki article on [wiki]A_Tracer[/wiki], you can adjust the homing frequency by changing how often A_Tracer is called. A_Tracer always fires homing missiles in multiples of 4 gametics, but there's also the more generic [wiki]A_SeekerMissile[/wiki] if want to manually adjust the chance for a homing missile. Apologies if this is not what you're looking for, I admit I'm not sure what sort of seeking behavior you'd like!

Edit:
If your goal is to only have one missile seek at a time rather than both at the same time, you could offset the firing order for each rocket by 1 tic. Otherwise, the solution suggested by Xtyfe above might be your best bet.
Post Reply

Return to “Scripting”