doboy

On acquire script?

Recommended Posts

Instead of rummaging around endlessly, I figured someone might have the answer to this.

I'm trying to get a script to run that sets a global boolean once the player has found a specific item. I'm not asking about how to write the script but more where to place it and how to trigger it. I hope that makes sense.

 

I mean it's kind of like updating a quest once you've received a certain item.

 

If that's not possible, could there be a way to run a script and make it look like that's what happened in some instance?

 

Thanks.

Share this post


Link to post
Share on other sites

Were you to acquire the item from a placeable utp container, you could (if that container is uniquely named) put a script in the OnClosed or OnInvDisturbed slots in KotOR Tool.

Alternatively, you could edit the .are file for the level using K-GFF, change the Mod_OnAcquirItem field to the script name. You'd then need to put the .are file back into the level (a .mod version of the level, so use ERFEdit to make a .mod if you don't have it already) using ERFEdit and save the level.

 

You'd then need to load a save from before entering the level for the edited .are file to take effect (or you could put it in the Override folder, but if two levels use the same filename, that could be interesting...).
 

Share this post


Link to post
Share on other sites

Welp, that's unfortunate. Looks like I'll have to take a look at editing all of the containers in the game, since I'm looking for a randomly generated object :(. When I think about it, I honestly don't think there are that many and writing the script I want is easy.

 

Would you happen to know if mods generally edit the default .utp files? Does TSLRCM? I can't really think of a reason why anybody would want to edit the default containers, but I also don't want to make anything majorly incompatible. 

Share this post


Link to post
Share on other sites

People don't edit the utp files, but there is hope for you yet!

 

You can try editing the k_def_disturb01.nss script, which is currently implemented into the game, but is in fact blank. As the comment says in the file, it's currently unused.

 

I know you want to script it yourself, but there's some info for a script layout here:

 

void main()

{

    // Get the object that made the script trigger

    object oItem = GetInventoryDisturbItem();

 

    // Get the tag of the object that made the script trigger

    string sItemTag = GetTag(oItem);

 

    // Get the type of action that made the script trigger

    // This will return 0 (Item added), 1(Item removed), or 2(Item stolen; which is probably unused in KotOR)

    int iItemAction = GetInventoryDisturbType();

 

    // If Item was added)

    if(iItemAction == INVENTORY_DISTURB_TYPE_ADDED)

    {

 

    }

    else if(iItemAction == INVENTORY_DISTURB_TYPE_REMOVED)

    {

 

    }

}

Share this post


Link to post
Share on other sites

Wow, thank you! So k_def_disturb01 and other k_def_eventwhatever are the scripts that fire when no OnDisturb or corresponding field is specified?

Share this post


Link to post
Share on other sites

Actually, the k_def_disturb01 is the script used by characters. And I've just checked the player's scripts and we have to do a workaround, since the On Inventory Disturbed script for the player is not assigned and we can't assign it.

 

So instead, we need to edit k_hen_spawn01 and k_def_userdef01 to make the game check when the player or party members pick up an item.

 

In k_hen_spawn01.nss, we need to go to the following line:

 

    //GN_SetSpawnInCondition(SW_FLAG_EVENT_ON_DISTURBED);

 

and change it to the following:

 

    GN_SetSpawnInCondtion(SW_FLAG_EVENT_ON_DISTURBED);

 

Then compile that and save it to the Override folder.

 

...

 

Now in the k_def_userdef01.nss, find the following:

 

    else if(nUser == 1008) // DISTURBED

    {

 

    }

 

Inside this section, we need to add the following (This is mostly what I posted above, but I've added in some extra protection to make sure this is the player character):

 

(remember, all of the following goes inside the else if(nUser == 1008) section's { } marks!)

 

   // If the object launching this script is the currently-controlled character, proceed

    if(GetPartyMemberByIndex(0) == OBJECT_SELF)

    {

        // Get the object that made the script trigger

        object oItem = GetInventoryDisturbItem();

 

        // Get the tag of the item that disturbed the inventory

        string sItemTag = GetTag(oItem);

 

        // Get the type of action that made the script trigger

        // This will return 0 (Item added), 1 (Item removed), or 2 (Item stolen, though I think this is not done in KotOR)

        int iItemAction = GetInventoryDisturbType();

 

        if(iItemAction == INVENTORY_DISTURB_TYPE_ADDED)                // If the item was added to the inventory

        {

 

        }

        else if(iItemAction == INVENTORY_DISTURB_TYPE_REMOVED)    // If the item was removed from the inventory

        {

 

        }

    }

 

 

At this point, you should be good to add whatever code you need to add to check for the item (you should just need to compare sItemTag against the tag of the item) then update your globals accordingly).

 

After that, just need to save and compile to the Override folder. If you really want to make sure this is working in-game, you can add the following just above the object oItem line:

 

SendMessageToPC(GetFirstPC(), "Hi! Disturbed Items are happening");

Share this post


Link to post
Share on other sites

Haha yeah I would have never figured that out. I'll have to experiment with it later when I get the time. By the way, what do the _FLAG_'s mean in general? Are they kind of specific to events?

Share this post


Link to post
Share on other sites

Generally speaking, anytime you see an all-caps phrase like that separated by _ marks, it's a variable. Most variables are found in nwscript.nss, but some are specified in include files (these generally, but not always, have "_inc_" in the filename; an include file is a script that does not have a void main() or an int StartingConditional() function).

 

The compiler processes these when you compile the script, then checks any include files you use (as noted by having "#include """ without the outer set of quotes) and nwscript.nss and will substitute those phrases for the actual numbers they represent.

 

For example, in the k_def_userdef01.nss, where it says "nUser == 1008", that is the equivalent of saying "nUser == KOTOR_DEFAULT_EVENT_ON_DISTURBED"; the compiler would find that phrase in nwscript.nss or an include file and it'd substitute the number that phrase represents, which in this case would be 1008.

Share this post


Link to post
Share on other sites

I was just wondering why the programmers would choose to add _FLAG_ to some of those names. Just for curiosity's sake.

 

I have some experience programming in C, and the syntax is pretty consistent to what Bioware is using. I'm just trying to get better understanding of game specific functions and such.

Share this post


Link to post
Share on other sites

Oh, that's probably just because these phrases are basically 0/1 boolean flags determining if the user-defined script is called in addition to the normal stuff.

Share this post


Link to post
Share on other sites

Makes sense. I only have one more question for now...

 

Do you know anything about manipulating the camera in dialogues? Is it possible to pan the camera or are you only able to cut directly to a different shot? And most importantly... how hard/time consuming is it lol.

Share this post


Link to post
Share on other sites

With the current tools (I hope to remedy this eventually...), it can be time-consuming, depending on how complex you want the camera to be.

 

In the Modding Tools section of starwarsknights.com, you will find a program called AniCam. This is used to make animated cameras, which can only be used in dialogs. You will also need the DLG Editor by tk102 from the same place, as this will let you edit or create dialogs.

 

For the record, I recommend reading AniCam's read-me all the way through.

 

I also recommend downloading the Utility Armbands mod from this link, as it will give you the needed angle and position for certain things. A lot of this you will be doing in first-person to make sure you're facing the right way before using the orientation armband.

 

You basically need to go in-game, find your starting position, orient yourself to face the right way with first-person view, and then use the Orientation Armband. The feedback will be on the secondary window in the Messages menu (the feedback log).

 

With this information (the XYZ coordinates and the Angle), you can start your first timed entry in AniCam. You'll enter that info into the first row and then tell AniCam to add another entry (use the menubar at the top). AniCam will increment the time field by 0.5 seconds (if you add a new entry between two entries, AniCam will auto-set the time field to mid-way between the two entries) and you can say where you want the camera to be at that point.

 

Things to note:

 

1. AniCam stats you off with CUT001W as the animation; this is perfectly fine, and animated cameras can have up to 99 animations.

2. You must give a Camera Shot Length (the total time of the animation; so needs to be done for each new CUT###W you make) and a Camera Name (part of the .mdl file's header, but also what AniCam will default the name of the .mdl and .mdx files to).

3. For the Orientation of the camera, the Heading column is the horizontal axis, the Pitch is the vertical axis, and the Roll is the left-right axis (left-right as in you tilting your head without moving it, for example).

4. In a DLG file in DLG Editor, click on the top entry (the black line) and put the name of the .mdl file (without the extension, of course) into the Camera Model field, then click on another entry in the DLG to register the change.

5. To make the animated camera play for a certain node/entry, set the Camera ID to -1 and the Camera Angle to 4.

6. To tell which animation to play, you need to set the Camera Animation to a number. This number is either 999 + the number of the animation (like Cut001W would be 1, so the number is 1000) or 1199.*

7. You do not have to animate a camera down to the nearest 0.1 second, or even the nearest 0.5 or 1.0. You can set the Camera Interpolation in AniCam to use the interpolation feature to smoothly estimate the differences between the entries of the animation.

8. I HIGHLY recommend saving two copies of your animated camera: .mdl for the one with interpolation (this will be the one you test and mod with) and -no_interpolation.mdl (this must be done with the Camera Interpolation set to none; this model will be the one you can import into AniCam whenever you need to make an edit to the animations).

 

*: The reason for the two numbers is that the 1000 series of numbers will continue an already-playing animation, but the 1200 series is used to actually start the animation. Also, you can't skip around the animations like this; if you start an animation with 1200, you can't call 1001 to continue CUT002W. You would need to put 1201 in the DLG node that starts that animation.

 

For this reason and to avoid making your cutscenes look weird, I will advise that every entry after the animation starts use the 1000 series of the animation you started to ensure that node is playing the animation and not stopping it prematurely.

Share this post


Link to post
Share on other sites

All I want to do is smoothly pitch the camera up and have it stay there until the conversation ends, so I don't think it should be complex. But seriously, you have saved me so much time and frustration. I can't thank you enough.

Share this post


Link to post
Share on other sites

Not sure if you played through the Leviathan with K1R or not, but the three animated cameras K1R uses there took me several hours to do...

 

Last tip for you: a Pitch of 90 = straight ahead, 0 = straight at the ground, 180 = straight up. Anything more than that and you could get interesting and amusing results...

Share this post


Link to post
Share on other sites

I haven't played K1 in a very long time, so I don't think I have. Actually, I don't even own a copy as of now :(. But I don't mind a few hours as that is relatively short to what I've already put in. I don't know if that's a good thing or a bad thing... I think I prefer modding rather than actually playing the game.

Share this post


Link to post
Share on other sites

Not sure why you want to modify all containers, the .are + script works just fine for the purposes of the OP. Check 803DRO for example how picking up certain items triggers conversations or questupdates.

Share this post


Link to post
Share on other sites

I'm mainly advising my method over the .are + containers because the guy is trying to trigger something for an item that is generated by random loot. And I was advising against editing the .utp files from the templates.bif because I know that the generic names makes it a possibility that they have custom .utp files in some of the modules. And I have no idea what could have been changed to make them require such a copy of the file.

Share this post


Link to post
Share on other sites

Instead of creating a new thread, I thought I'd ask here. Why can I not compile scripts without a main()? I'm trying to have a function library I can access anywhere, but it's not working. Even when I try to compile one of the games default libraries like, say "k_inc_item_gen", it doesn't work. KotOR tool will say compiled successfully but no .ncs file will be created. Have y'all had any experience with this?

 

It's not critical but annoying.

Share this post


Link to post
Share on other sites

So I can't create my own? Also, I have one more question if y'all would be so kind! How exactly does the model variation field work in .uti files? I looked at some lightsaber mods and noticed that some of the model variations in the item files would normally be out-of-bounds and cause the game to print a white box for the item's icon and not change the model. At least I think so. How would you add more model variations if possible?

Share this post


Link to post
Share on other sites

In the case of include files, they can't have a void main() or an int StartingConditional() because those make them action or condition scripts, instead of include libraries.

 

Include libraries are just raw .nss files that are "included" into the data before the script is compiled into a .ncs file.

Share this post


Link to post
Share on other sites

Actually, you can use any script as an include file. It doesn't matter if it has main() so long as it has other subroutines.

 

I usually give my include files a blank main() because that way NWNNSSComp will check it for errors. It doesn't affect how the scripts are included in other files in the slightest.

 

So I can't create my own? Also, I have one more question if y'all would be so kind! How exactly does the model variation field work in .uti files? I looked at some lightsaber mods and noticed that some of the model variations in the item files would normally be out-of-bounds and cause the game to print a white box for the item's icon and not change the model. At least I think so. How would you add more model variations if possible?

 

Model variations are 8-bit, meaning you can only use numbers 0 through 255.

Share this post


Link to post
Share on other sites

Actually, you can use any script as an include file. It doesn't matter if it has main() so long as it has other subroutines.

 

I usually give my include files a blank main() because that way NWNNSSComp will check it for errors. It doesn't affect how the scripts are included in other files in the slightest.

 

This is what I was trying, but KotOR tool would still give me an error saying it couldn't open the include file. Regardless, it doesn't matter much. I was just curious because I swear I had done it successfully before.

Share this post


Link to post
Share on other sites

So I can't create my own?

 

Well, in a sense you can, if you want to have your own pre-defined complex functions that you'll call on multiple times to use in your own scripts. Then you could call on the functions in that script and compile them by injecting it into the script you want to compile. To do that, put this in the script before your starting line.

#include "<name of include script w/o extension>"

The reason why include scripts don't compile is because they don't have a starting line - as in a void main() or int StartingConditional().

Share this post


Link to post
Share on other sites

Yes, I know but for some reason the compiler isn't able to open the include file. But on other note, has anyone experienced general unreliability with ActionEquipItem and ActionUnequipItem? It's hard to explain. Items will equip and unequip however they won't necessarily load? This happens almost exclusively with party members and I have to switch to them, either in the inventory screen or in-game, for the items to show correctly. I rarely, if ever, have problems with the player character or NPCs. And to give more context, I mostly run these scripts in a dialog sequence or after the end dialog option is clicked.

 

For the most part I think I understand AssignCommand(), ActionDoCommand(), Action___(), and the action queue in general. Sometimes I add the DelayCommand() and occasionally it will kind of help some of my problems. A majority of the time these things are due to human error, but I'm confused as to why they halfway work and why they behave oddly. This is really the last obstacle in the mod I'm making and it's fairly significant. Thoughts?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.