Cutscene help - scripting firing weapon

I was to do a kind of script in a cutscene that I’ve never attempted before. I want an NPC to fire a weapon, a sling in this case, and hitting a target NPC, and then the target NPC dies, and after that the cutscene dialogue continues. I thought I’d use and modify the ga_death script, but I don’t know how to script the firing of a weapon.

This is the ga_death script I’ve begun modifying:

// ga_death
/*
    This script makes objects appear dead
        sTag        = The tag(s) of the object(s) to make dead. You can pass multiple
                      tags, seperated by commas (NO SPACES) to make multiple objects dead
                      (ie. "Object1,Object2,Object3")
        iInstance   = The instance of the object(s) to make dead. Pass -1 to make
                      all instances dead.
*/
// TDE 3/7/05
// BMA-OEI 1/11/06 removed default param
// TDE 8/3/06 - Set Immortal and Plot flags to FALSE, Added some debug strings
// TDE 8/28/06 - Changed SetIsDestroyable to (FALSE, FALSE, TRUE) so that the corpses can be looted

#include "ginc_debug"

void Death(string sTagString, int iInstance = 0)
{
	PrettyDebug("Applying Death Effect To: " + sTagString + " Instance = " + IntToString(iInstance));		
    if (iInstance == -1)
    {
        int iInst;
        object oObject;
        while (GetIsObjectValid(GetObjectByTag(sTagString, iInst)))
        {
            oObject = GetObjectByTag(sTagString, iInst);

            AssignCommand(oObject, SetIsDestroyable( FALSE,FALSE,TRUE ));
		    SetImmortal( oObject, FALSE );
		    SetPlotFlag( oObject, FALSE );
            effect eFX = EffectDeath();
			PrettyDebug("Name of oObject = " + GetName(oObject));		
            ApplyEffectToObject( DURATION_TYPE_INSTANT,eFX,oObject );
            iInst ++;
        }
    }
    else
    {
        object oObject = GetObjectByTag(sTagString, iInstance);

        AssignCommand(oObject, SetIsDestroyable( FALSE,FALSE,TRUE ));
	    SetImmortal( oObject, FALSE );
	    SetPlotFlag( oObject, FALSE );
        effect eFX = EffectDeath();
		PrettyDebug("Name of oObject = " + GetName(oObject));		
        ApplyEffectToObject( DURATION_TYPE_INSTANT,eFX,oObject );
    }
}

void KillFelkit(string sTagString, int iInstance)
{
    string newString = sTagString;
    int iLen = GetStringLength(sTagString);

    //find first comma
    int CommaPos = FindSubString( newString, "," );

    while(CommaPos != -1)
    {
        string tempString = GetSubString(newString, 0, CommaPos);

        Death(tempString, iInstance);
        newString = GetSubString(newString, CommaPos + 1, iLen);
        iLen = GetStringLength(newString);
        CommaPos = FindSubString( newString, "," );
    }

    //newString is equal to last tag to destroy
    Death(newString, iInstance);
}

void main()
{
	
//Some sort of code here where a sling weapon is fired against the NPC

DelayCommand(1.0,KillFelkit("felkit",0));


}

Can anyone help with this perhaps?

// 'ag_cs_deathsling'
/*
	This uses PlayCustomAnimation() to fake the attack, but it might be possible
	to do a real attack (possibly requiring SetCombatOverrides() to avoid
	triggering retaliation, not that it matters much since defender is going to
	die) without screwing up the attacker's Action queue if that's a
	consideration.

	just saying I haven't tested this, it's an idea
*/

void doAttack(object oDefender);
void playAttack();
void die(object oDefender);

void main()
{
	object oAttacker = GetObjectByTag("attacker"); // TODO: tags ...
	object oDefender = GetObjectByTag("defender");

	// attacker should have sling and ammo equipped (or whatever, it's generic)

	AssignCommand(oAttacker, doAttack(oDefender));

	DelayCommand(0.2f, die(oDefender));
}


// OBJECT_SELF is attacker
void doAttack(object oDefender)
{
	SetFacingPoint(GetPosition(oDefender));
	DelayCommand(0.3f, playAttack());
}

// OBJECT_SELF is attacker
void playAttack()
{
	PlayCustomAnimation(OBJECT_SELF, "*1attack01", FALSE);
}

void die(object oDefender)
{
	SetPlotFlag(oDefender, FALSE);
	SetImmortal(oDefender, FALSE);
//	AssignCommand(oDefender, SetIsDestroyable(TRUE)); // this (and Plot/Immortal) could be set in toolset creature properties, idk

	effect eDeath = EffectDeath(FALSE, TRUE, TRUE); // or EffectDamage() if prefered
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oDefender);
}
1 Like

Force the attack with actionattack, so AssignCommand(oAttacker,ActionAttack(oTarget))

And then have a script into the on phisycal attacked or on damaged field of the target that will kill it when it recieve the bullet.

2 Likes

Thanks for the replies! Yeah, I was thinking that maybe I have to go the animation route just like you suggested in your script @kevL_s. I just hope that the projectile/bullet is visible when the attack occurs.

@Shallina - I actually thought about this too, but I was afraid that maybe the attacker doesn’t hit the target right awayt. Then the scene will look really lame. Maybe one could wait for the attacker to hit, but I really want the bullet to hit right away. That’s why I believe it might be better to go with the animation route.

As I said, I just hope the bullet is visible and that it’s just not an animation of the attacker doing what looks like an attack (if that makes sense).

EDIT: Looking here:

Shouldn’t I be using “thrw_1attack01” as in Thrown Weapons? Or maybe the game recognizes what weapon is equipped and therefore you just need to use “1attack01”? Is that how it works @kevL_s ?

1 Like

Don’t forget the “*” → “*1attack01”
But yes, it tells the game to play the animation “1attack01” for the character independently of the race, gender and weapon (so you don’t have to switch between P_HHM_1hS, P_EEF_bow or P_DDM_thrw).

2 Likes

@andgalf i was wondering about the bullet too… needs test

ps. oops, looks like I got the delays messed up, but you could sort it out if things start working …

@4760 there should be a way of playing a projectile … arrow traps maybe ?

going with @Shallina’s idea, it’s likely possible to ensure the first attack hits w/ SetCombatOverrides() before the attack. And that should play the projectile auto …

Yep. I see it. I won’t.

I’m about to test your script ingame now @kevL_s . We’ll see how it looks.

So after a bit of testing and adjusting the camera angles, it seems like it kind of works, but the projectile/bullet is nowere to be seen (at least not the “right” bullet). Sadly, when I tested this now ingame it happened to be dark and it’s an outside area, so I’m not totally sure about all this. Thing is, this is a sci fi module, so there is a laser beam that is suppose to show up (I’m using the abandoned star wars module with the neat overrides with slings looking like blasters that shoot lasers. And it works in the module overall, but maybe it’s a different thing when there’s an animation to be played like this?). The animations with the throwing weapon works though and the target lies down dead.

Maybe I need to go Shallina’s route and using SetCombatOverrides?

Uuggh! I can’t get the script to compile (the assigncommand action attack function is somewow wrong) and I don’t quite know what I’m doing with the SetCombatOverrides function with all the integers that are supposed to be set without me knowing how to set them. Here’s how it looks at the moment:

/*
	This uses PlayCustomAnimation() to fake the attack, but it might be possible
	to do a real attack (possibly requiring SetCombatOverrides() to avoid
	triggering retaliation, not that it matters much since defender is going to
	die) without screwing up the attacker's Action queue if that's a
	consideration.

	just saying I haven't tested this, it's an idea
	
	script by kevL_s with modifications by andgalf
*/

void DoAttack(object oDefender);
void PlayAttack();
void Die(object oDefender);

void main()
{
	object oAttacker = GetObjectByTag("l_kenku9"); // TODO: tags ...
	object oDefender = GetObjectByTag("felkit");

	// attacker should have sling and ammo equipped (or whatever, it's generic)

	AssignCommand(oAttacker,ActionAttack(oTarget));
	SetCombatOverrides(oAttacker,oDefender,1,1,1,1,1,FALSE,FALSE,TRUE,TRUE);
	//AssignCommand(oAttacker, DoAttack(oDefender));

	DelayCommand(0.9f, Die(oDefender));
}


// OBJECT_SELF is attacker
void DoAttack(object oDefender)
{
	SetFacingPoint(GetPosition(oDefender));
	DelayCommand(0.3f, PlayAttack());
}

// OBJECT_SELF is attacker
void PlayAttack()
{
	PlayCustomAnimation(OBJECT_SELF, "*1attack01", FALSE);
}

void Die(object oDefender)
{
	SetPlotFlag(oDefender, FALSE);
	SetImmortal(oDefender, FALSE);
//	AssignCommand(oDefender, SetIsDestroyable(TRUE)); // this (and Plot/Immortal) could be set in toolset creature properties, idk

	effect eDeath = EffectDeath(FALSE, TRUE, TRUE); // or EffectDamage() if prefered
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oDefender);
}

more like this

void main()
{
	object oAttacker = GetObjectByTag("l_kenku9");
	object oDefender = GetObjectByTag("felkit");

	SetCombatOverrides(oAttacker, oDefender,
		1, 0,
		OVERRIDE_ATTACK_RESULT_HIT_SUCCESSFUL,
		9999, 9999,
		TRUE, TRUE, TRUE, TRUE);

	AssignCommand(oAttacker, ActionAttack(oDefender));
	DelayCommand(6.0, ClearCombatOverrides(oAttacker)); // not sure what delay, give it a round
}

 
ps. if you want a sling to shoot a lazerbolt, try whipping up a SpecialEffect (beam) and apply it …

:zzz:

Not tested, but I guess the attacking NPC could be given a magic sling (with a +20 attack bonus) and the target NPC a cursed armor (with a -20 armor class modifier). Except for the automatic miss with a roll of 1, the attacker should always hit!
And that way, no need for an animation, just use the standard attack action.

No, I want to use the lazerbolt the weapon already fires. The effect is already there so no need for any external fx. Here’s what it looks like and what I’m using if you’re wondering (this abandoned module has already been shared with the community in an old thread here somewhere, and the creator has given his consent to use it, which is why I’m using part of it. No need to reinvent the wheel or how they say…):

Ok, but then there’s still a small chance of a miss, and I want to avoid that if possible.

I’ll try out your new script suggestions @kevL_s.

That was why my function wouldn’t compile. I forgot to change oTarget to oDefender. :man_facepalming:

EDIT: I have tested kevL_s modifications now and it seems to work. The dead body seems to disappear immediately though. Might have something to do with how I’ve set “Decays”, I don’t know. Here’s how the whole script looks now then:

/*
	This uses PlayCustomAnimation() to fake the attack, but it might be possible
	to do a real attack (possibly requiring SetCombatOverrides() to avoid
	triggering retaliation, not that it matters much since defender is going to
	die) without screwing up the attacker's Action queue if that's a
	consideration.

	just saying I haven't tested this, it's an idea
	
	script by kevL_S
*/

void DoAttack(object oDefender);
void PlayAttack();
void Die(object oDefender);

void main()
{
	object oAttacker = GetObjectByTag("l_kenku9"); // TODO: tags ...
	object oDefender = GetObjectByTag("felkit");

	// attacker should have sling and ammo equipped (or whatever, it's generic)

	SetCombatOverrides(oAttacker, oDefender,
		1, 0,
		OVERRIDE_ATTACK_RESULT_HIT_SUCCESSFUL,
		9999, 9999,
		TRUE, TRUE, TRUE, TRUE);

	AssignCommand(oAttacker, ActionAttack(oDefender));
	DelayCommand(6.0, ClearCombatOverrides(oAttacker)); // not sure what delay, give it a round

	DelayCommand(0.9f, Die(oDefender));
}


// OBJECT_SELF is attacker
void DoAttack(object oDefender)
{
	SetFacingPoint(GetPosition(oDefender));
	DelayCommand(0.3f, PlayAttack());
}

// OBJECT_SELF is attacker
void PlayAttack()
{
	PlayCustomAnimation(OBJECT_SELF, "*1attack01", FALSE);
}

void Die(object oDefender)
{
	SetPlotFlag(oDefender, FALSE);
	SetImmortal(oDefender, FALSE);
//	AssignCommand(oDefender, SetIsDestroyable(TRUE)); // this (and Plot/Immortal) could be set in toolset creature properties, idk

	effect eDeath = EffectDeath(FALSE, TRUE, TRUE); // or EffectDamage() if prefered
	ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oDefender);
}

try it with literally just this, Ag

The OVERRIDE_ATTACK_RESULT_HIT_SUCCESSFUL ought to deliver 9999 pts damage. So there should be no need to call Die() … unless Plot/Immortal flags were set – if so, just remove them before SetCombatOverrides()

Ah, now I understand. Didn’t think about that.

EDIT: Alright, so I tested today again. Did some tweaking with cameras and whatnot. It works like a charm now, so thanks everyone here who’s tried to help!

1 Like