Jump to content

Home

Need help with mod


wasa7

Recommended Posts

Hello all, and thanks in advance to those who may reply to this Thread.

 

I've been trying to make a mod that spawns a Sith Patrol right outside the Hideout in Taris. Sith Patrol equals one Red Sith Patrol Leader and two Silver Sith Troppers. I've been reading a lot of the Holowans tutorials but I'm still missing some important things to make it work. I have a lot of questions too.

 

Until now, I have the trigger that will fire on entering to the area. I have this script attached to it. Don't know if it works. Is not completed.

 

void main()
{

//How do I check if Bastila has been rescued from the Black Bulkars

 	int nCreatureSpawned = GetGlobalBoolean("Sith_Patrol_Check"); // Boolean created in the globalcat.2da for 									 this use only
 	if (nCreatureSpawned) { return; } // it will exit if TRUE

float x1=86.8399963378906; // coordinates from cheat console 'whereami'
   	float y1=104.660003662109; 
   	float z1=0.00; 

float r1=0.0f; // orientation in degrees. How do I get this? What is that letter f?
   	vector MyVec1 = Vector(x1,y1,z1); // positioning vector

   	float x2=88.2699966430664; 
   	float y2=102.180000305176; 
   	float z2=0.00; 

float r2=0.0f;
   	vector MyVec2 = Vector(x2,y2,z2);  

   	float x3=89.0500030517578; 
   	float y3=103.519996643066; 
   	float z3=0.00; 

   	float r3=0.0f; 
  	vector MyVec3 = Vector(x3,y3,z3); 


   	location SLoc1 = Location(MyVec1, r1); // create location for creature
   	object oSithL=CreateObject( OBJECT_TYPE_CREATURE, "s_patrol_leader", SLoc1); // spawn creature Sith Patrol 												Leader in the location

   	location SLoc2 = Location(MyVec2, r2); //
   	object oSithT1=CreateObject( OBJECT_TYPE_CREATURE, "s_trooper", SLoc2); //


   	location SLoc3 = Location(MyVec3, r3); //
   	object oSithT2=CreateObject( OBJECT_TYPE_CREATURE, "s_trooper", SLoc3); //


 	SetGlobalBoolean("my_global_bool",TRUE); // this prevent creature from spawning again

}

 

From that script, how do I check if Bastila have been rescued? I checked the boolean list and found one that may work but I compare two saved games, one before and after having Bastila and it was the same for both so...

 

Then I need another trigger around the created creatures, that will open the dialogue between the Sith Patrol Leader and the PC. After that, the fight. And finally, a dialogue between PC and Bastilla. If someone could help me or maybe point me in the right direction would be appreciated. Thank you all again.

Link to comment
Share on other sites

I've been trying to make a mod that spawns a Sith Patrol right outside the Hideout in Taris. Sith Patrol equals one Red Sith Patrol Leader and two Silver Sith Troppers. I've been reading a lot of the Holowans tutorials but I'm still missing some important things to make it work. I have a lot of questions too.

 

From that script, how do I check if Bastila have been rescued?

 

It should be enough to check if she's available as a party member, that will imply that she has been rescued since she's not available in the party before then. :) You could write that script like:

object SpawnNPCAtLocation(string sResRef, float x, float y, float r);

void main() {
   if (IsAvailableCreature(NPC_BASTILA) && !GetGlobalBoolean("Sith_Patrol_Check")) {
       SpawnNPCAtLocation("s_patrol_leader", 86.84, 104.66, 0.0);
       SpawnNPCAtLocation("s_trooper", 88.27, 102.18, 0.0);
       SpawnNPCAtLocation("s_trooper", 89.05, 103.52, 0.0);
       SetGlobalBoolean("Sith_Patrol_Check",TRUE);
   }
}

object SpawnNPCAtLocation(string sResRef, float x, float y, float r) {
   location lLoc = Location(Vector(x, y, 0.0), r);
   return CreateObject(OBJECT_TYPE_CREATURE, sResRef, lLoc);
}

 

Then I need another trigger around the created creatures, that will open the dialogue between the Sith Patrol Leader and the PC.

 

You could put that in the OnPerception AI script of the patrol leader. If he perceives the player approach and start conversation... That custom OnPerception script could look something like:

void main() {
   if (!GetLocalBoolean(OBJECT_SELF, 31) && (GetLastPerceived() == GetFirstPC())) {
       ClearAllActions();
       SetLocalBoolean(OBJECT_SELF, 31, TRUE);
       ActionStartConversation(GetFirstPC(), "sithdialog", FALSE, CONVERSATION_TYPE_CINEMATIC, TRUE);
   }
   else {
       ExecuteScript("k_ai_master", OBJECT_SELF, 1002);
   }   
}

 

That should engage dialog mode directly when he spots the player (to prevent them from running away). If you want them to move closer and not shout from wherever they are do that via a script set on the first dialog node.

Link to comment
Share on other sites

Gee thank you Stoffe, didn't hope to get such a fast answer. I also hope not be a bother but I have new questions.

 

You could put that in the OnPerception AI script of the patrol leader. If he perceives the player approach and start conversation...

Where on the Patrol Leader should that script be placed? I checked the NPC .uti in the script section and there are a lot of script sections (i.e. onheartbeat, onnotice, etc...). I copied this .uti from another module and it has a lot of scripts (default ones I think) so wich one shoul I replace? Onnotice?

 

That should engage dialog mode directly when he spots the player (to prevent them from running away). If you want them to move closer and not shout from wherever they are do that via a script set on the first dialog node.

Do I have to specify waypoints for the NPC to come closer to the PC? I want the whole Patrol to come closer to the PC, how do I specify that?

 

Thank you again for the help!

Link to comment
Share on other sites

Where on the Patrol Leader should that script be placed? I checked the NPC .uti in the script section and there are a lot of script sections (i.e. onheartbeat, onnotice, etc...).

 

Yes, it's called OnNotice for some reason. Compile your custom Perception AI script under a new ResRef and put the name of the script in the OnNotice box. (By the way I just noticed the name of the global didn't match where it was set and where it was checked. I fixed that in the revised spawn script in the above post.)

 

Do I have to specify waypoints for the NPC to come closer to the PC? I want the whole Patrol to come closer to the PC, how do I specify that?

 

A simple dialog script to move closer (2 meters for leader, 2.5 meters for grunts) to the player:

void main() {
   object oLeader = GetObjectByTag("[color=Yellow]PatrolLeaderTag[/color]");
   object oTroop1 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]");
   object oTroop2 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]", 1);
   object oPlayer = GetFirstPC();

   AssignCommand(oLeader, ActionMoveToObject(oPlayer, TRUE, 2.0));
   AssignCommand(oTroop1, ActionMoveToObject(oPlayer, TRUE, 2.5));
   AssignCommand(oTroop2, ActionMoveToObject(oPlayer, TRUE, 2.5));
}

 

A simple dialog script to make them attack the player if added to one of the end nodes of a DLG:

#include "k_inc_generic"

void main() {
   object oLeader = GetObjectByTag("[color=Yellow]PatrolLeaderTag[/color]");
   object oTroop1 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]");
   object oTroop2 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]", 1);
   object oPlayer = GetFirstPC();

   ChangeToStandardFaction(oLeader, STANDARD_FACTION_HOSTILE_1);
   ChangeToStandardFaction(oTroop1, STANDARD_FACTION_HOSTILE_1);
   ChangeToStandardFaction(oTroop2, STANDARD_FACTION_HOSTILE_1);

   AssignCommand(oLeader, GN_DetermineCombatRound(oPlayer));
   AssignCommand(oTroop1, GN_DetermineCombatRound(oPlayer));
   AssignCommand(oTroop2, GN_DetermineCombatRound(oPlayer));
}

 

An example OnDeath event script for the Sith Troops/Leader that might work to fire a dialog between Bastila and the main character when the Sith Patrol are all dead. You'll need to assign the script to the OnDeath event slot for both the Leader and the Trooper UTCs:

void StartPlayerBanter() {
   int i;
   for (i = 0; i < GetPartyMemberCount(); i++) {
       object oParty = GetPartyMemberByIndex(i);
       AssignCommand(oParty, ClearAllActions());
       CancelCombat(oParty);
   }

   object oPC = GetFirstPC();
   if (GetDistanceToObject(oPC) > 10.0) || !GetObjectSeen(oPC)) {
       ActionJumpToObject(oPC);
   }

   ActionStartConversation(oPC, "[color=PaleGreen]PostCombatDLG[/color]", FALSE, CONVERSATION_TYPE_CINEMATIC, TRUE);
}

void main() {
   object oLeader = GetObjectByTag("[color=Yellow]PatrolLeaderTag[/color]");
   object oTroop1 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]");
   object oTroop2 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]", 1);

   if ((!GetIsObjectValid(oLeader) || GetIsDead(oLeader))
       && (!GetIsObjectValid(oTroop1) || GetIsDead(oTroop1))
       && (!GetIsObjectValid(oTroop2) || GetIsDead(oTroop2)))
   {
       object oBastilaah = GetObjectByTag("Bastila");
       if (GetIsObjectValid(oBastilaah) && IsObjectPartyMember(oBastilaah)) {
           AssignCommand(oBastilaah, DelayCommand(2.0, StartPlayerBanter()));
       }
   }

   ExecuteScript("k_ai_master", OBJECT_SELF, 1007);
}

 

In all the above scripts, substitute the parts in yellow with the tags specified in your Sith Leader and Sith Trooper templates. There is a field for the Tag in the UTC files, it does not necessarily match the ResRef/Filename. Make sure the tags for your templates are unique and not shared by any other NPCs in the game world. The part in green should be replaced by the ResRef of your DLG file containing the after-battle chatter with Bastila.

 

(Warning: The above scripts are untested since I don't have the ability to run the game now to see if they work. If you get any errors please let me know and I'll see if I can spot what's wrong.)

Link to comment
Share on other sites

Hello Stoffe, how are things going?

Thanks a lot for the codes, I've studied them so I can understand them. I've made all the arranges so they are compatible with each other, put the right names, etc. Now all I need is to compile them and see if there are any errors. If they are, surely I'll let you know.

 

You've been very helpfull Stoffe, you're name will be in the "Thanks to" part inside the mod when released.

Link to comment
Share on other sites

(Warning: The above scripts are untested since I don't have the ability to run the game now to see if they work. If you get any errors please let me know and I'll see if I can spot what's wrong.)

 

void StartPlayerBanter() {
   int i;
   for (i = 0; i < GetPartyMemberCount(); i++) {
       object oParty = GetPartyMemberByIndex(i);
       AssignCommand(oParty, ClearAllActions());
       CancelCombat(oParty);
   }

   object oPC = GetFirstPC();
   if (GetDistanceToObject(oPC) > 10.0) || !GetObjectSeen(oPC)) {
       ActionJumpToObject(oPC);
   }

   ActionStartConversation(oPC, "[color=PaleGreen]PostCombatDLG[/color]", FALSE, CONVERSATION_TYPE_CINEMATIC, TRUE);
}

void main() {
   object oLeader = GetObjectByTag("[color=Yellow]PatrolLeaderTag[/color]");
   object oTroop1 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]");
   object oTroop2 = GetObjectByTag("[color=Yellow]PatrolTroopTag[/color]", 1);

   if ((!GetIsObjectValid(oLeader) || GetIsDead(oLeader))
       && (!GetIsObjectValid(oTroop1) || GetIsDead(oTroop1))
       && (!GetIsObjectValid(oTroop2) || GetIsDead(oTroop2)))
   {
       object oBastilaah = GetObjectByTag("Bastila");
       if (GetIsObjectValid(oBastilaah) && IsObjectPartyMember(oBastilaah)) {
           AssignCommand(oBastilaah, DelayCommand(2.0, StartPlayerBanter()));
       }
   }

   ExecuteScript("k_ai_master", OBJECT_SELF, 1007);
}

 

Hello again Stoffe, I compiled the codes and they all did fine except for this one. It give me a syntax error at "||" and it does not create the .ncs file. I wish I could solve this myself but I don't know what does it mean :)

Link to comment
Share on other sites

Hello again Stoffe, I compiled the codes and they all did fine except for this one. It give me a syntax error at "||" and it does not create the .ncs file. I wish I could solve this myself but I don't know what does it mean :)

 

There was a missing start paranthesis at the beginning of that if statement. Try the below version, it should compile. (Don't forget to change the tags to those of your Sith trooper characters and of the dialog file to start after the battle as well before compiling or it won't work as it should.)

 

void StartPlayerBanter() {
   int i;
   for (i = 0; i < GetPartyMemberCount(); i++) {
       object oParty = GetPartyMemberByIndex(i);
       AssignCommand(oParty, ClearAllActions());
       CancelCombat(oParty);
   }

   object oPC = GetFirstPC();
   if ((GetDistanceToObject(oPC) > 10.0) || !GetObjectSeen(oPC)) {
       ActionJumpToObject(oPC);
   }

   ActionStartConversation(oPC, "PostCombatDLG", FALSE, CONVERSATION_TYPE_CINEMATIC, TRUE);
}

void main() {
   object oLeader = GetObjectByTag("PatrolLeaderTag");
   object oTroop1 = GetObjectByTag("PatrolTroopTag");
   object oTroop2 = GetObjectByTag("PatrolTroopTag", 1);

   if ((!GetIsObjectValid(oLeader) || GetIsDead(oLeader))
       && (!GetIsObjectValid(oTroop1) || GetIsDead(oTroop1))
       && (!GetIsObjectValid(oTroop2) || GetIsDead(oTroop2)))
   {
       object oBastilaah = GetObjectByTag("Bastila");
       if (GetIsObjectValid(oBastilaah) && IsObjectPartyMember(oBastilaah)) {
           AssignCommand(oBastilaah, DelayCommand(2.0, StartPlayerBanter()));
       }
   }

   ExecuteScript("k_ai_master", OBJECT_SELF, 1007);
}

Link to comment
Share on other sites

Ok Stoff, almost seems to be ready. Last thing needed is to attach the spawning script to the module. I tried including a modified .git file into the override folder but crazy things happened. So, and this is not my idea, how about replacing an area script with the one you made and from that script make a call of the original one? An ExecuteScript would be required. This is what I did:

 

object SpawnNPCAtLocation(string sResRef, float x, float y, float r);

void main() 
{
   if (IsAvailableCreature(NPC_BASTILA) && !GetGlobalBoolean("Sith_Patrol_Check")) 
   {
       SpawnNPCAtLocation("my_sith_patrol_leader", 86.84, 104.66, 0.0);
       SpawnNPCAtLocation("my_sith_trooper", 88.27, 102.18, 0.0);
       SpawnNPCAtLocation("my_sith_trooper", 89.05, 103.52, 0.0);
       SetGlobalBoolean("Sith_Patrol_Check",TRUE);
       ExecuteScript("k_ptar_rodiantrg"); // This is the new line! 
   }
}

object SpawnNPCAtLocation(string sResRef, float x, float y, float r) 
{
   location lLoc = Location(Vector(x, y, 0.0), r);
   return CreateObject(OBJECT_TYPE_CREATURE, sResRef, lLoc);
}

It gives me the followin error:

Required argument missing in call to "ExecuteScript". What am I doing wrong?

 

EDIT: I found that what is missing is something like this:

ExecuteScript("k_ptar_rodiantrg", OBJECT_SELF, ####);

What numbers should I put after oject_self?

Link to comment
Share on other sites

Ok Stoff, almost seems to be ready. Last thing needed is to attach the spawning script to the module. I tried including a modified .git file into the override folder but crazy things happened.

 

Yes, never put GIT files in the override folder since it for some reason have higher priority than savegames, causing the GIT file containing the current area state to be ignored when loading the savegame. Also take care to use a GFF editor that handles the new Vector and Orientation field types, or the CameraList in the GIT file will get messed up when you modify the file.

 

If you need to modify the GIT file of an area you'll need to either put the modified GIT file back into the module's RIM file, or repackage the whole module as a MOD file, whichever you prefer.

 

That said, you don't set the event scripts of the area in the .GIT file, but in the .ARE file in the module. But it's probably a good idea not to put those in the override folder either, since many modules for some reason have ARE files with the same name, and putting one in the override folder will override them all. Put those back in the module RIM as well, or repackage as a MOD.

 

So, and this is not my idea, how about replacing an area script with the one you made and from that script make a call of the original one? An ExecuteScript would be required. This is what I did:

(snip)

SpawnNPCAtLocation("my_sith_patrol_leader", 86.84, 104.66, 0.0);

(snip)

ExecuteScript("k_ptar_rodiantrg"); // This is the new line!

(snip)

It gives me the followin error:

Required argument missing in call to "ExecuteScript". What am I doing wrong?

EDIT: I found that what is missing is something like this:

ExecuteScript("k_ptar_rodiantrg", OBJECT_SELF, ####);

What numbers should I put after oject_self?

 

If you want to replace a current script to fire your own, name your script exactly what the one you wish to replace was named. Then extract that original script, name it something else and put it in the override folder along with your new script. Then have your script execute the renamed file. If you use this variant, test it thoroughly in-game since I've noticed that there are some problems with ExecuteScript() not working properly under some unknown circumstances.

 

Anyway, as to your script, the first parameter to ExecuteScript() is the ResRef of the script to run, the second is the object who should run the script, and the third is an optional parameter to send to that script. Unless the script you replace requires any such parameters you should just leave out the third parameter entirely.

 

Another thing though, on the other line quoted above, marked in red, the ResRef of your UTC file is too long. It can be at most 16 characters in length, while yours is 21. You'll need to shorten it down to 16 characters, and rename your UTC file correspondingly, or it will not work properly.

Link to comment
Share on other sites

Ok, I tested the mod and it works but the results are not entirely the ones that we were especting. First, I had to replace the "k_ptar_rodiantrg.ncs", this is the script I took the name of. With out it, the messenger from Canderous, the twileek, will never show up. That's ok for the moment. Other thing, even if Bastila is not in the party, a Sith Patrol shows up. Even worst, when she's in the party, it triggers like 20 Sith Patrols in the main hall outside the hideout. What could be wrong? The global boolean? I've read all the codes again trying to find something wrong. I understand if you get tired of this, I'm getting frustrated my self, but the mod is almost done. Thank you again!

Link to comment
Share on other sites

First, I had to replace the "k_ptar_rodiantrg.ncs", this is the script I took the name of. With out it, the messenger from Canderous, the twileek, will never show up.

 

This is why you should extract the original script, rename it, and then run the renamed copy with ExecuteScript from within your new script. That way both will run.

 

 

Other thing, even if Bastila is not in the party, a Sith Patrol shows up.

 

The script only checks if she has been rescued (i.e. as joined your group), not if she's in the active party with the player, so that is not so strange. If you want to check if she's in the party with the player as well, add an extra condition to the if-statement like:

if (IsAvailableCreature(NPC_BASTILA) && IsNPCPartyMember(NPC_BASTILA) && !GetGlobalBoolean("Sith_Patrol_Check")) {

 

 

Even worst, when she's in the party, it triggers like 20 Sith Patrols in the main hall outside the hideout. What could be wrong? The global boolean?

 

I'd guess you have forgotten to add the global boolean to globalcat.2da. If you haven't the value you set to it will never be stored and thus it will always return FALSE. Also doublecheck that the name of the global is identical both where it is set and where it is changed.

 

Further, if this is supposed to be an OnEnter script of an area you must check that the entering object is the player as well. Since the OnEnter script fires whenever any creature is spawned into the area it will trigger once for every sith patrol you spawn in as well, in turn spawning 3 more who in turn spawn three more etc... Only triggering it for the player character solves that.

 

So, you'd end up with something like this as spawn script (don't forget to change the StrRefs of the troopers to the names you use):

object SpawnNPCAtLocation(string sResRef, float x, float y, float r);

void main() {
   if ((GetEnteringObject() == GetFirstPC())
       && IsAvailableCreature(NPC_BASTILA) 
       && IsNPCPartyMember(NPC_BASTILA)
       && !GetGlobalBoolean("Sith_Patrol_Check")) 
   {
       SpawnNPCAtLocation("s_patrol_leader", 86.84, 104.66, 0.0);
       SpawnNPCAtLocation("s_trooper", 88.27, 102.18, 0.0);
       SpawnNPCAtLocation("s_trooper", 89.05, 103.52, 0.0);
       SetGlobalBoolean("Sith_Patrol_Check",TRUE);
   }

   ExecuteScript("k_real_rodiantrg", OBJECT_SELF);
}

object SpawnNPCAtLocation(string sResRef, float x, float y, float r) {
   location lLoc = Location(Vector(x, y, 0.0), r);
   return CreateObject(OBJECT_TYPE_CREATURE, sResRef, lLoc);
}

Link to comment
Share on other sites

Hello Stoffe, here am I again :)

 

This is why you should extract the original script, rename it, and then run the renamed copy with ExecuteScript from within your new script. That way both will run.

I did this the first time, something's happening that it just doesn't work! This is what I did:

 

object SpawnNPCAtLocation(string sResRef, float x, float y, float r);

void main() 
{
   ExecuteScript("[color=DarkOrange]k_ptar_rodiantrg2[/color]", OBJECT_SELF);

   if ((GetEnteringObject() == GetFirstPC())
       && IsAvailableCreature(NPC_BASTILA) 
       && IsNPCPartyMember(NPC_BASTILA)
       && !GetGlobalBoolean("[color=Yellow]S_Patrol_Check[/color]")) 
   {
       SetGlobalBoolean("[color=Yellow]S_Patrol_Check"[/color],TRUE);
       SpawnNPCAtLocation("s_ptrl_ldr", 86.84, 104.66, 90.0);
       SpawnNPCAtLocation("s_trpr", 88.27, 102.18, 85.0);
       SpawnNPCAtLocation("s_trpr", 89.05, 103.52, 93.0);
   }
}

object SpawnNPCAtLocation(string sResRef, float x, float y, float r) {
   location lLoc = Location(Vector(x, y, 0.0), r);
   return CreateObject(OBJECT_TYPE_CREATURE, sResRef, lLoc);
}

I've checked the name of the global variable, both on the globalcat.2da and the script above. After I kill the Sith army we just spawned in the main hall, and reenter the area, they won't appear anymore so I think this boolean is working right.

 

So, what do we have? If the PC enters alone this area, the script won't fire. That's ok. If he enters with party members (Bastila not included), the script won't fire. I will change that it in the future, and I will add some options in the .dlg so they won't attack me unless Bastila is with the PC. But when Bastila is included:

 

1.- Sith army is spawned

 

2.- Original script won't trigger, even if I put the executescript line. I think somethig is missing there, like:

ExecuteScript("k_ptar_rodiantrg2", OBJECT_SELF, "some_other_parameter");

 

3.-When dialog triggers, Sith Patrol runs towards you, is there a way to make them walk?

 

4.-After you kill one patrol, another dialog corresponding another patrol will trigger and so on until you kill all patrols spawned.

 

5.-All Sith dead, dialog between PC and Bastila won't trigger.

 

I hope you're not so tired of helping me. If you want I can send you all the files so you can check what's wrong. If not, I will continue to test it untill it works just as I want it. Thanks a lot for all the help.

Link to comment
Share on other sites

ExecuteScript("k_ptar_rodiantrg2", OBJECT_SELF);

 

Same problem here, a ResRef can be at most 16 characters long, k_ptar_rodiantrg2 is 17 characters long. You'll need to shorten the name of the original modified script or it won't run properly.

 

3.-When dialog triggers, Sith Patrol runs towards you, is there a way to make them walk?

 

Change TRUE to FALSE in the ActionMoveToObject() function calls in the script that makes the troopers move. This will make them walk instead.

 

4.-After you kill one patrol, another dialog corresponding another patrol will trigger and so on until you kill all patrols spawned.

 

Uh? I'm not sure I understand what you mean here. Does more than one patrol spawn? Is this intentional or is it a bug? If more than one patrol should spawn, should they also talk, or are they reinforcements?

 

5.-All Sith dead, dialog between PC and Bastila won't trigger.

 

Have you assigned the script starting that dialog to the OnDeath event slot of all the Sith Troopers? Have you set the ResRef of the DLG file properly in the ActionStartConversation() call in that script? Make sure the name of the DLG file is not longer than 16 characters. Make sure you have set the tags of the troopers properly in that script as well. Make sure all the troops really have been killed and there aren't any lurking somewhere. Make sure their tags are unique for that UTC and not shared by other characters.

 

If you've checked all those and it still doesn't work you could try an alternate approach to detecting if everyone is dead. You could create a "trooper counter" global var and give the troopers a new OnSpawn script that increases that counter by 1 when spawned, and make the OnDeath scripts reduce it by 1. And when it reaches 0, start the conversation.

Link to comment
Share on other sites

You could create a "trooper counter" global var and give the troopers a new OnSpawn script that increases that counter by 1 when spawned, and make the OnDeath scripts reduce it by 1. And when it reaches 0, start the conversation.

 

Instead of using both OnSpawn & OnDeath, I use OnDeath to have trooper check if any are left (GetIsObjectValid), then if all are dead, set a boolean var to indicate death, then check for it from the spawn script so they only spawn once.

Link to comment
Share on other sites

IT WORKS! IT'S ALIVE! MUA JA JA JA!!!

 

Hahaha it finally works Stoff, at least par of it. The Sith Patrol spawns at the perfect spot, the original script triggers at the right moment, when I approuch the Sith soldiers, the dialog starts and they walk towars me, and then they get agressives so other kind of negotiation are required. That's perfect!

 

They are only a few bugs to correct. The Sith Patrol spaws everytime, something is not working correctly with the bloody boolean. I'm still working on that. To be more specific, if I reenter the area without Bastila, a new patrol spawns. If Bastila is with me, two patrols (two patrols = six Sith soldiers) will appear at the selected spot. It gets serious if you don't kill those soldiers as they remain in the area. If you reenter ten times, you'll have 30 Sith soldiers. The dialog between Bastila and PC just won't trigger. I check all the things you said but I'm still going through the codes to see if I find something wrong.

 

Well, that's it. You'll have to give you addres so I can send you a Christmas or a Holiday Card for having such patience with me lol. Thank you again :)

 

EDIT: By the way, hello Agent Xim, good to see you around here! Thank you for your help too.

Link to comment
Share on other sites

Ok Stoffe, the bloody boolean works! Hehe, yep you were right about that something was wrong in the conception of the global variable itself. I'm not sure why but the globalcat.2da file wasn't saving as it should so,... anyways, now I got it working. I'm still thinking how to arrange the dialog between Bastila and Pc. Take care!

Link to comment
Share on other sites

I'm still thinking how to arrange the dialog between Bastila and Pc.

 

Try this slightly modified variant of the OnDeath script of the troopers. As before, modifiy the part colored in yellow with the name of the DLG file (without the .dlg extension) to start after the battle is over, and the parts in blue with the proper tags of your Troopers (as set in their UTC files).

 

I've tested this script and it triggers the conversation when all the hostiles have died in my game.

 

The only thing that changed is that I added a slight delay before the conversation was triggered, since the StartConversation action was flushed from the action queue when Bastila exited combat mode for some reason if it was issued directly after. NWScript can be rather peculiar at times. :)

 

void StartPlayerBanter() {
   int i;
   for (i = 0; i < GetPartyMemberCount(); i++) {
       object oParty = GetPartyMemberByIndex(i);
       AssignCommand(oParty, ClearAllActions());
       CancelCombat(oParty);
   }

   object oPC = GetFirstPC();
   if ((GetDistanceToObject(oPC) > 10.0) || !GetObjectSeen(oPC)) {
       ActionJumpToObject(oPC);
   }

   NoClicksFor(1.0);
   DelayCommand(1.0, ActionStartConversation(oPC, "[color=Yellow]BastilaDlg[/color]", FALSE, CONVERSATION_TYPE_CINEMATIC, TRUE));
}

void main() {
   object oLeader = GetObjectByTag("[color=SkyBlue]PatrolLeader[/color]");
   object oTroop1 = GetObjectByTag("[color=SkyBlue]PatrolGrunt[/color]");
   object oTroop2 = GetObjectByTag("[color=SkyBlue]PatrolGrunt[/color]", 1);

   if ((!GetIsObjectValid(oLeader) || GetIsDead(oLeader))
       && (!GetIsObjectValid(oTroop1) || GetIsDead(oTroop1))
       && (!GetIsObjectValid(oTroop2) || GetIsDead(oTroop2)))
   {
       object oBastilaah = GetObjectByTag("Bastila");
       if (GetIsObjectValid(oBastilaah) && IsObjectPartyMember(oBastilaah)) {
           AssignCommand(oBastilaah, DelayCommand(2.0, StartPlayerBanter()));
       }
   }

   ExecuteScript("k_ai_master", OBJECT_SELF, 1007);
}

 

If that still doesn't work then you've done things different somewhere else than I did when I tested. :)

Link to comment
Share on other sites

Try this slightly modified variant of the OnDeath script of the troopers.

Hello Stoffe. What can I say? The code above worked just fine. THANK YOU! A LOT! I REALLY MEAN IT! The whole mod works perfectly. The dialogs trigger at the perfect time. I'm working on the dialogs so feel as part of the original game. I think you're going to be proud of it.

 

I can't think a better way to thank you that, from now long, to make mods for Kotor and Kotor TSL. I've learned a lot with what you've gave me. If you ever need something, a mod tester or whatever, just ask ok? Thank you again. I'll let you know when the mod is released.

Link to comment
Share on other sites

Hello Stoffe, remember me? how are things going?

I found recently that you're not a he but a she, I'm sorry for not knowing that before he he :)

 

Since my mod, I've been testing some other changes to the game. Right now I'm trying to modify Agent Xim's mod Operation Kill Bastila (OPK) (so far for my personal use only) but the results are not as I spected. I wonder if you could help me again with this.

 

The mod as it is, make all Sith Trooper to attack if Bastila is a party member. They all turn hostile when you enter the area but it looks weird because they stand in their places just waiting for you to come. What I've been trying to do is to make them walk normally as they usually do (this I did it ok) and when they notice the PC and Bastila, they become hostile (this is what I'm still working on). I made a code to put in the Onnotice field that check if Bastila is a party member, then turn hostile, or else, act normally by calling the original but renamed onnotice script just as you taught me. This is what I did:

 

#include "k_inc_debug"
#include "k_inc_generic"
#include "k_inc_tar"

void main()
{
  object oCreature = GetLastPerceived();

  if (GetLastPerceptionSeen() && GetIsPC(oCreature))
  {
     object oPlayer = GetFirstPC();

     if ((!TAR_GetWearingSithArmor()) 
     && (IsNPCPartyMember(NPC_BASTILA) == TRUE) 
     && (GetDistanceBetween(GetPCSpeaker(), GetObjectByTag("bastila")) <= 10.0) 
     || (GetIsObjectValid(GetItemPossessedBy(GetFirstPC(), "ptar_shieldcodes")))) 
     { 
        ActionDoCommand(SetFacingPoint(GetPosition(oCreature)));
        ExecuteScript("[color=Yellow]tar_gohostile[/color]", OBJECT_SELF);
     }


     if ((TAR_GetWearingSithArmor()) 
     && (!GetIsObjectValid(GetItemPossessedBy(GetFirstPC(), "ptar_shieldcodes")))) 
     {
        ExecuteScript("tar_goneutral", OBJECT_SELF);
     }

  }

  else
  {
     ExecuteScript("[color=Orange]k_old_percept01[/color]", OBJECT_SELF);
  }

}

 

The structure of the code is a combination of the original OPK code with an on_notice code I found on the web. I tried using the one you gave but it didn't work either. The yellow code is the original code (it works) that make the Sith Troopers to become hostile and the orange code is the original but renamed onnotice code. What do you think? Sorry to bother you again and I thank you in advance for your help. See ya and take care!

Link to comment
Share on other sites

The structure of the code is a combination of the original OPK code with an on_notice code I found on the web. I tried using the one you gave but it didn't work either. The yellow code is the original code (it works) that make the Sith Troopers to become hostile and the orange code is the original but renamed onnotice code.

 

A few things I spotted:

  • You use GetPCSpeaker() for distance check, but that function is only valid to use during a dialog. It returns the object the caller is in conversation with. Since you want to check distance from the one running the script (OBJECT_SELF), I'd use the GetDistanceToObject() function instead.
     
     
  • I'm not 100% sure how it works in KotOR, but believe GetIsPC() only returns true if the object passed to it is the player character. Thus Bastila could run around alone unmolested as long as the the player character keeps out of sight. Better to check for all party members instead, then it will trigger even if Bastila is running around alone.
     
     
  • Finally, it's probably better to execute k_ai_master directly with the parameter set to 1002 (i.e. triggering its OnPerception code). This is since all k_def_percept01 does is to execute k_ai_master. This way you save one script and one step of execution.

 

With that you might end up with a modified script looking something like:

#include "k_inc_debug"
#include "k_inc_generic"
#include "k_inc_tar"

int HasShieldCodes(object oPossessor) {
   return GetIsObjectValid( GetItemPossessedBy(oPossessor, "ptar_shieldcodes") );
}

void main() {
   object oSeen = GetLastPerceived();
object oPC = GetFirstPC();

   if (GetLastPerceptionSeen() && IsObjectPartyMember(oSeen)) {
       if (HasShieldCodes(oPC)
           || (!TAR_GetWearingSithArmor() 
               && IsNPCPartyMember(NPC_BASTILA) 
               && (GetDistanceToObject( GetObjectByTag("Bastila") ) <= 10.0))) 
       { 
           ActionDoCommand(SetFacingPoint(GetPosition(oSeen)));
           ExecuteScript("tar_gohostile", OBJECT_SELF);
           return;
       }
       else if (TAR_GetWearingSithArmor() && !HasShieldCodes(oPC)) {
           ExecuteScript("tar_goneutral", OBJECT_SELF);
           return;
       }

   }

   ExecuteScript("k_ai_master", OBJECT_SELF, 1002);
}

 

It should be noted though that if Bastila is not within a 10 meter radius once all party members have been perceived the trooper will not attack even when she gets closer, since the OnPerception event only fires once the NPC either first perceives, looses perception of, or re-perceives a character it lost perception of. It does not continually fire while seeing another character. At least as far as I understand it. :)

Link to comment
Share on other sites

WOW! You did again Stoffe, thank you very much! Not only the code works perfectly, but the effect that it causes (I mean visually) is simply amazing. I will even ask Agent Xim to see if he want to release this upgrade for his mod. Thanks again!

Link to comment
Share on other sites

That's some fine coding there stoffe :)

 

I pretty much (attempted) in Operation Kill Bastila to combine the code from:

k_ptar_sithdis.ncs, k_ptar_sithdis2.ncs, k_con_bastpm.ncs, k_ptar_candcode.ncs

which were all dialog conditionals so that explains why my code doesn't always work lol.

Link to comment
Share on other sites

That's some fine coding there stoffe :)

 

I pretty much (attempted) in Operation Kill Bastila to combine the code from:

k_ptar_sithdis.ncs, k_ptar_sithdis2.ncs, k_con_bastpm.ncs, k_ptar_candcode.ncs

which were all dialog conditionals so that explains why my code doesn't always work lol.

 

I was just PM-ing you Agent Xim. I was planing to send you the modifications I made, with Stoffe's help off course, so you can post it as a new update to the OKB mod. PM me so I know where to send you the .zip file. You're going to like it!

Link to comment
Share on other sites

Hello Stoffe, it's me again, how are you? I'm in need of your helpful teachings again. I spoke to Agent Xim and he agreed to pass me the Operation Kill Bastila project, mostly because he is bussy with other projects and off course because I just can't stop messing around with it hehehe :p

 

Right now, what I'm trying to do is to spawn some Sith Troopers and some Battle Droids in the Sith Base, right after you kill the Sith Governor so the party can't scape so easily from the Sith Base. I compiled this code without errors (is a melange of some codes you've given me) but I can't make it trigger because I can't figure what's the correct entering .ncs file of the area. Any ideas?

 

//I don't know why I keep including this libraries but what the h***...

#include "k_inc_debug"
#include "k_inc_generic"
#include "k_inc_tar"


//Used to check is Sith Codes are available
int HasShieldCodes(object oPossessor) 
{
  return GetIsObjectValid(GetItemPossessedBy(oPossessor, "ptar_shieldcodes"));
}

//Used for easy creature spawnign
object SpawnNPCAtLocation(string sResRef, float x, float y, float r);


void main() 
{
  object oPC = GetFirstPC();

  //Execute original area script 
  ExecuteScript("[color=Yellow]k_old_govtlk_en[/color]", OBJECT_SELF, 1002); 

  //If PC enters the area and if Sith Codes are available, then spawn creatures
  if ((GetEnteringObject() == GetFirstPC()) 
     && (HasShieldCodes(oPC))) 
  {
     SpawnNPCAtLocation("x_sith_1", 35.36, 12.84, 0.0);
     SpawnNPCAtLocation("x_sith_2", 34.38, 10.69, 0.0);
     SpawnNPCAtLocation("x_battle_droid", 37.08, 11.28, 0.0);

     SpawnNPCAtLocation("x_sith_1", 6.20, 33.59, 0.0);
     SpawnNPCAtLocation("x_sith_2", 1.37, 33.23, 0.0);
     SpawnNPCAtLocation("x_battle_droid", 4.15, 31.15, 0.0);
     SpawnNPCAtLocation("x_battle_droid", 2.77, 36.19, 0.0);

     SpawnNPCAtLocation("x_sith_1", -3.50, -14.25, 0.0);
     SpawnNPCAtLocation("x_sith_1", -3.22, -15.40, 0.0);
     SpawnNPCAtLocation("x_sith_2", 6.44, -15.26, 0.0);
     SpawnNPCAtLocation("x_battle_droid", -5.69, -14.66, 0.0);

  }


}


object SpawnNPCAtLocation(string sResRef, float x, float y, float r) 
{
 location lLoc = Location(Vector(x, y, 0.0), r);
 return CreateObject(OBJECT_TYPE_CREATURE, sResRef, lLoc);
}

 

The yellow part should be the name of the original but renamed onentering area script, once I find wich one is it off course. I hope you don't get too tired of helping me out. In any case, thanks in advance and have a nice week! Take care!

Link to comment
Share on other sites

Archived

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

×
×
  • Create New...