Jump to content

NPC Death Splash Damage


Go to solution Solved by Szico VII,

Recommended Posts

Does anyone know of a way to make an NPC deal splashdamage upon death? I'd like to have to run an effect (say an explosion) which also does damage.

 

You can set splashdamage on fx_runners but this isnt run from a fx_runner, its from animevents.cfg

I also thought about spawning an fx_runner at the npc origin on death using a deathscript but the origin tag doesnt seem to work in MP for moving entities.

 

Any thoughts?

Link to comment

I also thought about spawning an fx_runner at the npc origin on death using a deathscript but the origin tag doesnt seem to work in MP for moving entities.

Origin tag as in so?

move ($tag( "npc_targetname", ORIGIN)$, 0.000 );

 

What about this then?

$get( VECTOR, "SET_ORIGIN")$

 

You'd need a global variable (via declare, don't forget the free later) to be able to get that origin over to the other entity, does this work?

 

//(BHVD)
declare ( /*@DECLARE_TYPE*/ VECTOR, "tmp" );
set ( "tmp", $get( VECTOR, "SET_ORIGIN")$ );

affect ( "dat_cool_fx_runner", /*@AFFECT_TYPE*/ FLUSH )
{
move ( $get( VECTOR, "tmp")$, 0.000 );
free ( "tmp" );
rem ( "maybe wait() here?" );
use ( "dat_cool_fx_runner" );
}
Link to comment

Vector is the type of variable - a 3 dimensional (mathematical) vector, used to represent positions in 3D space (x, y and z coordinate). It's how an entity's origin is stored.

 

As to how the script works, that's the deathscript of your NPC. It queries the NPC's position and stores that in a new global variable of the name tmp with the type (3D-)Vector that is created first (via declare). There's a limit of like 16 global variables so you want to keep their usage down, which is why it is removed (using free) once we're done using it. If you want to get data from one entity to another, you'll have to do it via global variable because all the other things you can set/get are relative to the script-executing entity.

 

Anyway, I've tried actually building an example map and found that using move(); on an fx_runner in MP breaks it. So I tried set(SET_ORIGIN);, and what can I say?

 

http://youtu.be/E_CckT-9ckY

 

Works like a charme. I've had to use an extra relay so the fx_runner executing the script does not use itself - Jedi Academy prints a warning to the console if that happens since it's prone to causing infinite loops - and reset the deathscript because apparently dying once causes it to be executed multiple times (wtf?). So this is what the final script looks like:

 

//Generated by BehavEd

declare ( /*@DECLARE_TYPE*/ VECTOR, "tmp" );
set ( /*@SET_TYPES*/ "SET_DEATHSCRIPT", "" );
set ( "tmp", $get( VECTOR, "SET_ORIGIN")$ );

affect ( "dat_cool_fx_runner_script", /*@AFFECT_TYPE*/ FLUSH )
{
set ( /*@SET_TYPES*/ "SET_ORIGIN", $get( VECTOR, "tmp")$ );
free ( "tmp" );
use ( "dat_cool_fx_runner_relay" );
}

 

Here's the map I used for testing:

 

 

// entity 0
{
"classname" "worldspawn"
// brush 0
{
( 600 256 -64 ) ( -544 256 -64 ) ( -544 -368 -64 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -544 -368 0 ) ( -544 256 0 ) ( 600 256 0 ) imperial/basic 0 0 0 0.500000 0.500000 0 4 0
( -544 -384 8 ) ( 600 -384 8 ) ( 600 -384 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 -368 8 ) ( 640 256 8 ) ( 640 256 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 600 256 8 ) ( -544 256 8 ) ( -544 256 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 256 8 ) ( -576 -368 8 ) ( -576 -368 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
}
// brush 1
{
( 704 256 0 ) ( 640 256 0 ) ( 640 -384 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 -384 256 ) ( 640 256 256 ) ( 704 256 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 -384 192 ) ( 704 -384 192 ) ( 704 -384 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 704 -384 192 ) ( 704 256 192 ) ( 704 256 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 704 256 192 ) ( 640 256 192 ) ( 640 256 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 256 192 ) ( 640 -384 192 ) ( 640 -384 0 ) imperial/basic 0 0 0 0.500000 0.500000 0 4 0
}
// brush 2
{
( 640 256 256 ) ( -576 256 256 ) ( -576 -384 256 ) imperial/basic 0 0 0 0.500000 0.500000 0 4 0
( -576 -384 320 ) ( -576 256 320 ) ( 640 256 320 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 -384 320 ) ( 640 -384 320 ) ( 640 -384 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 -384 320 ) ( 640 256 320 ) ( 640 256 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 256 320 ) ( -576 256 320 ) ( -576 256 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 256 320 ) ( -576 -384 320 ) ( -576 -384 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
}
// brush 3
{
( -576 256 0 ) ( -640 256 0 ) ( -640 -384 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -640 -384 256 ) ( -640 256 256 ) ( -576 256 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -640 -384 256 ) ( -576 -384 256 ) ( -576 -384 64 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 -384 192 ) ( -576 256 192 ) ( -576 256 0 ) imperial/basic 0 0 0 0.500000 0.500000 0 4 0
( -576 256 256 ) ( -640 256 256 ) ( -640 256 64 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -640 256 256 ) ( -640 -384 256 ) ( -640 -384 64 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
}
// brush 4
{
( 640 320 0 ) ( -576 320 0 ) ( -576 192 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 192 256 ) ( -576 320 256 ) ( 640 320 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 256 256 ) ( 640 256 256 ) ( 640 256 0 ) imperial/basic 0 0 0 0.500000 0.500000 0 4 0
( 640 192 256 ) ( 640 320 256 ) ( 640 320 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 320 256 ) ( -576 320 256 ) ( -576 320 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 320 256 ) ( -576 192 256 ) ( -576 192 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
}
// brush 5
{
( 576 -384 0 ) ( -512 -384 0 ) ( -512 -448 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -512 -448 256 ) ( -512 -384 256 ) ( 576 -384 256 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( -576 -448 256 ) ( 512 -448 256 ) ( 512 -448 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 640 -448 256 ) ( 640 -384 256 ) ( 640 -384 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
( 576 -384 256 ) ( -512 -384 256 ) ( -512 -384 0 ) imperial/basic 0 0 0 0.500000 0.500000 0 4 0
( -576 -384 256 ) ( -576 -448 256 ) ( -576 -448 0 ) system/caulk 0 0 0 0.500000 0.500000 0 4 0
}
}
// entity 1
{
"origin" "-448 0 64"
"classname" "info_player_start"
}
// entity 2
{
"npc_targetname" "random_droid"
"deathscript" "tests/move_fx_runner_mp"
"origin" "-416 0 64"
"classname" "NPC_Ugnaught"
}
// entity 3
{
"target" "dat_cool_fx_runner"
"targetname" "dat_cool_fx_runner_relay"
"origin" "0 128 64"
"classname" "target_relay"
}
// entity 4
{
"classname" "fx_runner"
"origin" "0 0 128"
"fxfile" "explosions/hugeexplosion3"
"spawnflags" "6"
"splashDamage" "50"
"splashRadius" "128"
"targetname" "dat_cool_fx_runner"
"script_targetname" "dat_cool_fx_runner_script"
}

 

 

eezstreet likes this
Link to comment

Yeah....I was like WTF.... the deathscript kept running like 4-5 times and the damage worked, but the effect didnt... Weird. Ill try the method above..One sec.

 

P.S I also had the vector variable declared in a global initial spawnscript. Ah, right....I'll do it your way, works just as well.

P.P.S Whats the relevance of the NPC_targetname?

P.P.P.S What effect will the "set_deathscript NULL" have if the npc respawns? Apparently still respawns and works fine, whats it for then?

P.P.P.PS - Would this break if multiple NPC's had same deathscript and died together? WOuld I need a newvariable/fx combo for each NPC?

Link to comment

Edit: It seems from some trial and error, models not having a pelvis bone in the GLM/GLA makes it impossible to reference an origin of a model using icarus, so the fx_runner cant move there. Interesting.

 

@@mrwonko - thanks for all the help, I think we're finally at the bottom of getting it all working!

Link to comment

NPC_Targetname is not necessary, it's just so I can see the script executing entity's name. Should've removed that.

 

Regarding the deathscript: Ever wonder why NPCs use NPC_Targetname instead of Script_Targetname? They have a script_targetname, too, but that is for the spawner. I suppose the script names get copied to the NPC when they are spawned and only those copied values get changed by the script.

 

As for having multiple at once: I haven't investigated how exactly Icarus works, but I suppose it doesn't suspend a script mid-execution unless there's a wait so the scripts should run serial. The affect could mean trouble though, I don't know if it's guaranteed to start as soon as that command is issued or if it's just sent to a queue. Worst thing that could happen: All the dying NPC's effects go to one of them, or to an undefined position. (Triple Zero?)

 

The pelvis thing is weird, but not unusual. The code seems to make a lot of assumptions about that kind of thing.

Link to comment

 

Origin tag as in so?

move ($tag( "npc_targetname", ORIGIN)$, 0.000 );

 

What about this then?

$get( VECTOR, "SET_ORIGIN")$

 

You'd need a global variable (via declare, don't forget the free later) to be able to get that origin over to the other entity, does this work?

 

//(BHVD)
declare ( /*@DECLARE_TYPE*/ VECTOR, "tmp" );
set ( "tmp", $get( VECTOR, "SET_ORIGIN")$ );

affect ( "dat_cool_fx_runner", /*@AFFECT_TYPE*/ FLUSH )
{
move ( $get( VECTOR, "tmp")$, 0.000 );
free ( "tmp" );
rem ( "maybe wait() here?" );
use ( "dat_cool_fx_runner" );
}

 

Oh my gosh. You are my hero.

 

P.S. Could something similar be used to move something like...a trigger?

Link to comment

Bet you wish you'd asked earlier now :D

 

Oh my gosh. You are my hero.

 

P.S. Could something similar be used to move something like...a trigger?

 

Well you can definitely move trigger_hurt (did it in Atlantica) so I'd assume so, yes. That was a bit simpler.

 

 

affect ( "trigger_scriptname", /*@AFFECT_TYPE*/ INSERT )
            {
                move ( $tag( "ref_tag_name", ORIGIN)$, < 0.000 0.000 0.000 >, 1000.000 );
            }

 

@@mrwonko - EDIT: There appears to be a massive flaw with the method you suggested - the FX_runner wont move through walls or solid objects to get to its destination. Which means that if the NPC moves out other room it starts in the effect breaks down.

therfiles likes this
Link to comment

@@mrwonko - EDIT: There appears to be a massive flaw with the method you suggested - the FX_runner wont move through walls or solid objects to get to its destination. Which means that if the NPC moves out other room it starts in the effect breaks down.

I doubt that. I can imagine it breaking if it changes the leaf, which often happens to be behind a wall though. To verify this is the problem, try going to where the effect originally is, do r_lockpvs 1, then move to where it is supposed to play.

 

Actually, I'll experiment some more myself.

 

EDIT @@Szico VII: Okay, confirmed it. Moving an effect does not update it in the effect system - it is not played until its original leaf is in the PVS. Workaround: Do no VIS compile. :P

 

http://www.youtube.com/watch?v=y0i_0zEdFOo

Link to comment

Man, that might work but thats a lot of fx_runners and trigger entities and rooms to go through :o Because, really, you need 2 triggers on each side of every door, as npcs would be continuously activating the same script if it was covering an entire room.

Link to comment

Thats what we're looking into, We're also looking into using a trigger_hurt with animevents.cfg atm. Problem with that is that it requires a new GLA and animevens for every model, atm we're just using different skins on same model but want different death effects.

Link to comment

Too many for that unfortunately :o

 

Well, eventually got it to work. Fx_runner does the damage, deathanim does the effect.

 

Issues - The NPC corpse doesnt get removed, if you animate it to move under the floor the effect also goes under the floor. Currently using a "make invisible" script when it dies and then making it visible again on respawn to get around it. Seems to work alright.

 

Wont work OFC with spawns via the console, only with the ones placed in radiant..Unelss you use lugormod to give spawned npcs deathscripts and spawnscripts.

Link to comment

SET_ORIGIN is probably fixable, but unfortunately move() is not, simply because it sets the entity type to being an ET_MOVER rather than ET_FX which means no more fx.  In SP this is fine because its already being a ET_MOVER and it plays the effects directly from the game-side code.  But because clients are using ET_FX to tell it that it needs to handle it as an FX entity we can't fix this without a compat breaking change.

eezstreet likes this
Link to comment
Guest
This topic is now closed to further replies.
×
×
  • Create New...