PDA

View Full Version : Letting an NPC keep their items?


Princess Artemis
06-12-2006, 06:16 AM
I'm on the last legs of my NPC recruit mod...

What I'm wondering is if, once the NPC is completely removed from the party, is there a way for that NPC to keep any items, weapons, and such he was weilding when he was removed? So he'll still have them when he comes back?

This wouldn't be an issue except that the NPC's hands are locked, so nothing can be put in his alternate weapon slots unless I script them in. I would like him to keep his weapons, but if that's not possible, I can just add to his second recruit script a few lines to put the weapon in his alt hand again, although that doesn't solve the problem of the items just up and disappearing (i.e., the items are lost when the NPC leaves the first time, including lightsaber upgrades--I suspect he still has his 'saber because he's returning to his default .utc configuration.)

stoffe
06-12-2006, 06:49 AM
What I'm wondering is if, once the NPC is completely removed from the party, is there a way for that NPC to keep any items, weapons, and such he was weilding when he was removed? So he'll still have them when he comes back?


If you remove the NPC from the party table he is no longer stored globally in the savegame. If the NPC was present in an area when you removed him and you didn't call DestroyObject() or RemoveNPCFromPartyToBase() on him he should still be kept "intact" within that module as long as its still kept in the save game and not deleted (some areas are purged from the savegame when you reach certain points in the game to save space). But then you'd only be able to re-add him within that area using AddAvailableNPCByObject().

If you can't keep the NPC in the party table (e.g. if someone else needs their party table slot) but you still need to keep the state (equipment, levels, powers/feats etc) of the NPC and be able to put them back into the party anywhere in the game, you can store them temporarily in the Puppet table instead. The puppet table also keeps its data globally, like the party table does.Then, when you need to re-add the NPC you spawn them from the puppet table and then put them back into the party.

Princess Artemis
06-12-2006, 12:11 PM
Ah...! OK, so...if I had a leave script that looked like this:
void main() {
AddAvailablePUPByTemplate(PUP_OTHER1, "tel_dustil2");
RemoveNPCFromPartyToBase(NPC_HK_47); //Dustil takes HK's spot, so removes 'HK' from the party.
RemoveAvailableNPC(NPC_HK_47); //Makes Dustil unavailable.
}

And a spawn script like this...
void main() {
object oEntering = GetEnteringObject();
if ((oEntering == GetFirstPC())) {
SetNPCSelectability(6, 0);
if (GetGlobalNumber("Dustil_Recruit") == 1)
SpawnAvailablePUP("tel_dustil2", Location(Vector(95.27966, 216.02438, 1.06601), 131.49179));
}
}

Would this do what I'm looking for it to do? Remove Dustil from the party, then later spawn Dustil where I want him on Korriban, only if the global is right, and keep planting him there no matter what the PC does until Dustil either leaves or is recruited (at which point I would have the global Dustil_Recruit change so this script wouldn't pull him out of the puppet table?)

stoffe
06-12-2006, 03:56 PM
Ah...! OK, so...if I had a leave script that looked like this:
(snip)
Would this do what I'm looking for it to do? Remove Dustil from the party, then later spawn Dustil where I want him on Korriban, only if the global is right, and keep planting him there no matter what the PC does until Dustil either leaves or is recruited (at which point I would have the global Dustil_Recruit change so this script wouldn't pull him out of the puppet table?)


No, you'll have to use AddAvailablePUPByObject(), otherwise it won't work as intended:

By Template - Creates a new instance of the NPC from scratch their UTC template, which will be an exact copy of that template.
By Object - Uses an existing instance of the NPC object in the world, with any new equipment and stat changes they may have received. This is what you want if you want to save the current in-game state of an existing NPC.

Provided that the Tag of the Dustil NPC is tel_dustil2, it might look like:

void main() {
object oDust = GetObjectByTag("tel_dustil2");
RemoveAvailableNPC(NPC_HK_47); // Remove from party table
AddAvailablePUPByObject(PUP_OTHER1, oDust); // Add to puppet table
DestroyObject(oDust); // Remove from the current Area
}


This would remove the character occupying HK47s slot in the party table from that table. It would then take the NPC with the Tag tel_dustil2, who must exist in the current area, and store it in the second slot in the puppet table. Finally it will remove the NPC from the current area (but it'll still exist in the puppet table and can be spawned into the world from it with its game state intact).

The script to do this could then look something like this, assuming it's an OnEnter script for an Area or a Trigger:

void main() {
if ((GetEnteringObject() == GetFirstPC())
&& (GetGlobalNumber("Dustil_Recruit") == 1)
&& !GetIsObjectValid(GetObjectByTag("tel_dustil2"))
{
object oDust = SpawnAvailablePUP(PUP_OTHER1, Location(Vector(95.28, 216.02, 1.07), 131.5));
// ST: To put him back in the party again you'd do like this,
// i.e. use ByObject() and not ByTemplate()...
// AddAvailableNPCByObject(NPC_HK_47, oDust);
}
}


Unless I misunderstand what you are doing the SetNPCSelectability() call would be unnessecary since you already removed the NPC from that slot in the first script, thus that slot should be empty.

The above would check that the Dustil_Recruit global is 1 and that the NPC does not already exist before spawning the NPC using the instance in the second slot in the puppet table.

I also removed a few decimals from the coordinates so it only goes by centimeter precision. The coordinates are in in-game meters, and the player will hardly notice if he's standing a few millimeters off the desired spot. :)

Princess Artemis
06-12-2006, 09:21 PM
Thankee-sai, I'll try those. I'm starting to 'get' scripting, but there is much magic involved still :)

The second script is k_701area_enter, which is the first part of Korriban. I guess SetNPCSelectability() is preventing the player from using Kreia? It's in the original script, so I left it there and added the Dustil spawn code after it. OK, so it's by tag then, d'oh! Hrm, Dustil's tag is HK47; I think the reason I had to do that was because he started cloning on the Hawk if his tag wasn't HK47. Would that cause problems if the player brings HK with them onto Korriban when Dustil is supposed to be there? The way I have him spawn on Korriban now uses tel_dustil2, but I can see now that it's creating a brand new version based on the UTC (which I don't want.)

If it will be a problem, could I do something using this bit of fancy footwork I found around this forum to make sure the script is looking for the right HK-47? (I added back the SetNPCSelectability() because it's part of that particular script's original version)...

void main() {
object oEntering = GetEnteringObject();
if ((oEntering == GetFirstPC())) {
SetNPCSelectability(6, 0);
object oDust=GetObjectByTag ("HK47");
string sName = GetName(oDust);
string sSubName = GetSubString(sName,0,5);
(GetGlobalNumber("Dustil_Recruit") == 1)
&& !GetIsObjectValid(oDust)
&& (sSubName == "Dusti");
{
object oDust = SpawnAvailablePUP(PUP_OTHER1, Location(Vector(95.28, 216.02, 1.07), 131.5));
}
}
}

I just know there's something wrong with that. :indif: And watch, it won't be a problem and I just made a lot of unneccesary work for myself :)

stoffe
06-13-2006, 06:35 AM
(snip)
I just know there's something wrong with that. :indif: And watch, it won't be a problem and I just made a lot of unneccesary work for myself :)

Almost right, the conditional check just got a bit messed up. :) Doing like this might work:


#include "k_inc_glob_party"

void main() {
object oEntering = GetEnteringObject();
if ((oEntering == GetFirstPC())) {
SetNPCSelectability(NPC_KREIA, FALSE);

if (GetGlobalNumber("Dustil_Recruit") == 1) {
int iIdx = 0;
int bFound = FALSE;
object oDust = GetObjectByTag(GetNPCTag(NPC_HK_47), iIdx);

while (GetIsObjectValid(oDust)) {
if (GetName(oDust) == "Dustil") {
bFound = TRUE;
break;
}
oDust = GetObjectByTag(GetNPCTag(NPC_HK_47), ++iIdx);
}

if (!bFound) {
SpawnAvailablePUP(PUP_OTHER1, Location(Vector(95.28, 216.02, 1.07), 131.5));
}
}
}
}


This way you'd get the standard tag for the NPC in HK-47's party slot ("hk47") used by the Ebon Hawk scripts, just in case. If would then check through all NPCs in the area with that tag, and if none of them are named "Dustil" the NPC would be spawned. This way it hopefully shouldn't cause any trouble if the player has HK47 in the party when entering the area.

Princess Artemis
06-14-2006, 02:20 AM
Sorry it took so long to get bacl on this. The sample script to test for HK won't compile--GetNPCTag doesn't seem to be a valid function.

I tested my faulty script and storing Dustil as a puppet worked to keep his items, so I'm at least that much closer to getting this worked out :)

Anyway, how much of a possibility is there that a leave script like this:

void main() {
object oDust = GetObjectByTag("HK47");
AddAvailablePUPByObject(PUP_OTHER1, oDust); // Add to puppet table
RemoveAvailableNPC(NPC_HK_47); // Remove from party table
}

would cause the game to crash? (Specifically, as the game is trying to load the Telos polar regions).

And this,

void main() {
object oDust = GetObjectByTag("HK47");
AddAvailablePUPByObject(PUP_OTHER1, oDust); // Add to puppet table
RemoveNPCFromPartyToBase(NPC_HK_47);
RemoveAvailableNPC(NPC_HK_47); // Remove from party table
}

would cause the Telos Academy scenes to get all jumbled up? With this script, it only seems to bargle the game if you agree right away to give up your weapons to the Handmaidens (the scene with Kreia and Atton doesn't occur, both of them can be found standing around in one of the rooms; Kreia can't be talked to, but Atton gives you a choice of [Cheat] Continue Kreia conversation and [Cheat] Skip something or other, and neither really do anything...chasing down Atris will trigger her scene, but finding T3 will act like he's in the party. Very weird.) Other choices work fine.

Just to be thorough, if the script doesn't fire at all, Dustil will show up to fight the HK-50's as what I can only call a guest, so that there are four people fighting. I don't remember what happens if I then go into the academy, IIRC, he disappears but is still selectable as a party member.

Again, to be very thorough, the dialogue that the leave script is fired in is called by a script that was reportedly decompiled incorrectly (tr_shuttle in 232TEL), so I guess it could also be the culprit, although it worked fine when I was just returning to base and clearing NPC_HK_47 from the party table.

stoffe
06-14-2006, 07:41 AM
Sorry it took so long to get bacl on this. The sample script to test for HK won't compile--GetNPCTag doesn't seem to be a valid function.


Oops, forgot to include the header of that script when I posted it it seems. You'll need to add the line...
#include "k_inc_glob_party"
...at the top, and extract that include file from scripts.bif to use the GetNPCTag() function. It's an include file with party management functions that are used by the Ebon Hawk area to do things. But I suppose you can hardcode "hk47" as the tag just as well. :)




Anyway, how much of a possibility is there that a leave script like this:
(snip)
would cause the game to crash?


Can't see why it should crash, but the game can be a bit touchy about the context and sequence in which certain script functions are used, I've noticed. From where are you firing this script? From a dialog with the NPC in question?


With this script, it only seems to bargle the game if you agree right away to give up your weapons to the Handmaidens (the scene with Kreia and Atton doesn't occur, both of them can be found standing around in one of the rooms; Kreia can't be talked to, but Atton gives you a choice of [Cheat] Continue Kreia conversation and [Cheat] Skip something or other, and neither really do anything...


This is not caused by a mod, it's a bug in the game itself that was introduced with the v1.0b patch. Apparently Obsidian was in such a hurry to get the patch done that they forgot to remove some debug code before releasing it. :) The parameter to a dialog script is set improperly on that particular node. To fix it, see what parameter the other responses use and set the same value on that particular reply node.

Princess Artemis
06-14-2006, 05:12 PM
Thank you so much for your help! With the #include "k_inc_glob_party", the script you provided worked perfectly. Dustil did gain a huge amount of experience sitting in the puppet table for such a short time, though. My PC had roughly 65,000 XP, and Dustil rejoined with 100,000 XP! He was pretty close in XP on Telos; he left with 52,000 XP. His MultiplierSet is 0, the same as HK-47 (and Atton). Should I change that so he doesn't get crazy-grabby with the XP while he's chillin' in the puppet table?

Can't see why it should crash, but the game can be a bit touchy about the context and sequence in which certain script functions are used, I've noticed. From where are you firing this script? From a dialog with the NPC in question?

It fires from the shuttle dialogue in the Telos Military Base once you've chosen to leave for the Telos polar regions. The second script I provided, with the RemoveNPCFromPartyToBase(), worked fine, so I guess the game was feeling a little touchy that "HK" hadn't been taken out of the party before he was removed from the party table, or something :)

This is not caused by a mod, it's a bug in the game itself that was introduced with the v1.0b patch. Apparently Obsidian was in such a hurry to get the patch done that they forgot to remove some debug code before releasing it. The parameter to a dialog script is set improperly on that particular node. To fix it, see what parameter the other responses use and set the same value on that particular reply node.

Oh, hee. I hunted it down--not only did they forget to set the script parameters, they forgot to put in the rest of the silent reply and entry nodes that had the rest of the script parameters! Well, 'tis fixed. I know I'm not the first to fix it, but there it is, the fix will be included in the mod.