ACS can't reference a monster's hp after it dies

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
Duvo
Posts: 42
Joined: Thu Dec 26, 2019 4:17 am

ACS can't reference a monster's hp after it dies

Post by Duvo »

Hi everyone, I have a few issues with my code, which you can find in this pk3: http://s000.tinyupload.com/index.php?fi ... 2968183397
The full code and map may be found there, while I will reference parts of it this for this thread.

Within this pk3 I have a map with a custom zombie actor, which has 20 health and can resurrect upon death with the following state:

Code: Select all

Death:
		POSS H 5;
		POSS I 5 A_Scream;
		POSS J 5 A_NoBlocking;
		POSS K 5;
		//POSS L -1;
		POSS L random(20, 25);
		//POSS R 2 Revive();
		POSS K 5;
		POSS JIH 5 HealThing(20);
		
		Goto See;
		//Goto Raise;
		//Stop;
One of them, given the TID of 20, has it's health tracked on the HUD, along with a timer.

Code: Select all

script 100 ENTER{
	int t;
	int duration = 60;
	int health = GetActorProperty(20,APROP_HEALTH);
	while(true){
		t = Timer() / 35;
		health = GetActorProperty(20,APROP_HEALTH);
		SetFont("BIGFONT");
		HudMessage(s:"Zombie: ", d:(health),
		s:"\n",
		d:(duration - (t%10));
		HUDMSG_PLAIN,1, CR_RED, 0.1, 0.9, 0);
		Delay(35);
	}

}
However, upon resurrecting, it's health, on the hud, remains at the level it was upon it's death,
and does not change thereafter. I suspect that upon it's death it loses it's ID.

furthermore, I have used some code from Deathmatch simulator to make these zombies fight amongst themselves, using the alliance flickering technique.

Code: Select all

virtual void DoAllianceFlicker()
	{
		// Randomly flick between friendly and unfriendly if you don't have a
		// target, in order to simulate a free-for-all.
		if (target == null && health > 0)
		{
			bFRIENDLY = random(0,1);
		}
		
		if (target != null && target.health > 0 && health > 0)
		{
			bFRIENDLY = random(0,1);
		}
		
	}
unfortunately, after death and resurrection, the zombies take no interest in zombies previously raised and will instead go after zombies which have not been killed before.
Which is appropriate zombie behaviour, but not what I would like them to do. I'm not sure what causes this.
Blue Shadow
Posts: 5043
Joined: Sun Nov 14, 2010 12:59 am

Re: ACS can't reference a monster's hp after it dies

Post by Blue Shadow »

HealThing does nothing if used on an actor that's already dead. So instead, you want to use [wiki]A_RaiseSelf[/wiki].
User avatar
Duvo
Posts: 42
Joined: Thu Dec 26, 2019 4:17 am

Re: ACS can't reference a monster's hp after it dies

Post by Duvo »

Hi @Blue Shadow, I've implemented the change.

I moved the player into the arena and it seems that once the monsters are killed and raised,
they no longer are able to be shot at, bullets will go right through them. I think this is the root of the problem
User avatar
Duvo
Posts: 42
Joined: Thu Dec 26, 2019 4:17 am

Re: ACS can't reference a monster's hp after it dies

Post by Duvo »

I've stripped down the Zombie class to it's bare essentials, but the problem still persists. after the zombie is raised, it cannot be hit by anything at all

Code: Select all

class raisingZombie : ZombieMan{
	States{
		Death:
			POSS H 5;
			POSS I 5 A_Scream;
			POSS K 5;
			POSS L random(20, 25);
			POSS JIH 5 A_RaiseSelf();
			
			Goto See;
	}
}
User avatar
Duvo
Posts: 42
Joined: Thu Dec 26, 2019 4:17 am

Re: ACS can't reference a monster's hp after it dies

Post by Duvo »

I've found the source of the problem. the raise code has a few specifications for a clean resurrection, my first being that the frame upon which the zombie respawns had to have a timer of -1. I started from the base zombie class and added what I needed on top of it. now it works like a charm, the health correctly displays on the hud too. Here is the code:

Code: Select all

class OGZombieMan : Actor
{
	Default
	{
		Health 20;
		Radius 20;
		Height 56;
		Speed 1;
		PainChance 200;
		Monster;
		+FLOORCLIP
		SeeSound "grunt/sight";
		AttackSound "grunt/attack";
		PainSound "grunt/pain";
		DeathSound "grunt/death";
		ActiveSound "grunt/active";
		Obituary "$OB_ZOMBIE";
		Tag "$FN_ZOMBIE";
		DropItem "Clip";
		+NOBLOCKMONST;
		+BLOCKASPLAYER;
		+DROPOFF;
	}
	
	vector3 oldPos;
	vector2 neckchecker;
	int wallcooldown;
	int addtimer;
	
 	States
	{
	Spawn:
		POSS AB 10 A_Look;
		Loop;
	See:
		POSS AABBCCDD 4 A_Chase;
		Loop;
	Missile:
		POSS E 10 A_FaceTarget;
		POSS F 8 A_PosAttack;
		POSS E 8;
		Goto See;
	Pain:
		POSS G 3;
		POSS G 3 A_Pain;
		Goto See;
	Death:
		POSS H 5;
		POSS I 5 A_Scream;
		POSS J 5 A_NoBlocking;
		POSS K 5;
		POSS L -1;
		Stop;
	XDeath:
		POSS M 5;
		POSS N 5 A_XScream;
		POSS O 5 A_NoBlocking;
		POSS PQRST 5;
		POSS U -1;
		Stop;
	Raise:
		POSS K 5;
		POSS JIH 5;
		Goto See;
	}
	
	void A_FDMChase(statelabel melee = "Melee", statelabel missile = "Missile", int flags = 0)
	{
		DoAvoidWallrunning();
		A_Chase(melee, missile, flags);
		A_Recoil(-speed);
		oldPos = pos;
	}
	
	void A_FDMRoam()
	{
		DoAvoidWallrunning();
		
		A_Wander();
		A_Look();
		A_Recoil(-speed);
		oldPos = pos;
	}
	
	override void Tick()
	{
		// These have all been broken into seperate functions so that individual
		// actors can disable or override them for whatever reason.
		
		DoAllianceFlicker();
		
		// Stops monsters from switching away from their opponent to the player
		// in the middle of a fight
		if (addtimer > 0)
		{
			addtimer--;
		}
		
		if (curstate == MissileState || curstate == MeleeState)
		{
			addtimer = 60;
		}
		
		Super.Tick();
	}
	
	
	virtual void DoAvoidWallrunning()
	{
		// Making an attempt to prevent actors running into walls a bunch
		if (pos.xy == oldpos.xy)
		{
			A_Recoil(speed * 2);
			self.angle = self.angle + 180;
		}
	}
	
	
	virtual void DoAllianceFlicker()
	{
		// Randomly flick between friendly and unfriendly if you don't have a
		// target, in order to simulate a free-for-all.
		if (target == null && health > 0)
		{
			bFRIENDLY = random(0,1);
		}
		
		if (target != null && target.health > 0 && health > 0)
		{
			bFRIENDLY = random(0,1);
		}
		
	}
}

// Zombieman
class FighterZombie : OGZombieMan replaces ZombieMan
{
	Default
	{
		Health 100;
		Radius 20;
		Height 56;
		PainChance 200;
		Monster;
		+FLOORCLIP;
		speed 2;
		
		AttackSound "grunt/attack";
		PainSound "grunt/pain";
		DeathSound "grunt/death";
		ActiveSound "grunt/active";
		Obituary "$OB_ZOMBIEMAN";
		//Tag "$FN_ZOMBIE";
		DropItem "Clip";
		Decal "BulletChip";
	}
	States
	{
	Spawn:
		POSS A 10 A_Look;
		goto Roam;
	Roam:
		POSS AABBCCDD 4 A_FDMRoam();
		Loop;
	See:
		POSS AABBCCDD 4 A_FDMChase;
		Loop;
	Missile:
		POSS E 0 ThrustThing(frandom(0,360), 4, 0, 0);
		POSS E 4 A_FaceTarget;
		POSS F 2 A_SpawnProjectile("ZombBullet", 27);
		//POSS E 1 A_CPosRefire;
		Goto Missile;
	Pain:
		POSS G 3;
		POSS G 3 A_Pain;
		Goto See;
	Death:
		POSS H 5;
		POSS I 5 A_Scream;
		POSS K 5;
		POSS L random(20, 25);
		POSS JI 2;
		POSS H -1 A_RaiseSelf();
		
		Goto See;
	}
	
	override void PostBeginPlay ()
	{
		Super.PostBeginPlay ();
		bFRIGHTENED = random(0,1);
	}
}

Post Reply

Return to “Scripting”