Jump to content
  • 0

DeHacked monster chases, but only attacks when attacked.


Scypek2

Question

I made two dehacked monsters. One replaces the hell knight, but functions pretty much like the zombieman. The other one replaces the revenant, and functions pretty much like the shotgun guy. The two enemies are extremely similar, their states are laid out pretty much identically aside from the attack sequence (which, by itself, works just right for both enemies), their thing properties are very similar too.

 

Which is why it's so baffling that the quasi-zombieman works perfectly in every way, but the quasi-shotgunner never ever tries to attack on its own, despite noticing the player and chasing them just fine, and only attacks when hurt by the player (only one attack, then goes right back to harmlessly chasing).

 

Is this some hardcoded gimmick specific to the Revenant? That's the only hypothesis I have at this point, but why would it make an enemy so non-aggressive?

Share this post


Link to post

3 answers to this question

Recommended Posts

  • 1

The revenant has special coding that makes it prefer to close in for a melee attack when near enough to the player (or whatever its target is), except for retaliation strike when hurt.

 

You can experiment with it if you want: put a revenant in a cage so it's stuck in place, and then move toward it. You'll notice there's a range where it can't attack you and it becomes completely harmless. Go a bit further away, and it'll resume throwing missiles in your face, though. Go closer and you're in range for a punch. But in between these two limits, you're safe as you as you don't make it go into pain.

 

//
// P_CheckMissileRange
//
boolean P_CheckMissileRange (mobj_t* actor)
{
    fixed_t	dist;
	
    if (! P_CheckSight (actor, actor->target) )
	return false;
	
    if ( actor->flags & MF_JUSTHIT )
    {
	// the target just hit the enemy,
	// so fight back!
	actor->flags &= ~MF_JUSTHIT;
	return true;
    }
	
    if (actor->reactiontime)
	return false;	// do not attack yet
		
    // OPTIMIZE: get this from a global checksight
    dist = P_AproxDistance ( actor->x-actor->target->x,
			     actor->y-actor->target->y) - 64*FRACUNIT;
    
    if (!actor->info->meleestate)
	dist -= 128*FRACUNIT;	// no melee attack, so fire more

    dist >>= 16;

    if (actor->type == MT_VILE)
    {
	if (dist > 14*64)	
	    return false;	// too far away
    }
	

    if (actor->type == MT_UNDEAD)
    {
	if (dist < 196)	
	    return false;	// close for fist attack
	dist >>= 1;
    }
	

    if (actor->type == MT_CYBORG
	|| actor->type == MT_SPIDER
	|| actor->type == MT_SKULL)
    {
	dist >>= 1;
    }
    
    if (dist > 200)
	dist = 200;
		
    if (actor->type == MT_CYBORG && dist > 160)
	dist = 160;
		
    if (P_Random () < dist)
	return false;
		
    return true;
}

Note the MT_UNDEAD line coding here. If the target is nearer than 196 map units, this function returns false, meaning that the missile state will not be entered because it'll think it's not in range.

 

You can also see the MF_JUSTHIT flag check before that is what creates the retaliation shot mechanism.

 

Also you can see the the arch-vile (MT_VILE), cyberdemon (MT_CYBORG), the spiderdemon (MT_SPIDER) and the lost soul (MT_SKULL) also have special hardcoded mechanisms. Oh, and monsters without a melee state, too. Note that this won't help a revenant that lost its melee state, though.

Edited by Gez

Share this post


Link to post
  • 0

My issue was too severe to blame solely on being too close for the revenant's missile attack, but it seems like removing the revenant's melee attack messes with its head! I just gave it a "melee" attack that just points to the ranged attack, and now it works as it should, fixing the issue regardless of distance! I still don't know why it wasn't even shooting when far away, but the issue is fixed now.

Share this post


Link to post
  • 0

Doom tries to calculate the distance between the player and the monster and then uses that to determine if a monster should go into a ranged attack or not. But it also messes with this "distance" in various ways:

dist = P_AproxDistance ( actor->x-actor->target->x,
			     actor->y-actor->target->y) - 64*FRACUNIT;

if (!actor->info->meleestate)
	dist -= 128*FRACUNIT;	// no melee attack, so fire more

First the distance between the monster and player is estimated, and this distance is reduced by 64. Your monster did not have a melee attack, so the "distance" between the player and the monster was reduced by a further 128 units. Then came:

 if (actor->type == MT_UNDEAD)
    {
	if (dist < 196)	
	    return false;	// close for fist attack
	dist >>= 1;
    }

At this point, it goes through special code for the Revenant. Adding back the 128+64 units removed before, we see that the monster has to be more than *388* units away from the player, or else it will not attempt to do a ranged attack at all. This "dist" value is then halved, meaning it's at least 194.

 

But then we have:

if (dist > 200)
	dist = 200;

[...]

if (P_Random () < dist)
	return false;

So the minimum "dist" will be is 194, and it will go up to a maximum of 200. So what you end up with once all is said and done, the monster would have to be a minimum of 388 units away or else it will never attack, and it would have a 75% to 80% chance of choosing not to attack any time the game actually does go through the ranged attack code.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...