DECORATE Projectile that goes through multiple actors?

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
PeceMan
Posts: 6
Joined: Fri Oct 30, 2020 2:42 pm

DECORATE Projectile that goes through multiple actors?

Post by PeceMan »

Not just a ripper projectile, but a projectile that deals a specific ammount of damage to a specific ammount of enemies upon contact, and then dissapears

I'm currently trying for the life of me to make a shuriken. The shuriken is supposed to be able to go through one enemy, hitting two total. Its not a homing projectile, so if it hits a wall before hitting both monsters itll just count as a miss.

I want to be able to shoot it at a group of really weak enemies (10 hp each) and two of them die, because the shuriken deals 15 damage to its two targets. Only two enemies are supposed to die.

I'm running a bit on the desperate side here. Pls hlp
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49252
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: DECORATE Projectile that goes through multiple actors?

Post by Graf Zahl »

In DECORATE you won't be able to do it. You'll need ZScript and override the SpecialMissileHit method which allows you to fine tune the behavior of your projectile when it hits a target.
User avatar
KometFox
Posts: 64
Joined: Thu Nov 05, 2020 12:43 pm

Re: DECORATE Projectile that goes through multiple actors?

Post by KometFox »

Graf Zahl wrote:In DECORATE you won't be able to do it. You'll need ZScript and override the SpecialMissileHit method which allows you to fine tune the behavior of your projectile when it hits a target.
It is possible by using multiple projectiles that gets fired at the same time. That's how I achieved multiple target piercing effect on my mod, and yes this method worked before I made the conversion to ZScript. The downside of it that it the projectile must be shot with 100% accuracy, in my case I made the damaging projectile almost invisible save for when it hits a target and a dummy projectile that gets fired last which does the more fancier fake particle effects at 0 damage, I tested it a lot and it meet to my exceptions. It also still works when the projectile inherits FastProjectile actor.
So for example when those the main projectile does 60 damage and the weapon fires 5 of it then it will be able to pierce 5 doomimps and the faux projectile "detonates" at the last target.
I did this because the +ripper flag does not represent the behavior of how a average AP shot works in real life.

Code: Select all

APHE_Fire:
	"####" A 0 A_TakeInventory("MT_75x500mmAP",1)
	"####" A 0 A_Jumpifinventory("MTU_APShot_2",2, "APHE3_Fire")
	"####" A 0 A_Jumpifinventory("MTU_APShot_2",1, "APHE2_Fire")
	"####" AAAAAAA 0 A_Firecustommissile("MT_105mmAPHEshell",0,0) //Damaging Projectile
	"####" A 0 A_FireCustomMissile("MT_105mmAPHEshell_Dummy",0,1)  //Faux Projectile
	Goto MuzzleFlash_Default

Code: Select all

//----Armor Piercing High Explosive Shell
//AP is shot 7x times.
const int p105mmAPHE_ttd = 55;
const int p105mmAPHE_dd = 100;
const int p105mmAPHE_sdmg = 50;
const int p105mmAPHE_srad = 90;
const int p105mmAPHE_sfullrad = 80;
//UPG1
const int p105mmAPHE_2_dd = 120;
const int p105mmAPHE_2_sdmg = 72;
const int p105mmAPHE_2_srad = 108;
const int p105mmAPHE_2_sfullrad = 90;
//UPG2
const int p105mmAPHE_3_dd = 144;
const int p105mmAPHE_3_sdmg = 87;
const int p105mmAPHE_3_srad = 130;
const int p105mmAPHE_3_sfullrad = 120;

ACTOR MT_105mmAPHEshell : MTP_ShellBase_Fast
{
  Speed 95
  DamageType Piercing
  damage (p105mmAPHE_dd)
  Obituary "%o <105mm APHE] %k" 
  +BLOODSPLATTER
  States
  {
Setter:
	TNT1 A 0 A_SetUserVar("user_ttl", p105mmAPHE_ttd)
	TNT1 A 0 A_SetUserVar("user_mode", 1)
	TNT1 A 0 A_Jump(256, "Jumper")
	Goto Jumper
Drop:
	TNT1 A 0 A_CustomMissile("MT_105mmAPHEshell_Drop", 0, 0, 0, CMF_AIMDIRECTION, velz / 2)
	Stop  
Death:
	TNT1 A 0 A_Spawnitem("MTCEG_MediumExplosion_APHEFlash_EX")
	TNT1 A 0 A_PlaySound("Medium/APExplosion")
FDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_sdmg,p105mmAPHE_srad,0,0,p105mmAPHE_sfullrad)
	Stop
XDeath:
	TNT1 A 0 A_spawnitemex("MT_CEG_75mm_OrganHit_Trail",0,0,0,+frandom(-12,12),+frandom(-12,12),+frandom(-12,12))  
	TNT1 AAAA 0 A_spawnitemex("MT_CEG_75mm_OrganHit",0,0,0,+frandom(-3,3),+frandom(-3,3),+frandom(-3,3))
	TNT1 A 0 A_PlaySound("MeaHit3")
FXDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_sdmg,p105mmAPHE_srad,0,0,p105mmAPHE_sfullrad)
    Stop
Crash:
	TNT1 A 0 A_Spawnitem("MTCEG_MediumExplosion_APHEFlash_EX")
	TNT1 A 0 A_PlaySound("MetHit3")
FCrash:
	TNT1 A 1 A_Explode(p105mmAPHE_sdmg,p105mmAPHE_srad,0,0,p105mmAPHE_sfullrad)
	Stop
  }
}

ACTOR MT_105mmAPHEshell_Drop : MTP_ShellBase
{
  Speed 60
  Gravity 0.25
  DamageType Piercing
  damage (p105mmAPHE_dd)
  Obituary "%o <105mm APHE] %k" 
  +BLOODSPLATTER
  States
  {
Setter:
	TNT1 A 0 A_SetUserVar("user_ttl", 9999)
	TNT1 A 0 A_SetUserVar("user_mode", 1)
	TNT1 A 0 A_Jump(256, "Jumper")
	Goto Jumper
Death:
	TNT1 A 0 A_Spawnitem("MTCEG_MediumExplosion_APHEFlash_EX")
	TNT1 A 0 A_PlaySound("Medium/APExplosion")
FDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_sdmg,p105mmAPHE_srad,0,0,p105mmAPHE_sfullrad)
	Stop
XDeath:
	TNT1 A 0 A_spawnitemex("MT_CEG_75mm_OrganHit_Trail",0,0,0,+frandom(-12,12),+frandom(-12,12),+frandom(-12,12))  
	TNT1 AAAA 0 A_spawnitemex("MT_CEG_75mm_OrganHit",0,0,0,+frandom(-3,3),+frandom(-3,3),+frandom(-3,3))
	TNT1 A 0 A_PlaySound("MeaHit3")
FXDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_sdmg,p105mmAPHE_srad,0,0,p105mmAPHE_sfullrad)
    Stop
Crash:
	TNT1 A 0 A_Spawnitem("MTCEG_MediumExplosion_APHEFlash_EX")
	TNT1 A 0 A_PlaySound("MetHit3")
FCrash:
	TNT1 A 1 A_Explode(p105mmAPHE_sdmg,p105mmAPHE_srad,0,0,p105mmAPHE_sfullrad)
	Stop
  }
}

ACTOR MT_105mmAPHEshell_2 : MT_105mmAPHEshell
{
  States
  {
Drop:
	TNT1 A 0 A_CustomMissile("MT_105mmAPHEshell_2_Drop", 0, 0, 0, CMF_AIMDIRECTION, velz / 2)
	Stop  
FDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_2_sdmg,p105mmAPHE_2_srad,0,0,p105mmAPHE_2_sfullrad)
	Stop
FXDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_2_sdmg,p105mmAPHE_2_srad,0,0,p105mmAPHE_2_sfullrad)
    Stop
FCrash:
	TNT1 A 1 A_Explode(p105mmAPHE_2_sdmg,p105mmAPHE_2_srad,0,0,p105mmAPHE_2_sfullrad)
	Stop
  }
}

ACTOR MT_105mmAPHEshell_2_Drop : MT_105mmAPHEshell_Drop
{
  States
  {
FDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_2_sdmg,p105mmAPHE_2_srad,0,0,p105mmAPHE_2_sfullrad)
	Stop
FXDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_2_sdmg,p105mmAPHE_2_srad,0,0,p105mmAPHE_2_sfullrad)
    Stop
FCrash:
	TNT1 A 1 A_Explode(p105mmAPHE_2_sdmg,p105mmAPHE_2_srad,0,0,p105mmAPHE_2_sfullrad)
	Stop
  }
}


ACTOR MT_105mmAPHEshell_3 : MT_105mmAPHEshell
{
  States
  {
Drop:
	TNT1 A 0 A_CustomMissile("MT_105mmAPHEshell_3_Drop", 0, 0, 0, CMF_AIMDIRECTION, velz / 2)
	Stop  
FDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_3_sdmg,p105mmAPHE_3_srad,0,0,p105mmAPHE_3_sfullrad)
	Stop
FXDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_3_sdmg,p105mmAPHE_3_srad,0,0,p105mmAPHE_3_sfullrad)
    Stop
FCrash:
	TNT1 A 1 A_Explode(p105mmAPHE_3_sdmg,p105mmAPHE_3_srad,0,0,p105mmAPHE_3_sfullrad)
	Stop
  }
}

ACTOR MT_105mmAPHEshell_3_Drop : MT_105mmAPHEshell_Drop
{
  States
  {
FDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_3_sdmg,p105mmAPHE_3_srad,0,0,p105mmAPHE_3_sfullrad)
	Stop
FXDeath:
	TNT1 A 1 A_Explode(p105mmAPHE_3_sdmg,p105mmAPHE_3_srad,0,0,p105mmAPHE_3_sfullrad)
    Stop
FCrash:
	TNT1 A 1 A_Explode(p105mmAPHE_3_sdmg,p105mmAPHE_3_srad,0,0,p105mmAPHE_3_sfullrad)
	Stop
  }
}


ACTOR MT_105mmAPHEshell_Dummy : MTP_ShellBase_Fast
{
  Speed 95
  Damagetype Piercing
  damage (0)
  DeathSound "Medium/APExplosion"
  Obituary "%o <105mm APHE] %k" 
  +BLOODSPLATTER
  decal MT_LargeAPHit 
  States
  {
Setter:
	TNT1 A 0 A_SetUserVar("user_ttl", p105mmAPHE_ttd)
	TNT1 A 0 A_SetUserVar("user_mode", 1)
	TNT1 A 0 A_Jump(256, "Jumper")
	Goto Jumper
Drop:
	TNT1 A 0 A_CustomMissile("MT_105mmAPHEshell_Drop_Dummy", 0, 0, 0, CMF_AIMDIRECTION, velz / 2)
	Stop  
  Death:
    TNT1 A 0 A_Spawnitem("MTCEG_MediumExplosion_APHE")
    TNT1 A 0 A_PlaySound("Medium/APExplosion")
	TNT1 A 1
    Stop
  }
}

ACTOR MT_105mmAPHEshell_Drop_Dummy : MTP_ShellBase
{
Speed 60
Damagetype Piercing
gravity 0.25
damage (0)
DeathSound "Medium/APExplosion"
Obituary "%o <105mm APHE] %k" 
+BLOODSPLATTER
decal MT_LargeAPHit 
  States
  {
Setter:
	TNT1 A 0 A_SetUserVar("user_ttl", 9999)
	TNT1 A 0 A_SetUserVar("user_mode", 1)
	TNT1 A 0 A_Jump(256, "Jumper")
	Goto Jumper  
Death:
	TNT1 A 0 A_Spawnitem("MTCEG_MediumExplosion_APHE")
	TNT1 A 0 A_PlaySound("Medium/APExplosion")
	TNT1 A 1
    Stop
  }
}
User avatar
Mini--Joe
Posts: 97
Joined: Sun Jul 27, 2014 10:25 am

Re: DECORATE Projectile that goes through multiple actors?

Post by Mini--Joe »

[]Dot wrote: It is possible by using multiple projectiles that gets fired at the same time. That's how I achieved multiple target piercing effect on my mod, and yes this method worked before I made the conversion to ZScript. The downside of it that it the projectile must be shot with 100% accuracy, in my case I made the damaging projectile almost invisible save for when it hits a target and a dummy projectile that gets fired last which does the more fancier fake particle effects at 0 damage, I tested it a lot and it meet to my exceptions. It also still works when the projectile inherits FastProjectile actor.
So for example when those the main projectile does 60 damage and the weapon fires 5 of it then it will be able to pierce 5 doomimps and the faux projectile "detonates" at the last target.
I did this because the +ripper flag does not represent the behavior of how a average AP shot works in real life.
So you simply spawn a bunch of different projectiles at the exact same time with the exact same hitbox? I tried this with only one projectile type and it does not seem to work...
User avatar
KometFox
Posts: 64
Joined: Thu Nov 05, 2020 12:43 pm

Re: DECORATE Projectile that goes through multiple actors?

Post by KometFox »

Mini--Joe wrote:So you simply spawn a bunch of different projectiles at the exact same time with the exact same hitbox? I tried this with only one projectile type and it does not seem to work...
Pretty much, how did you performed your test? Did you tried using your weapon against multiple doom imps that are standing in multiple lines? There is some certain enemy type which I forget that can negate this effect if I am not mistaken if you try to hit it against monster types like cacodemons that have long lasting corpse blocking during their death state then this effect wont work, the monster needs to be modified so that upon death they start losing their collision box on the first frame.

I have a damage based ZScript code that achieves the same effect which has the advance it scales dynamically depending how strong the projectile is:

Code: Select all

Mixin Class Common_Proj
{
	int Dmg;
}

//Hit multiple targets.
Mixin Class MultiPiercing
{
	/*
	First get the victim health. If the victim health is greater
	than the current projectile damage then just do normal damage and
	kill the projectile, else kill the victim and proceed with normal
	trajectory.			
	*/
	
	//Requires Common_Proj to work!
	//Mixin Common_Proj;
	
	Override void BeginPlay()
	{
		Dmg = GetMissileDamage(0, 0, AAPTR_DEFAULT);
				
		Super.BeginPlay();
	}

	Override int SpecialMissileHit (Actor victim)
	{
		int Victim_HP = victim.health;
		
		if (!victim.player && Dmg > 0)
		{
			victim.DamageMobj(self, target, Dmg, damagetype, 0);
			Dmg -= Victim_HP;	
		}

		if (Dmg <= 0)
		{
			//Using -1 here results in double damage.
			return 0;
		}
		
		return 1;
	}


}

Post Reply

Return to “Scripting”