Ripper with fixed damage per actor?
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!)
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!)
Ripper with fixed damage per actor?
I want to create a projectile that goes through enemies but hurts each of them only once. Is it posssible to accomplish with rippers? Do they do damage every tic? Maybe I should give it a zero damage but give it PosionDamage with a duration of a second (because in that time the projectile would definitely leave the body), but then if two such projectiles hit one actor within a second, the damage from the second one will be ignored, if I don't set the flag ADDITIVEPOISONDAMAGE. But if I add it, wouldn't the ripper add the poison as much times as it would do normal damage?
Re: Ripper with fixed damage per actor?
rippers don't do damage once per tic
they do damage based on distance travelled through an actor
if you're using zscript, you'll want to take a look at SpecialMissileHit
they do damage based on distance travelled through an actor
if you're using zscript, you'll want to take a look at SpecialMissileHit
Re: Ripper with fixed damage per actor?
Unfortunately, this is the extent of my knoledge of zscript: https://zdoom.org/wiki/Converting_DECOR ... to_ZScript, and I don't even understand everything in there. Are there any tutorials? The pages in the category "ZScript guides" are more like reference cards for those who already know their way around. Where can I learn the basics? Like its structure, what goes where, etc.
Re: Ripper with fixed damage per actor?
As far as I can tell, making SpecialMissileHit return 1 just turns it into a ripper. Of course, my knoledge of zscript is very limited, so maybe I'm just doing something wrong. My code is this:
It definitely does damage multiple times.
Code: Select all
Class HLCrossbowBolt : FastProjectile
{
override int SpecialMissileHit (Actor victim)
{
victim.DamageMobj (self, target, 10, 'Melee');
return 1;
}
Default
{
// Speed 90;
Speed 10;
DamageFunction 0;
DamageType "Ether";
SeeSound "";
Radius 2;
Height 2;
Projectile;
+DONTSPLASH;
+WINDTHRUST;
RenderStyle "Add";
DeathSound "BOWHIT1";
Obituary "$OB_MPCROSSBOW";
MissileHeight 8;
Decal "CrossbowScorch";
}
States
{
Spawn:
HLAR A 1 Bright A_SpawnItem("EtherealFlare1");
Loop;
Death:
FX03 CDE 2 Bright A_SpawnItem("EtherealFlare2");
Stop;
}
}
- Arctangent
- Posts: 1235
- Joined: Thu Nov 06, 2014 1:53 pm
- Contact:
Re: Ripper with fixed damage per actor?
I mean, you're telling the missile to, each time it collides with a damageable actor, deal 10 damage and then pass through without exploding. So, it'll pass through once, deal its damage, pass through again, deal its damage, etc.. Basically, you're not telling the game to do anything but what ripping missiles already do - there's nothing there saying "pass through this actor, but don't deal damage."
So, you're going to want to do that, and the most straightforward way to do that is to keep track of what actors the missile has already hit, so it can know not to damage them. [wiki]Dynamic arrays[/wiki] are perfect for this - they can store any number of actor pointers and have the Find() function to grab the index of an item - so you could, say,
to add a dynamic array to your missle, then use the info in there to see if the missile's hit anything or not.
Note the if statement: if Find() can't find the item, then it'll instead return the array's size. So we can compare Find() and Size() to see if the victim's not in there, and thus, hasn't already been hit.
So, you're going to want to do that, and the most straightforward way to do that is to keep track of what actors the missile has already hit, so it can know not to damage them. [wiki]Dynamic arrays[/wiki] are perfect for this - they can store any number of actor pointers and have the Find() function to grab the index of an item - so you could, say,
Code: Select all
Array<Actor> hitList;
override int SpecialMissileHit (Actor victim)
{
if (hitList.Find (victim) == hitList.Size())
{
victim.DamageMobj (self, target, 10, 'Melee');
hitlist.Push (victim)
}
return 1;
}
Note the if statement: if Find() can't find the item, then it'll instead return the array's size. So we can compare Find() and Size() to see if the victim's not in there, and thus, hasn't already been hit.
Re: Ripper with fixed damage per actor?
Here more elegant solution
Code: Select all
actor last_hit;
override int SpecialMissileHit (Actor victim)
{
if (last_hit == victim) {return 1;}
victim.damagemobj(arguments);
last_hit = victim;
return 1;
}
- Arctangent
- Posts: 1235
- Joined: Thu Nov 06, 2014 1:53 pm
- Contact:
Re: Ripper with fixed damage per actor?
... which will proceed to use normal ripping behavior if the projectile is in the position to hit multiple actors at the same time ( y'know, like in the very rare situation where monsters are standing next to each other ), which is what I'd call the exact opposite of "elegant."Apeirogon wrote:Here more elegant solutionCode: Select all
actor last_hit; override int SpecialMissileHit (Actor victim) { if (last_hit == victim) {return 1;} victim.damagemobj(arguments); last_hit = victim; return 1; }
Re: Ripper with fixed damage per actor?
This is most likely an artificial situation. Because I used it, like always, and dont faced with such situation.hit multiple actors at the same time
Only cases when this really can happens is when projectile have enormous height and/or radius.
- Arctangent
- Posts: 1235
- Joined: Thu Nov 06, 2014 1:53 pm
- Contact:
Re: Ripper with fixed damage per actor?
If it was an artificial situation, then the vanilla rocket launcher would be pretty useless.Apeirogon wrote:This is most likely an artificial situation. Because I used it, like always, and dont faced with such situation.hit multiple actors at the same time
Only cases when this really can happens is when projectile have enormous height and/or radius.
Unless by "enormous height and radius" you mean ... y'know, the size of vanilla projectiles, considering they're more than capable of colliding with multiple monsters at once, especially in the narrow spaces of Doom 1 maps.
Re: Ripper with fixed damage per actor?
Thanks! That works beautifulyArctangent wrote:Code: Select all
Array<Actor> hitList; override int SpecialMissileHit (Actor victim) { if (hitList.Find (victim) == hitList.Size()) { victim.DamageMobj (self, target, 10, 'Melee'); hitlist.Push (victim) } return 1; }
There's one hitch though, such a projectile hits myself the moment it is spawned I suppose, projectiles are spawned by default inside the players "box" (or what is it called). So I suppose the simplest way of avoiding hurting the launcher of the projectile (it can be not only the player since I'm planning on giving a similar attack to a monster) would be to place it in the array. Something like this?
Code: Select all
Array<Actor> hitList;
hitlist.Push (something) // <- the designation of the actor that launches the projectile
override int SpecialMissileHit (Actor victim)
{
if (hitList.Find (victim) == hitList.Size())
{
victim.DamageMobj (self, target, 10, 'Melee');
hitlist.Push (victim)
}
return 1;
}
Re: Ripper with fixed damage per actor?
Also, I tested such a projectile with monsters. They do indeed hurt themselves when launching such projectiles, and besides, if a member of their species is hit with it, they get into infights within the species. Can it be prevented without setting the damagefactor to zero?
- Arctangent
- Posts: 1235
- Joined: Thu Nov 06, 2014 1:53 pm
- Contact:
Re: Ripper with fixed damage per actor?
Something as simple as this:
before the rest of the code in SpecialMissileHit should handle all of that perfectly fine.
All standard projectile-spawning functions will set the projectile's target to its owner, so you can always use that as a reference to them. As for why it's stored as the projectile's target? That's because in vanilla Doom 1, the only pointer actors had to other actors was their target, so id just reused it for projectiles since there weren't any that needed to keep track of an actual target.
Which, of course, changed as soon as Doom 2 rolled around, and that's why there's a target and a tracer pointer for all actors.
Code: Select all
if (victim == target) return 1;
All standard projectile-spawning functions will set the projectile's target to its owner, so you can always use that as a reference to them. As for why it's stored as the projectile's target? That's because in vanilla Doom 1, the only pointer actors had to other actors was their target, so id just reused it for projectiles since there weren't any that needed to keep track of an actual target.
Which, of course, changed as soon as Doom 2 rolled around, and that's why there's a target and a tracer pointer for all actors.
Re: Ripper with fixed damage per actor?
Thanks, that fixes the problem with damaging self, but the monsters still get into infights within one species. I mean, normally, if a monster is hit by a projectile launched by a member of its species, it is unharmed and does not turn on the launcher, but with these projectiles they do get hurt and turn on each other.
I scrambled something that I thought would fix it (additional condition), but it does not work:
Edit: It was my lack of attention, I forgot to insert this into one of the two projectiles. Actually this does work.
But this doesn't: I tried to put "PrintBold(s:"The script works");" the line above "return 1", but then the game wouldn't launch with this error:
Trying to PlaySound prior to "return 1" also returns "unknown function" (I wanted to make the projectiles play the hit sound, because now they go silently through everyone).
I scrambled something that I thought would fix it (additional condition), but it does not work:
Edit: It was my lack of attention, I forgot to insert this into one of the two projectiles. Actually this does work.
Code: Select all
if (victim.GetSpecies() == target.GetSpecies())
return 1;
Code: Select all
Script error, ":zscript.proj_mon_beast" line 68:
Call to unknown function 'PrintBold'
-
- Posts: 4949
- Joined: Sun Nov 14, 2010 12:59 am
Re: Ripper with fixed damage per actor?
They should be [wiki]A_PrintBold[/wiki] and [wiki]A_PlaySound[/wiki]. What you're trying to use there are their ACS equivalent.