Jump to content

Home

A fight between PC and Party member


Pavlos

Recommended Posts


void main()
{
object oPC= GetFirstPC();
object oNPC= GetObjectByTag("kreia");
object oWeap= CreateItemOnObject("kre_light",oNPC);
AssignCommand (oNPC, ActionEquipItem(oWeap, INVENTORY_SLOT_RIGHTWEAPON));
SetMinOneHP(oPC, 1);
SetMinOneHP(oNPC, 1);
ChangeToStandardFaction(oNPC, STANDARD_FACTION_PREY);
ChangeToStandardFaction(oPC, STANDARD_FACTION_PREDATOR);
}
[/Code]

 

That much I can do on my own. However I am at a loss as to where to go next. What I wish to do is to start a fight between Kreia and the PC. I can equip kreia with a lightsaber and then set the PC hostile and her hostile but in such a way that everyone else should be neutral to them. However how do I make it so that when Kreia is down to 0VP the fight ends and it goes on to a new dialogue with her. I know how to resume a dialogue via a script it is just the bit inbetween. Also would I do the same thing as anyone suggests for the PC reaching 0VP only alter it slightly. I'd imagine it would involve local booleans and all that but I just can't fathom it! But I'm pleased with my progress anyway :) *Smiles to self while everyone sniggers*

Link to comment
Share on other sites

Well, I know absolutely nothing about scripting, but I do have a couple of questions/suggestions that may or may not be helpful:

 

1) Have you looked at the Secret Tomb fight to see how the devs did it? Is there source code referenced there that might be helpful?

 

2) Would it be possible to use existing "cheater" scripts (ala the giveitem script) to run this via a dialog without having to build your own code?

Link to comment
Share on other sites

I intended to look at the Handmaiden fights but DeNCS doesn't seem to be able to handle it. What do you mean in number two? I'm sorry I don't quite understand it.

 

Edit: Oh I see what you mean! Erm well I tried a_atkonend but all my party came in and attacked Kreia, lol. So I decided to make an all inclusive one. What my problem is that I cannot get the fight to stop! They just carry on fighting, I set them to invinisible to avoid Kreia being killed so I need to know how to start up 1 dialogue option when Kreia reaches 0VP and the other when the PC reaches 0VP. As I say I'd imagine it would have something to do with Local Booleans being set but how do I get it to recognise that the PC or Kreia is on 0VP? Would this have something to do with the heartbeat script? I don't want to change anymore than is necessary.

Link to comment
Share on other sites

SetMinOneHP(oPC, 1);

SetMinOneHP(oNPC, 1);

ChangeToStandardFaction(oNPC, STANDARD_FACTION_PREY);

ChangeToStandardFaction(oPC, STANDARD_FACTION_PREDATOR);

 

You can't change the faction of the player character (or any members of the active party). They are automatically set to a special "Party" faction when they are added to the active party that there is no scripting constant defined for.

 

If Kreia isn't in the active party, just set her to STANDARD_FACTION_HOSTILE1 instead and she'll attack the player (remove her from the active party first if she is in it). Set any nearby creatures you don't want to interfere to STANDARD_FACTION_NEUTRAL, or disable their AI. You can turn off their AI by setting Local Boolean 87 to TRUE on them.

 

 

how do I make it so that when Kreia is down to 0VP the fight ends and it goes on to a new dialogue with her.

 

Since SetMinOneHP(), which you used above, prevents the creature from dropping below 1 VP, it wouldn't be meaningful to check if they are down to 0 VP since they never will be. Also, 0 VP = Death, so you could just as well use GetIsDead() instead then. :)

 

Nitpicking aside, the easiest way is probably to alter the custom OnDamaged event script of Kreia so that it checks her current VP whenever she is hit during the fight (set a Global to indicate that the fight is on). When her current VP is down to 1, call ClearAllActions(), CancelCombat() and set Kreia's faction back to STANDARD_FACTION_FRIENDLY1 (or add her to the active party again).

 

The easiest way would be to check the player's hitpoints in Kreia's OnDamage event script as well, and end the fight if the player is near death too. While it'll only make the player lose if they manage to hit Kreia, it saves you an extra script since you can't change which AI scripts the player character uses (and it's unnessesary to bog down the generic AI scripts with extra code of this specific nature).

 

You may need to kickstart the battle as well, since sometimes the combat AI doesn't trigger if a creature turns hostile right in front of their enemy. You can do this by calling...

ExecuteScript("k_ai_master", oNPC, 1003);

Link to comment
Share on other sites


int StartingConditional()
{

object oNPC= GetObjectByTag("kreia");
int nCurHP= GetCurrentHitPoints(oNPC);

if ((nCurHP < 10))
{
ClearAllEffects();
ClearAllActions();
CancelCombat(oNPC);
ChangeToStandardFaction(oNPC, STANDARD_FACTION_FRIENDLY_1);
ActionDoCommand(ActionStartConversation(oNPC));
}


}
[/Code]

Would something like that work? I don't know what to put for an else I take it I need one. Is there a resume combat function? Any help would be appreciated.

Link to comment
Share on other sites

does anyone know how to script a fight between...

NPC Party member and NPC non-party member ?

 

 

example:

Atton fights the Twin Suns in the game

 

 

how does one go about isolating the NPC party member so you can control them and picking a fight with a NPC non-party member via script?

(and wouldnt there need to be some kind of exit scipt by the NPC non-party members death... i mean i dont want to be stuck controlling the NPC party member as the PC indefinately)

 

 

sorry to leech off your thread Pavlos, but the question is in related and a great place to ask :)

Link to comment
Share on other sites

(snip)

Would something like that work? I don't know what to put for an else I take it I need one. Is there a resume combat function? Any help would be appreciated.

 

If this is run as Kreia's OnDamaged event script (rather than as a dialog conditional script with seems to be the case, for some reason) you don't need to get object by tag, you can use OBJECT_SELF instead since she's the one running the script.

 

Further, ActionDoCommand(ActionStartConversation(oNPC)); is rather unnessesary to do. The ActionDoCommand() function adds a function call to the action queue of the object, but functions with named starting with Action... are already added to the action queue. Just...

ActionStartConversation(GetFirstPC());

... should work.

 

 

Since I don't know anything about the situation where this will be used it's hard to say if this does what you want, but I think a custom OnDamaged event script like the one below, assigned to Kreia, might work. You'll need to add a new global for this (i used ST_KREIA_FIGHT_ON in the example below) to globalcat.2da, and set this global to TRUE when the fight starts.

 

While that is the easy way, it might be better to alter the custom userdefined event script and catch the OnDamaged event there instead since you are modifying a standard game character. It's probably not a good idea to alter Kreia's template (both to avoid possible naming conflicts and to prevent you from having to start a new game for the change to take effect). Just make the below main() into a custom function instead (remember to remove the call to "k_ai_master if you do this). Then add it to k_oei_hench_inc.nss, call the new function from DoKreiaUserDef() under the OnDamaged (1006) case. You'll probably need to enable the custom OnDamaged event in the DoKreiaSpawnIn() too, by adding GN_SetSpawnInCondition(SW_FLAG_EVENT_ON_DAMAGED); somewhere near the top of that function.

 

#include "k_inc_switch"

void StopFighting(object oCreature=OBJECT_SELF) {
   AssignCommand(oCreature, ClearAllEffects());
   AssignCommand(oCreature, ClearAllActions());
   CancelCombat(oCreature);
   DelayCommand(0.4, SetMinOneHP(oCreature, FALSE));
}

void main() {
   if (GetGlobalBoolean("ST_KREIA_FIGHT_ON") && (GetCurrentHitPoints() < 10)) {
       SetGlobalBoolean("ST_KREIA_FIGHT_ON", FALSE);

       object oPC = GetFirstPC();
       SurrenderToEnemies();
       StopFighting();
       StopFighting(oPC);
       ChangeToStandardFaction(OBJECT_SELF, STANDARD_FACTION_FRIENDLY_1);

       NoClicksFor(0.5);
       DelayCommand(0.5, ActionStartConversation(oPC));
   }
   else {
       ExecuteScript("k_ai_master", OBJECT_SELF, KOTOR_HENCH_EVENT_ON_DAMAGE);
   }
} 

Link to comment
Share on other sites

I hate to sound terribly ignorant now but how would I add it to k_oei_hench_inc.nss as a custom function? Do I just put my script inside that one and compile? Also, though you know far better than me (For obvious reasons) surely your

 GetGlobalBoolean("ST_KREIA_FIGHT_ON") [/Code]

wouldn't work as it is not check whether or not it is active. Should it be:

[Code] (GetGlobalBoolean("ST_KREIA_FIGHT_ON") == TRUE [/Code]

?

I'm not going to use your script but hopefully build my own, I hate stealing other people's work. I just want to know whether that correction is, uh, correct and also how I go about adding the custom function. I'm really new to this whole concept. Thanks for all your help.

Link to comment
Share on other sites

I hate to sound terribly ignorant now but how would I add it to k_oei_hench_inc.nss as a custom function? Do I just put my script inside that one and compile?

 

Near the top of k_oei_hench_inc.nss, just after the function prototypes, add these two functions:

// ST: NEW FUNCTION! Add after the function prototypes near the top of k_oei_hench_inc.nss
void StopFighting(object oCreature=OBJECT_SELF) {
   AssignCommand(oCreature, ClearAllEffects());
   AssignCommand(oCreature, ClearAllActions());
   CancelCombat(oCreature);
   DelayCommand(0.4, SetMinOneHP(oCreature, FALSE));
}

// ST: NEW FUNCTION! Add after the function prototypes near the top of k_oei_hench_inc.nss
void SurrenderOnLostDuel() {
   if (GetGlobalBoolean("ST_KREIA_FIGHT_ON") && (GetCurrentHitPoints() < 10)) {
       SetGlobalBoolean("ST_KREIA_FIGHT_ON", FALSE);

       object oPC = GetFirstPC();
       SurrenderToEnemies();
       StopFighting();
       StopFighting(oPC);
       ChangeToStandardFaction(OBJECT_SELF, STANDARD_FACTION_FRIENDLY_1);

       NoClicksFor(0.5);
       DelayCommand(0.5, ActionStartConversation(oPC));
   }
}

 

Then go down and find the implementation of the function DoKreiaSpawnIn() and make the following changes to it:

// ST: THIS FUNCTION ALREADY EXISTS! Added line at the top...
void DoKreiaSpawnIn(object oPartyMember, string sModuleName) {
   // ST: Added this line to handle duel!
   GN_SetSpawnInCondition(SW_FLAG_EVENT_ON_DAMAGED);

   int In003EBO = (sModuleName == "003EBO");
   int In711KOR = (sModuleName == "711KOR");

   if (In003EBO && (GetGlobalBoolean("003_cutscene_mode") == FALSE)) {
       AssignCommand(oPartyMember, GN_SetSpawnInCondition(SW_FLAG_EVENT_ON_DIALOGUE_END));
       AssignCommand(oPartyMember, ActionPlayAnimation(ANIMATION_LOOPING_MEDITATE, 1.0, -1.0));
   }
   else if (In711KOR) {
       GN_SetSpawnInCondition(SW_FLAG_EVENT_ON_DAMAGED);
       SetMinOneHP(oPartyMember,TRUE);
   }
}

 

Then find the implementation of the function DoKreiaUserDef() and make these changes to it:

// ST: THIS FUNCTION ALREADY EXISTS! Added call to custom function at ONDAMAGED event.
void DoKreiaUserDef(object oPartyMember,int pUserEvent, string sModuleName) {
   int In003EBO = (sModuleName == "003EBO");
   int In711KOR = (sModuleName == "711KOR");

   if (In711KOR) {
       Do711UserDef(oPartyMember, pUserEvent);
       return;
   }

   if (In003EBO && (GetGlobalBoolean("003_cutscene_mode") == FALSE)) {
       switch(pUserEvent) {
           case 1001://HEARTBEAT
           case 1002://PERCEIVE
           case 1003://END OF COMBAT
           case 1004://ON DIALOGUE
           case 1005://ATTACKED
           case 1006://DAMAGED
               // ST: Added call to custom function here...
               SurrenderOnLostDuel();
               break;
           case 1007://DEATH
           case 1008://DISTURBED
           case 1009://BLOCKED
           case 1010://SPELL CAST AT
               break;
           case 1011: //DIALOGUE END
               AssignCommand(oPartyMember, ActionPlayAnimation(ANIMATION_LOOPING_MEDITATE, 1.0, -1.0));
               break;
           case 1100://HOSTILE RETREAT
               AssignCommand(oPartyMember, UT_ReturnToBase());
               break;
       }
   }
}

 

Now, since the k_oei_hench_inc.nss file is an include file and not a stand-alone script you'll need to recompile the two scripts that use it that are relevant for this task. Save your modified k_oei_hench_inc.nss in the same folder as nwnnsscomp.exe and then recompile the scripts k_oei_spawn.nss and k_oei_userdef.nss. Put the resulting NCS files in override.

 

Also, though you know far better than me (For obvious reasons) surely your

 GetGlobalBoolean("ST_KREIA_FIGHT_ON") [/Code]

wouldn't work as it is not check whether or not it is active. Should it be:
[Code] (GetGlobalBoolean("ST_KREIA_FIGHT_ON") == TRUE [/Code]
?

 
GetGlobalBoolean already returns a valid boolean value used as a parameter in the if-statement, it's unnessesary to do a check that produces the same result in this case. If the boolean is FALSE, GetGlobalBoolean() will return FALSE already, just like (GetGlobalBoolean() == FALSE) would.
 
And, in the cases of LocalBooleans it's dangerous to check directly if the value equals TRUE, since that function seems to either return FALSE or !FALSE (not FALSE). I.e. TRUE in NWScript is a constant with the value 1 and FALSE is a constant with value 0, but that function for some reason often return either 0 (FALSE) or a much larger value (which evaulates to a true boolean value, but not the NWScript TRUE constant). Any number other than 0 evaluates to a logical [b]true[/b] value in nwscript, while a value only equals TRUE (as in the constant) if it's 1 and nothing else.
 
For example:
[code]
int nTest = 12;

if (nTest) {
   // This is run, since the test is true..
}

if (nTest == TRUE) {
   // This is not run, since 12 (bTest) does not equal 1 (TRUE)
}

Link to comment
Share on other sites

Wow thanks for your help but still it wont work. I have the following script for activation in my dialogue:


void main()
{
object oNPC= GetObjectByTag("kreia");
object oWeap= CreateItemOnObject("kre_light",oNPC);
AssignCommand (oNPC, ActionEquipItem(oWeap, INVENTORY_SLOT_RIGHTWEAPON));
ChangeToStandardFaction(oNPC, STANDARD_FACTION_HOSTILE_1);
SetGlobalBoolean("ST_KREIA_FIGHT_ON", TRUE);
}
[/Code]

Then I made the changes that you suggested and Kreia wont stop fighting! I have to kill her! GAH! It is probably something really obvious that I have gotten wrong but I can't think what.

Link to comment
Share on other sites

Oh stupid me! I need to re-enter the module as the script for all the characters has changed. It works now. Do you mind if I use your changes? Thanks for all your help! Do you know how I would get it to result differently for a PC getting down to a certain level of health? Thanks once more!

Link to comment
Share on other sites

  • 3 years later...

Another way to get two creatures to fight and for everyone else to leave them alone is to set them as Predator and Prey. This makes them hostile to each other but neutral to everyone else. Check the last post in this thread to help you out.

Link to comment
Share on other sites

Archived

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

×
×
  • Create New...