Jump to content

Home

A death animation that won't kill my NPC?


Ulic and Cay

Recommended Posts

Is there a death animation that won't kill my NPC? I have the script below fire several times during a dialog that I initiate with my "210_Atallo" character. At some point during the conversation I jump him elsewhere and show him being killed by another NPC (see case 2). The thing is this NPC's death immediately ends the conversation I had running and I want it to continue for a little longer. At least I think that's what's happening. So how can I get away with faking his death and then really killing him when the conversation ends so I can come across his body later? I can't seem to find a "fake death" animation although I could just be missing it. Also if my conversation is aborting for some other reason let me know.

 

location ST_GetLoc(string sWP);
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF);
void sub3(object objectParam1);
void main() {
object oAtallo = GetObjectByTag("210_Atallo");
object oCzerka = GetObjectByTag("czerkaguard01");
int nParam1 = GetScriptParameter(1);
switch (nParam1){
	case 0: {
		object oDoor = GetObjectByTag("Airlock3a");
		AssignCommand(oCzerka, ActionEquipItem(CreateItemOnObject("w_blaste_03",oCzerka), 4));
		SetGlobalFadeOut (0.0, 1.0);
		ActionCloseDoor(oDoor);
		SetLocked(oDoor, 1);
		SetLocalBoolean(GetObjectByTag("TermAirlock3", 0), 30, 0);
	}
	return;
	case 1: {
		ST_JumpToPoint("WP_Atadeath", oAtallo);
		ST_JumpToPoint("WP_Czerdeath", oCzerka);
		SetGlobalFadeIn (0.2, 1.0);
		DelayCommand(0.5, AssignCommand(oAtallo, ActionForceMoveToLocation(GetLocation(GetObjectByTag("WP_Atadeath1")))));
	}
	return;
	case 2: {
		ChangeToStandardFaction(oAtallo, 2);
		SetCommandable(1, oCzerka);
		AssignCommand(oCzerka, ClearAllActions());
		ChangeToStandardFaction(oCzerka, 4);
		SetMinOneHP(oCzerka, 1);
		DelayCommand(0.5, AssignCommand(oCzerka, ActionDoCommand(sub3(oAtallo))));
		DelayCommand(1.1, AssignCommand(oCzerka, ActionDoCommand(CutsceneAttack(oAtallo, 217, 3, GetCurrentHitPoints(oAtallo)))));
		SetGlobalFadeOut (2.5, 1.0);
	}
	return;
	case 3: {
		ST_JumpToPoint("WP_Czerkalou", oCzerka);
		ChangeToStandardFaction(oCzerka, 1);
		ActionTakeItem(GetItemPossessedBy(oCzerka, "w_blaste_03"), oCzerka);
		SetGlobalFadeIn (0.2, 1.0);
	}
	return;
}
}
location ST_GetLoc(string sWP) {
       return GetLocation(GetObjectByTag(sWP));
}
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF) {
       SetCommandable(TRUE, oJumper);
       AssignCommand(oJumper, JumpToLocation( ST_GetLoc(sWP) ));
}
void sub3(object objectParam1) {
SetMinOneHP(objectParam1, 0);
ApplyEffectToObject(0, EffectDamage((GetCurrentHitPoints(objectParam1) - 1), 8, 0), objectParam1, 0.0);
ApplyEffectToObject(1, EffectAssuredHit(), OBJECT_SELF, 3.0);
ActionAttack(objectParam1, 0);
}

Link to comment
Share on other sites

I jump him elsewhere and show him being killed by another NPC (see case 2). The thing is this NPC's death immediately ends the conversation I had running and I want it to continue for a little longer.

 

The easiest solution to this is to make another object than your doomed NPC be the conversation owner, and just set that NPCs tag in the Speaker field of the nodes it should by saying. This way the conversation won't end if the character dies.

 

You can either do this by creating an invisible placeable and have it initiate the dialog with the player, or by having the script make the player initiate conversation with themselves.

 

void main() {
   object oPC = GetFirstPC();
   object oCut = CreateObject(OBJECT_TYPE_PLACEABLE, "[color=Yellow]mycuttalker[/color]", GetLocation(oPC));
   DelayCommand(0.5, AssignCommand(oCut, ActionStartConversation(oPC, "[color=Red]mycutdialog[/color]", FALSE, 0, TRUE)));
}

 

...or...

 

void main() {
   object oPC = GetFirstPC();
   AssignCommand(oPC, ActionStartConversation(oPC, "[color=Red]mycutdialog[/color]", FALSE, 0, TRUE));
}

 

And:

 

location ST_GetLoc(string sWP);
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF);
void AttackAndKill(object oVictim);


void main() {
   object oAtallo = GetObjectByTag("210_Atallo");
   object oCzerka = GetObjectByTag("czerkaguard01");

   switch (GetScriptParameter(1)){
       case 0: {
           object oDoor = GetObjectByTag("Airlock3a");
           AssignCommand(oCzerka, ActionEquipItem( CreateItemOnObject("w_blaste_03", oCzerka), INVENTORY_SLOT_RIGHTWEAPON) );
           SetGlobalFadeOut (0.0, 1.0);
           AssignCommand(oDoor, ActionCloseDoor(oDoor));
           SetLocked(oDoor, TRUE);
           SetLocalBoolean(GetObjectByTag("TermAirlock3"), 30, FALSE);
       }
       break;

       case 1: {
           ST_JumpToPoint("WP_Atadeath", oAtallo);
           ST_JumpToPoint("WP_Czerdeath", oCzerka);
           SetGlobalFadeIn (0.2, 1.0);
           DelayCommand(0.5, AssignCommand(oAtallo, ActionForceMoveToLocation( ST_GetLoc("WP_Atadeath1") )));
       }
       break;

       case 2: {
           ChangeToStandardFaction(oAtallo, STANDARD_FACTION_FRIENDLY_1);
           SetCommandable(TRUE, oCzerka);
           AssignCommand(oCzerka, ClearAllActions());
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_FRIENDLY_2);
           SetMinOneHP(oCzerka, TRUE);

           // [color=PaleGreen]ST: These two lines do essentially the same thing. Better safe than sorry?  [/color]
           DelayCommand(0.5, AssignCommand(oCzerka, ActionDoCommand(AttackAndKill(oAtallo))));
           DelayCommand(1.1, AssignCommand(oCzerka, ActionDoCommand(CutsceneAttack(oAtallo, 217, ATTACK_RESULT_AUTOMATIC_HIT, GetCurrentHitPoints(oAtallo)))));
           SetGlobalFadeOut (2.5, 1.0);
       }
       break;

       case 3: {
           ST_JumpToPoint("WP_Czerkalou", oCzerka);
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_HOSTILE_1);
           DestroyObject(GetItemPossessedBy(oCzerka, "w_blaste_03"));
           SetGlobalFadeIn (0.2, 1.0);
       }
       break;
   }
}


location ST_GetLoc(string sWP) {
       return GetLocation(GetObjectByTag(sWP));
}


void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF) {
       SetCommandable(TRUE, oJumper);
       AssignCommand(oJumper, JumpToLocation( ST_GetLoc(sWP) ));
}


void AttackAndKill(object oVictim) {
   SetMinOneHP(oVictim, FALSE);
   ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(GetCurrentHitPoints(oVictim) - 1), oVictim);
   ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAssuredHit(), OBJECT_SELF, 3.0);
   ActionAttack(oVictim);
}

Link to comment
Share on other sites

I thought about that and tried something similar. I created a placeable where my NPC was but I couldn't select it, only my NPC. I may have done something wrong though. Is that what you're suggesting I do? Create a placeable near my NPC and have it fire one of those scripts above "on use"? Or would I fire one of them for my NPC's on dialog?

Link to comment
Share on other sites

I thought about that and tried something similar. I created a placeable where my NPC was but I couldn't select it, only my NPC. I may have done something wrong though. Is that what you're suggesting I do? Create a placeable near my NPC and have it fire one of those scripts above "on use"? Or would I fire one of them for my NPC's on dialog?

 

You would fire it from whever you currently fire the conversation with the NPC who will end up killed. If it's just the player starting conversation with them normally then you'll have to give the NPC a custom OnDialog event script that makes your placeable start the conversation rather than the NPC itself when the NPC is selected/activated.

Link to comment
Share on other sites

That's what I thought and I tried that, having your second script fire for that NPC's "on dialog", and I couldn't get it to work. It didn't fire the conversation, it just made it impossible to bring up the menu or interact with anything like I was in a conversation. But it seems like it should work so I'm sure I've done something wrong. I'll take another look. Thanks again for all your help. I'll post again if I can't figure it out.

Link to comment
Share on other sites

Yeah I can't get it to work at all. Its that same problem I described before, nothing is selectable and the conversation won't fire. Do you think its a problem with my dialog, which will fire fine if I leave the default ondialog script alone, or is it a scripting problem? I'm really at a loss here. Anymore suggestions would be appreciated.

Link to comment
Share on other sites

That's what I thought and I tried that, having your second script fire for that NPC's "on dialog", and I couldn't get it to work. It didn't fire the conversation, it just made it impossible to bring up the menu or interact with anything like I was in a conversation. But it seems like it should work so I'm sure I've done something wrong. I'll take another look. Thanks again for all your help. I'll post again if I can't figure it out.

 

Make sure the placeable you use is not set as "static". Try this variant as an OnDialog script. Replace the things marked in yellow with the tag of the placeable and Resref/filename of the DLG file:

 

#include "k_inc_generic"
#include "k_inc_switch"

object ST_GetNearestEnemy(object oSource = OBJECT_SELF);

void main() {
   int nMatch = GetListenPatternNumber();
   if (GN_GetSpawnInCondition( SW_FLAG_EVENT_ON_DIALOGUE_INTERRUPT )) {
       if (nMatch == -1)
           ResetDialogState();

       SignalEvent(OBJECT_SELF, EventUserDefined(1004));
       return;
   }

   if (!GN_GetSpawnInCondition(SW_FLAG_AI_OFF)) {
       object oShouter = GetLastSpeaker();
       object oIntruder;
       object oAttacker = GetLastHostileActor(oShouter);
       object oPC = GetFirstPC();
       object oDummy = GetObjectByTag("[color=Yellow]PlaceableTag[/color]");

       if (!GetIsObjectValid(oAttacker) 
           || GetIsDead(oAttacker) 
           || !GetObjectSeen(oAttacker, oShouter)
           || !GetIsEnemy(oAttacker, oShouter))      
       {
           if (GetCommandable()) {
               if (nMatch == -1) {
                   ClearAllActions();

                   if (oShouter == oPC) {
                       AssignCommand(oDummy, ActionStartConversation(oPC, "[color=Yellow]mycutdialog[/color]", FALSE, 0, TRUE));
                   }
                   else {
                       if (GN_GetSpawnInCondition( SW_FLAG_ON_DIALOGUE_COMPUTER ))
                           ActionStartConversation(GetFirstPC(), "", FALSE, CONVERSATION_TYPE_COMPUTER);
                       else
                           BeginConversation();
                   }

                   return;
               }
               else if ((nMatch != -1) 
                   && GetIsObjectValid(oShouter) 
                   && !GetIsPC(oShouter) 
                   && GetIsFriend(oShouter))
               {
                   if (nMatch >= 1) {
                       oIntruder = GetLastHostileActor(oShouter);
                       if (!GetIsObjectValid(oIntruder)) {
                           oIntruder = GetAttemptedAttackTarget();
                           if (!GetIsObjectValid(oIntruder)) {
                               oIntruder = GetAttemptedSpellTarget();
                               if (!GetIsObjectValid(oIntruder)) { 
                                   oIntruder = ST_GetNearestEnemy();
                                   if (!GetIsObjectValid(oIntruder))
                                       oIntruder = OBJECT_INVALID;
                               }
                           }
                       }
                   }

                   GN_RespondToShout(oShouter, nMatch, oIntruder);
               }
           }
       }
   }

   if (nMatch == -1)
       ResetDialogState();

   if (GN_GetSpawnInCondition( SW_FLAG_EVENT_ON_DIALOGUE ))
       SignalEvent(OBJECT_SELF, EventUserDefined(1004));
}


object ST_GetNearestEnemy(object oSource = OBJECT_SELF) {
   int nIdx = 1;
   object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSource, nIdx, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);  

   while (GetIsObjectValid(oEnemy) && (GetIsDead(oEnemy) || (GetCurrentHitPoints(oEnemy) < 1)) )
       oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSource, ++nIdx, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);   

   if (GetIsDead(oEnemy) || (GetCurrentHitPoints(oEnemy) < 1)) 
       return OBJECT_INVALID;

   return oEnemy;
}

Link to comment
Share on other sites

When I try and compile it it has a problem with line 54: "Undeclared Identifier"

oIntruder = ST_GetNearestEnemy();

Can you give me that sub string?

 

Oops, must have used the OnDialog script from my tweaked AI as base for that. I've updated the script in the above post with that custom function, hopefully that should be enough. :)

Link to comment
Share on other sites

That didn't do it either. Still the same problem. I tried it a few different ways; having the placeable already in the module, creating it by tweaking the ondialog script above, having it launch a different dialog, all to no avail.

 

That's weird. Did you set the Speaker fields to the tag of the dialog participants in your dialog file, and the dialog scripts not to use OBJECT_SELF for anything that refers to the participants (since the placeable becomes the dialog owner)?

 

Have you tried, for testing purposes, to initiate conversation directly with the placeable instead of the NPC and seen if it works then (you need to make it usable, set the dialog in the Conversation field and set a dialog starting script in the OnUsed event script field).

 

If you can't get that to work for some weird reason either, have you tried making the player initiate conversation with themselves, rather than use a placeable?

Link to comment
Share on other sites

I'll address these in bullet points in the order you suggested them.

 

I've got the dialog set up correctly with the correct speaker's tag in the Speaker field. (I don't need to have something in the Listener field for the replies do I?) I don't think any of my scripts use "OBJECT_SELF". However, to make sure that I didn't mess something up I created a much smaller dialog with no scripts and the correct Speaker and Listener tags for every line (including the Listener replies) . It still wouldn't fire.

 

Initiating the conversation directly with the placeable works fine, for both my shortened test dialog and my full, original, dialog.

 

I also have tried having the player initiate the conversation directly with themselves rather than the placeable by using the second script you suggested

void main() {
   object oPC = GetFirstPC();
   AssignCommand(oPC, ActionStartConversation(oPC, "mycutdialog", FALSE, 0, TRUE));
}

I also tweaked the longer OnDialog variant you provided to have the player initiate the conversation directly with themselves. It still didn't work.

 

 

It seems that any change I make to my NPC's OnDialog script will result in this problem. I changed it to this script:

void main() {
ActionStartConversation(GetPartyMemberByIndex(0), "", 0, 0, 1);
}

Which should fire his dialog right? But it doesn't, it has the same problem. This makes me think that it might have something to do with the NPC itself. Is that possible?

 

So now I'm at even more of a loss.

Link to comment
Share on other sites

Because I couldn't get the "OnDialog" for my NPC to work I tried setting up a trigger that will fire the dialog (making the PC the conversation owner) when the PC gets near the NPC. Here's the script:

void main() {
if ((GetGlobalNumber("201TEL_Q_Yima") ==2)) {
	object oPC = GetFirstPC();
	AssignCommand(oPC, ActionStartConversation(oPC, "210atallo", FALSE, 0, TRUE));
}
}

Again the dialog will play fine until the attack plays out at which point it fades to black and the dialog ends. Here's the script I'm using:

location ST_GetLoc(string sWP);
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF);
void ST_Attack(object oAttackee, int intParam2);
void ST_AssignCommand(object oAttacker, object oAttackee, int intParam3);
void ST_ChangeFaction(object oAttacker, int intParam2);

void main() {
object oAtallo = GetObjectByTag("210_Atallo");
object oCzerka = GetObjectByTag("czerkaguard01");
switch (GetScriptParameter(1)){
case 0: {
	object oDoor = GetObjectByTag("Airlock3a");
	AssignCommand(oCzerka, ActionEquipItem( CreateItemOnObject("w_blaste_03", oCzerka), INVENTORY_SLOT_RIGHTWEAPON) );
	SetGlobalFadeOut (0.0, 1.0);
	AssignCommand(oDoor, ActionCloseDoor(oDoor));
	SetLocked(oDoor, TRUE);
	SetLocalBoolean(GetObjectByTag("TermAirlock3"), 30, FALSE);
}
break;
case 1: {
	ST_JumpToPoint("WP_Atadeath", oAtallo);
	ST_JumpToPoint("WP_Czerdeath", oCzerka);
	SetGlobalFadeIn (0.2, 1.0);
	DelayCommand(0.5, AssignCommand(oAtallo, ActionForceMoveToLocation( ST_GetLoc("WP_Atadeath1") )));
}
break;
case 2: {
	ActionDoCommand(ChangeToStandardFaction(oCzerka, STANDARD_FACTION_HOSTILE_1));
	ChangeToStandardFaction(oAtallo, 2);
	ST_ChangeFaction(oCzerka, 4);
	DelayCommand(0.5, ST_AssignCommand(oCzerka, oAtallo, 0));
	SetGlobalFadeOut (2.0, 1.0);
}
break;
case 3: {
	ST_JumpToPoint("WP_Czerkalou", oCzerka);
	ChangeToStandardFaction(oCzerka, STANDARD_FACTION_FRIENDLY_1);
	DestroyObject(GetItemPossessedBy(oCzerka, "w_blaste_03"));
	SetGlobalFadeIn (0.2, 1.0);
}
break;
}
}

location ST_GetLoc(string sWP) {
return GetLocation(GetObjectByTag(sWP));
}
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF) {
SetCommandable(TRUE, oJumper);
AssignCommand(oJumper, JumpToLocation( ST_GetLoc(sWP) ));
}
void ST_Attack(object oAttackee, int intParam2) {
if (intParam2) {
	SetMinOneHP(oAttackee, 1);
	ApplyEffectToObject(0, EffectDamage((GetCurrentHitPoints(oAttackee) - 1), 8, 0), oAttackee, 0.0);
}
ApplyEffectToObject(1, EffectAssuredHit(), OBJECT_SELF, 3.0);
ActionAttack(oAttackee, 0);
}
void ST_AssignCommand(object oAttacker, object oAttackee, int intParam3) {
if (((!GetIsObjectValid(oAttacker)) || (!GetIsObjectValid(oAttackee)))) {
	return;
}
AssignCommand(oAttacker, ActionDoCommand(ST_Attack(oAttackee, intParam3)));
}
void ST_ChangeFaction(object oAttacker, int intParam2) {
if ((!GetIsObjectValid(oAttacker))) {
	return;
}
SetCommandable(1, oAttacker);
AssignCommand(oAttacker, ClearAllActions());
ChangeToStandardFaction(oAttacker, intParam2);
SetMinOneHP(oAttacker, 1);
}

 

Am I setting up the factions wrong or something? What possible reason would there be for the attack not to play out?

Link to comment
Share on other sites

Am I setting up the factions wrong or something? What possible reason would there be for the attack not to play out?

 

Is this what is meant to happen?

  1. Give Czerka guard a blaster, close and lock airlock door, fade to black
  2. Warp Atollo to the waypoint with the tag WP_Atadeath, warp the guard to the waypoint with the tag WP_Czerdeath, make Atollo walk towards the waypoint with tag WP_Atadeath1after half a second. Fade in.
  3. Make Atollo and the Guard hostile to each other, make the guard impossible to kill, and make it kill Atollo. Fade to black again after 2 seconds.
  4. Fade in again, warp the guard to the waypoint with tag WP_Czerkalou, make him friendly to the player and take away his blaster.

 

How are you firing the different stages of the script? From different dialog nodes that have some delay between each is run? Are you running any other scripts on those dialog nodes as well? Have you checked carefully that you are using tags and resrefs in the correct places, and that there are no typos?

 

Try this and see if it makes any difference:

 

location ST_GetLoc(string sWP);
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF);
void ST_Kill(object oAttackee);


void main() {
   object oAtallo = GetObjectByTag("210_Atallo");
   object oCzerka = GetObjectByTag("czerkaguard01");


   switch (GetScriptParameter(1)){
       case 0: {
           object oDoor = GetObjectByTag("Airlock3a");
           AssignCommand(oCzerka, ActionEquipItem( CreateItemOnObject("w_blaste_03", oCzerka), INVENTORY_SLOT_RIGHTWEAPON, TRUE) );
           SetGlobalFadeOut (0.0, 1.0);
           AssignCommand(oDoor, ActionCloseDoor(oDoor));
           SetLocked(oDoor, TRUE);
           SetLocalBoolean(GetObjectByTag("TermAirlock3"), 30, FALSE);
       }
       break;

       case 1: {
           ST_JumpToPoint("WP_Atadeath", oAtallo);
           ST_JumpToPoint("WP_Czerdeath", oCzerka);
           SetGlobalFadeIn (0.2, 1.0);
           DelayCommand(0.5, AssignCommand(oAtallo, ActionForceMoveToLocation( ST_GetLoc("WP_Atadeath1") )));
       }
       break;

       case 2: {
           ChangeToStandardFaction(oAtallo, STANDARD_FACTION_GIZKA_1);
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_GIZKA_2);
           SetMinOneHP(oCzerka, TRUE);         
           DelayCommand(0.5, AssignCommand(oCzerka, ST_Kill(oAtallo)));
           DelayCommand(2.0, SetGlobalFadeOut (2.0, 1.0));
       }
       break;

       case 3: {
           ST_JumpToPoint("WP_Czerkalou", oCzerka);
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_FRIENDLY_1);
           DestroyObject(GetItemPossessedBy(oCzerka, "w_blaste_03"));
           SetGlobalFadeIn (0.2, 1.0);
       }
       break;
   }
}

location ST_GetLoc(string sWP) {
   return GetLocation(GetObjectByTag(sWP));
}


void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF) {
   AssignCommand(oJumper, SetCommandable(TRUE, oJumper));
   AssignCommand(oJumper, JumpToLocation( ST_GetLoc(sWP) ));
}


void ST_Kill(object oAttackee) {
   SetMinOneHP(oAttackee, FALSE);
   SetPlotFlag(oAttackee, FALSE);

   ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectAssuredHit(), OBJECT_SELF, 6.0);

   SetCommandable(TRUE);
   ClearAllActions();
   ActionAttack(oAttackee);
   DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAttackee));
}

Link to comment
Share on other sites

Yeah that's almost what's supposed to happen. The order of the fades is a little confused. It should look like this:

1. Give Czerka guard a blaster, fade to black to cover up the close and lock of the airlock door

2. Warp Atollo to the waypoint with the tag WP_Atadeath, warp the guard to the waypoint with the tag WP_Czerdeath, set fade in from black, make Atollo walk towards the waypoint with tag WP_Atadeath1 after half a second.

3. Make Atollo and the Guard hostile to each other, make the guard impossible to kill, and make it kill Atollo, fade to black again after Atallo is dead.

4. Warp the guard to the waypoint with tag WP_Czerkalou, make him friendly to the player and take away his blaster, fade in again/end dialog.

 

I tried the script you provided. The fades are a little off but that can be fixed, however, it still won't show the two NPCs fighting (the Czerka guard and Atallo) just like before. Sometimes I'll get one blaster bolt, or the beginning of a blaster bolt, from the guard but that's it.

Yes you're right the different stages of the script are fired from different dialog nodes. No other scripts are set to run on those dialog nodes. I'm almost sure that the tags and resrefs are in the correct places and that there are no typos. All the NPCs move to the correct waypoints at the correct times. Everything plays correctly aside from the fight.

I really appreciate all your help and if you have any more suggestions I would love to try them but in the mean time I'm just gonna throw in a fade out. Its not what I was hoping for but it kinda works.

Link to comment
Share on other sites

I tried the script you provided. The fades are a little off but that can be fixed, however, it still won't show the two NPCs fighting (the Czerka guard and Atallo) just like before. Sometimes I'll get one blaster bolt, or the beginning of a blaster bolt, from the guard but that's it.

 

Probably a timing issue then. NWScript is horrible at getting carefully timed sequences to play out the same every time, in particular when the action queue is involved. It's a bit like trying to paint a portrait while having to use a broom as brush. :)

 

The "proper" way of handling this would probably be to give Atollo a custom OnDamaged event script that checks when he's actually hit by the guard, and kill and fade from there. However, if you want to keep your cutscene actions confined to one script you can probably fake it reasonably by repeatedly checking if he's been hit, and then kill+fade. That way you wouldn't get the fade until he's actually been hit and killed. Just make sure you set the delay on the dialog node firing the fight part of the script a bit higher to give it some wiggle room before it proceeds to the next section of the script.

 

Try this, which attempts to do the above:

location ST_GetLoc(string sWP);
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF);
void ST_Kill(object oAttackee);
void ST_DoAtolloDeath(object oAtollo, int iHP);


void main() {
   object oAtallo = GetObjectByTag("210_Atallo");
   object oCzerka = GetObjectByTag("czerkaguard01");


   switch (GetScriptParameter(1)){
       case 0: {
           SetGlobalFadeOut (0.0, 1.0);
           object oDoor = GetObjectByTag("Airlock3a");
           AssignCommand(oCzerka, ActionEquipItem( CreateItemOnObject("w_blaste_03", oCzerka), INVENTORY_SLOT_RIGHTWEAPON, TRUE) );
           AssignCommand(oDoor, ActionCloseDoor(oDoor));
           SetLocked(oDoor, TRUE);
           SetLocalBoolean(GetObjectByTag("TermAirlock3"), 30, FALSE);
       }
       break;

       case 1: {
           ST_JumpToPoint("WP_Atadeath", oAtallo);
           ST_JumpToPoint("WP_Czerdeath", oCzerka);
           SetGlobalFadeIn (0.2, 1.0);
           DelayCommand(0.5, AssignCommand(oAtallo, ActionForceMoveToLocation( ST_GetLoc("WP_Atadeath1") )));
       }
       break;

       case 2: {
           ChangeToStandardFaction(oAtallo, STANDARD_FACTION_GIZKA_1);
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_GIZKA_2);
           SetMinOneHP(oCzerka, TRUE);         
           DelayCommand(0.5, AssignCommand(oCzerka, ST_Kill(oAtallo)));
       }
       break;

       case 3: {
           ST_JumpToPoint("WP_Czerkalou", oCzerka);
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_FRIENDLY_1);
           DestroyObject(GetItemPossessedBy(oCzerka, "w_blaste_03"));
           SetGlobalFadeIn (0.2, 1.0);
       }
       break;
   }
}


location ST_GetLoc(string sWP) {
   return GetLocation(GetObjectByTag(sWP));
}


void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF) {
   AssignCommand(oJumper, SetCommandable(TRUE, oJumper));
   AssignCommand(oJumper, JumpToLocation( ST_GetLoc(sWP) ));
}


void ST_DoAtolloDeath(object oAtollo, int iHP) {
   if (GetIsDead(oAtollo) || (iHP > GetCurrentHitPoints(oAtollo))) {
       ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAtollo);
       DelayCommand(1.0, SetGlobalFadeOut (2.0, 1.0));
   }
   else {
       DelayCommand(0.5, ST_DoAtolloDeath(oAtollo, iHP));
   }
}


void ST_Kill(object oAttackee) {
   SetMinOneHP(oAttackee, FALSE);
   SetPlotFlag(oAttackee, FALSE);

   ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageImmunityDecrease( DAMAGE_TYPE_BLASTER, 100 ), oAttackee);
   ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAssuredHit(), OBJECT_SELF, 12.0);

   SetCommandable(TRUE);
   ClearAllActions();
   ST_DoAtolloDeath(oAttackee, GetCurrentHitPoints(oAttackee));
   ActionAttack(oAttackee);
}

Link to comment
Share on other sites

The fight plays! Thank you so much! But there's a new problem now. Apparently the dialog nodes after the fight don't play. This prevents the last stage of my script from firing and leaves the fadeout set and the player in total darkness. I know the last stage isn't firing because if I remove the fadeout and fadein calls the Czerka guard won't jump away. I've done some cheating to correct this by altering the script but its just that, cheating. I have no idea why the rest of the dialog nodes abort. Like painting "a portrait while having to use a broom as brush", that's one valid description. I personally feel like I've been trying to drive a nail with my head :). Anyway the altered script looks like this:

location ST_GetLoc(string sWP);
void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF);
void ST_Kill(object oAttackee);
void ST_DoAtolloDeath(object oAtollo, int iHP);


void main() {
   object oAtallo = GetObjectByTag("210_Atallo");
   object oCzerka = GetObjectByTag("czerkaguard01");


   switch (GetScriptParameter(1)){
       case 0: {
           SetGlobalFadeOut (0.0, 1.0);
           object oDoor = GetObjectByTag("Airlock3a");
           AssignCommand(oCzerka, ActionEquipItem( CreateItemOnObject("w_blaste_03", oCzerka), INVENTORY_SLOT_RIGHTWEAPON, TRUE) );
           AssignCommand(oDoor, ActionCloseDoor(oDoor));
           SetLocked(oDoor, TRUE);
           SetLocalBoolean(GetObjectByTag("TermAirlock3"), 30, FALSE);
       }
       break;

       case 1: {
           ST_JumpToPoint("WP_Atadeath", oAtallo);
           ST_JumpToPoint("WP_Czerdeath", oCzerka);
           SetGlobalFadeIn (0.2, 1.0);
           DelayCommand(0.5, AssignCommand(oAtallo, ActionForceMoveToLocation( ST_GetLoc("WP_Atadeath1") )));
       }
       break;

       case 2: {
           ChangeToStandardFaction(oAtallo, STANDARD_FACTION_GIZKA_1);
           ChangeToStandardFaction(oCzerka, STANDARD_FACTION_GIZKA_2);
           SetMinOneHP(oCzerka, TRUE);         
           DelayCommand(0.5, AssignCommand(oCzerka, ST_Kill(oAtallo)));
           DelayCommand(6.0, ST_JumpToPoint("WP_Czerkalou", oCzerka));
           DelayCommand(6.0, ChangeToStandardFaction(oCzerka, STANDARD_FACTION_FRIENDLY_1));
           DelayCommand(6.0, DestroyObject(GetItemPossessedBy(oCzerka, "w_blaste_03")));
           DelayCommand(7.0, SetGlobalFadeIn (0.0, 1.0));
       }
       break;
   }
}


location ST_GetLoc(string sWP) {
   return GetLocation(GetObjectByTag(sWP));
}


void ST_JumpToPoint(string sWP, object oJumper=OBJECT_SELF) {
   AssignCommand(oJumper, SetCommandable(TRUE, oJumper));
   AssignCommand(oJumper, JumpToLocation( ST_GetLoc(sWP) ));
}


void ST_DoAtolloDeath(object oAtollo, int iHP) {
   if (GetIsDead(oAtollo) || (iHP > GetCurrentHitPoints(oAtollo))) {
       ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAtollo);
       DelayCommand(1.0, SetGlobalFadeOut (2.0, 1.0));
   }
   else {
       DelayCommand(0.5, ST_DoAtolloDeath(oAtollo, iHP));
   }
}


void ST_Kill(object oAttackee) {
   SetMinOneHP(oAttackee, FALSE);
   SetPlotFlag(oAttackee, FALSE);

   ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamageImmunityDecrease( DAMAGE_TYPE_BLASTER, 100 ), oAttackee);
   ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAssuredHit(), OBJECT_SELF, 12.0);

   SetCommandable(TRUE);
   ClearAllActions();
   ST_DoAtolloDeath(oAttackee, GetCurrentHitPoints(oAttackee));
   ActionAttack(oAttackee);
}

Thanks again for all your help, and if something obvious strikes you let me know, I'm more than willing to try out any of your always helpful suggestions, otherwise this plays out almost exactly like I wanted it to and I'm happy with that.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...