Recommended Posts

HI guys

In spite many attempts I haven't been able to get a working Destroy Object Script in KotOR 1. It's just for make disappear a NPC in its place after a Dialog.

Anyone can help?

Thanks in advance

Share this post


Link to post
Share on other sites

Is the NPC the owner of the DLG/script? That can sometimes cause problems, since a script will immediately terminate as soon as its owner is destroyed. You can still destroy the owner as the final function in an exit node script, but this will usually happen in plain sight of the player unless you jump them somewhere else first. You can also command them to walk somewhere, like the module exit, first before destroying themselves. In general though, it's pretty straightforward:

DestroyObject(oNPC, 0.0, TRUE, 0.0);

The variables here are the creature to destroy, the delay in seconds before destroying them, not fading them out (so FALSE if you do want them to fade), and the delay in seconds before they start fading (which only matters if the previous term was set to FALSE). If the creature is the script owner then you can swap the object reference to OBJECT_SELF. But in that case I would delay calling the function until everything else in the script has finished executing, like so:

DelayCommand(2.5, DestroyObject(oNPC, 0.0, TRUE, 0.0));

This will delay calling the function by 2.5 seconds, the value of which you can adjust as needed.

If you want a creature to destroy itself after walking somewhere first, you can add the command to its action stack. This is commonly seen when an NPC "exits" an area. Often this can be part of the creature's UserDefine script, the case for which can be called at the end of the conversation. For example:

ActionMoveToObject(GetObjectByTag("k_exit", 0), FALSE);
ActionDoCommand(DestroyObject(OBJECT_SELF));
SetCommandable(FALSE);

To issue those commands from a script owned by a different creature/object, you'd need to use AssignCommand to assign them to the NPC of interest.

If you want more specific details, you need to provide more info about the circumstances of your scene and how it is currently set up.

  • Thanks 1

Share this post


Link to post
Share on other sites

Testing asap!!

---------------------------------------------

@DarthParametric

First, thanks, now I know something else (well, let's say ...just something) about those variables.

The general idea that I want design with the NPC (by now is just "talkable/fightable") is: Open Door-->Trigger Talk-->Launch Cutscene of existent .bik-->Talk/Fight-->Talk/Fade Out in its place without move.

I had created on purpose a NPC test (close to my entry point in the Module), created a simple .dlg and attaching the .ncs (Destroy Object Script) to it. These are the results with your examples:

- No fading out

void main()

{

object onpc_test = GetObjectByTag("npc_test", 0);

DestroyObject(onpc_test, 0.0, TRUE, 0.0);

}

Result: Ok, it works, reloading/reentering in the Module and testing 10-12 times in a row.

------

- Delay before destroy

void main()

{

object onpc_test = GetObjectByTag("npc_test", 0);

DestroyObject(onpc_test, 3.0, TRUE, 0.0);

}

Result: 

First attempt it took about 10 seconds and then NPC destroyed. No CTD.

Second attempt in a row (reloading/reentering), instantly CTD.

Third attempt, after restart the game, about 12 seconds delay then CTD.

------

- Fading out

void main()

{

object onpc_test = GetObjectByTag("npc_test", 0);

DestroyObject(onpc_test, 0.0, FALSE, 0.0);

}

Result: CTD.

-----

- Delaying fade out

void main()

{

object onpc_test = GetObjectByTag("npc_test", 0);

DestroyObject(onpc_test, 0.0, FALSE, 3.0);

}

Result: Delay 3 secs then CTD.

------

- Delaying command

void main()

{

object onpc_test = GetObjectByTag("npc_test", 0);

DelayCommand(2.5, DestroyObject(onpc_test, 0.0, FALSE, 0.0));

}

Result: Delay 2'5 secs then CTD.

--------

I haven't tried moving the NPC, I guess that the results would be the same.

--------------------

What do you mean about if the NPC is the owner of the dlg/script? the dlg/scripts created exclusivesly for it? if that is the case, both .dlg and script are just for this NPC, or you mean the scripts attached by default while the creation of the NPCs? That make me think, could be a conflict with the ScriptEndDialogu "k_def_endconv"?

Edited by Obi Wan Pere

Share this post


Link to post
Share on other sites

A conversation is initiated between two objects. One is the owner of the dialogue (and all scripts attached to it) and the other is the listener. This is typically the player, but not always. The owner of a DLG is considered the default speaker of entry nodes unless someone else's tag is specified in the Speaker field for that node. All scripts attached to the DLG are executed by the owner. In practical terms, this means you don't need to use a tag for the owner, you can use OBJECT_SELF. You also don't need to assign commands to the owner - any command that isn't assigned to someone else defaults to the owner. But, as I said, a script (and the DLG itself) will immediately terminate when their owner is destroyed. This can create problems if you need a scene to continue on past a creature being destroyed and it was the owner.

In essence, whoever you assign an ActionStartConversation to is the owner of that DLG and its scripts. If you assigned it to a placeable then the placeable is the owner. The game uses a lot of invisible placeables as owners for cutscenes, because it frees the designer up to do whatever they want to the NPC participants.

As to your crashes, that is not normal behaviour. Not for a simple fade. That is the default behaviour anyway, so you'd be getting that all the time during the vanilla game. If you are using an EndConversation/EndConverAbort script then yes, I'd expect that could be the issue, since you are presumably destroying the owner of the DLG just as it tries to fire another script due to the delay.

  • Like 2

Share this post


Link to post
Share on other sites

The screenplay/sequence described is just the idea for the final/real NPC (I still have to learn set triggers, launch the cutscene and more) and "disappear" would be the end of all the set, after that nothing else, just continuing playing, so after faded out should have no problems.

I have installed the Patch 1.03, K1R and the Community Patch 1.7, nothing else and the work is being done running on it. Anyway, still now and in the past, with or without K1R, I get several CTDs, usually at the same points, other times simply random CTDs at any point.

The npc test is filled just with a simple "hello/bye" dlg for to check the Destroy Object Script attached to its .dlg file and I created this NPC with its default scripts attached. No more scripts used (as far as I know).

Now I'm tried erasing the field -leaving blanck- the ScriptEndDialogu box in the "npc_test.utc" file with K-GFF but, at least fading out, I've got the same CTD result.

Edit: Usuful info about the "owners", thnx

Edited by Obi Wan Pere

Share this post


Link to post
Share on other sites

In future, you shouldn't use K1R and K1CP together. Versions of K1CP after 1.7 aren't compatible.

If you are getting crashes with the fade, try Disable Vertex Buffer Objects=1 in the [Graphics Options] of swkotor.ini if you don't already have that added. That's the only thing I can think of with that. It shouldn't be related to the script itself. As I said before, fading is the default behaviour that a lot of vanilla scripts use, so if you are encountering crashing elsewhere then that could be the cause.

  • Like 1

Share this post


Link to post
Share on other sites
13 hours ago, DarthParametric said:

In future, you shouldn't use K1R and K1CP together. Versions of K1CP after 1.7 aren't compatible.

Yes, I saw recently that the CP had been updated to 1.8.1 version and it's no longer compatible with K1R. That's the reason to use the 1.7 version that I already had.

I hadn't the option "Vertex Buffer Objects" in my .ini file, so I added it but I wished test it first set to 1. I get CTDs. I've set it to 0 and get the usual CTDs again in my run.

Now I think is best a little of background. In my "usual" and known CTD points I got used to save before reach them and I learned to live with that. Usually at second (or third) attempt I can pass them. (Specifically in the Endar Spire the points are, in the first and initial module, after open the door to acces the bridge, and in the second module, closing/geting out of the pannel that make explode the power conduit killing sith). Anyway, restarting KotOR, reloading and trying again I can go ahead.

Alright, coming back to the problem. For to test I always use a Save made before enter in the Module which I'm working on, precisely for to have a "clean" module and, of course, if I changed something in the files compiled in the .mod. In that way is when I always get the CTDs with the npc test and the destroy object script. Well, thinking about my "usual" and known CTD points, I've made a save in my module work, just before talk to the npc test. The first attemp I get the CTD. Restarting the game and using/reloading that Save made just before talk to the npc test ...NO CTD!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Even in a row: talk, fade out, reload that Save, talk fade out, reload that Save, talk, fade out... I still get CTDs some times but, as with my '"usual-and-known-CTD-points", restarting and reloading, if not with the first attempt, with the second or third the thing works and the npc test fades out with no problems. (And I hope always be so...).

So, as you said, the problem is not the Script. It works fine (well... really, when my KotOR wants, but by now I settle for that).

Share this post


Link to post
Share on other sites

Yeah, it's the fade out effect that causes this problem with certain hardware. I think I've had this problem on destroying NPCs that have bump maps. It's probably a memory leak or some similar issue.

  • Like 1

Share this post


Link to post
Share on other sites

You should probably also check in the options menu to see if Frame Buffer Effects is set to on or off, same for Soft Shadows (you'll want both to be off).

I was getting crashes after character creation until I turned Frame Buffer Effects off - fun times. I wonder what it is about how Bioware coded the effects that doesn't play nice.

Share this post


Link to post
Share on other sites

@ZeldaTheSwordsman

Sorry for do not answer before, I forgot it completely.

For all these years I've tried all possible combinations with the -disponible- graphic options and never got a satisfactory one, even with different hardware.

The most critical seems to be related with the V-Sync and, as you say, with the Shadows and Frame Buffer Effects but always, randomly or at the usual points, I got (and I still get) CTDs, in the creation character as well, even with all the graphic options -resolution included- set at its minimun valours/deactivated.

What I mean is that I can set all the options at maximun/activated and have no problems for hours or set all the options at minimun/deactivated and have no problems for hours, but in both conditions get randoms CTDs (or/and at the "usual" points).

Share this post


Link to post
Share on other sites

Hi again

I'm trying with the "Triggers" and "Spawn NPC" Scripts. I've set a Trigger that make spawn the NPC. It works fine but two NPCs appear instead just one.

void main()

{

    vector vPos;
    vPos.x  = 25.00;
    vPos.y  = 81.00;
    vPos.z  =   -1.27;
    
    float fAngle = 0.00;

    CreateObject(OBJECT_TYPE_CREATURE, "trig_test", Location(vPos, fAngle));
    DestroyObject(OBJECT_SELF);

}

Any tip?

Share this post


Link to post
Share on other sites

Well for starters, you can specify a location much more neatly as a single variable, like so:

location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);

Then your CreateObject call would be:

CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);

As to the double spawn, this is presumably the trigger's OnEnter? I would guess that it is firing multiple times before the DestroyObject kicks in, either by party members entering the trigger after the player, or perhaps the spawned creature itself. There are a few things you can do to limit that. One is to put the entire function inside an If check for the object entering being only the player specifically, or only a party member (including the player). That way no random NPCs or the spawned creature itself will initiate the trigger. Like so:

 void main() {
	
	object oPC = GetFirstPC();
	object oEntering = GetEnteringObject();
	location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);
	
	if (oEntering == oPC)
		{
			CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
			DestroyObject(OBJECT_SELF);
		}
}

For a check of any player controlled character instead, you can leave out the oPC declaration and change the If statement to:

if (GetIsPC(oEntering))

The other thing you can do is to check for and set a boolean. Have the initial If check make sure that a boolean is set to FALSE, then set it to TRUE when the trigger fires. This will ensure the trigger only fires a single time, regardless of who enters it subsequently. Doing that means you don't need to destroy it, but you can do that as well if you want. Keeping the trigger around may be beneficial for some cases where you want to reuse it later.

 void main() {
	
	object oEntering = GetEnteringObject();
	int SW_PLOT_HAS_TALKED_TO = 10;
	location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);
	
	if (GetIsPC(oEntering) && !GetLocalBoolean(OBJECT_SELF, SW_PLOT_HAS_TALKED_TO))
		{
			SetLocalBoolean(OBJECT_SELF, SW_PLOT_HAS_TALKED_TO, TRUE);
			CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
			
			//Uncomment the line below if you also wish to destroy the trigger.
			//DelayCommand(1.0, DestroyObject(OBJECT_SELF));
		}
}

The exclamation mark in front of a function means you are checking for the return value to be FALSE (well technically not TRUE, which is an important distinction per the below). Alternatively, you can also write it as:

GetLocalBoolean(OBJECT_SELF, SW_PLOT_HAS_TALKED_TO) == FALSE

Both are valid, but the second way can sometimes prove to be a little flaky with uninitialised booleans in my experience (even though that's the method Bioware most commonly used in vanilla scripts).

Note that I have declared SW_PLOT_HAS_TALKED_TO here just so you can see what I was doing. You could just cut that out and use 10 directly, or indeed use any of the plot flag locals from 0 to 10.

  • Light Side Points 1

Share this post


Link to post
Share on other sites

Working!!!!!!!!!!!!!!!!!

Thanks!!!!!!!!!!!!!

Yes, the Trigger is "On Enter". The PC is alone so the spawned NPC should be the responsible to fire again the Trigger before is destroyed. It's logical but I didn't realized that random NPCs, even the spawned one, could activate the Trigger. 

Some days ago I had a lot of troubles trying to set the coordinates of the poligon that activates the Trigger so I reused an existing one and I still have to attune these coord. What I mean is that was a problem  that, seeing the positions of the Objects, I'm almost sure I would not have seen with the correct coordinates (and it has helped to avoid future headaches).

This is the format I used:

void main() {

    object oEntering = GetEnteringObject();
    location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);

    if (GetIsPC(oEntering))
          {
            CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
            DestroyObject(OBJECT_SELF);
          }
}

By now I feel more comfortable if it's not imperative use Booleans.

------------------------------------

Now the doubt. How can I spawn multiple NPCs -with the same tag- with the same Script? Is enough add a different coordinates line?

--------------------------------

Ehmm... well... and another question I'm fighting with the last hours.

I need make a Script for a Transition Module. I think is needed the "Jump to Location" Script but I don't know how to do it. I guess I need the name of the destination module but I'd need set different entry coordinates instead the usual for that Module.

THNX in advance

Share this post


Link to post
Share on other sites

You can spawn multiple instances of the same UTC with different locations, yes. There are a few different ways you can do it in terms of varying efficiency, using loops and so forth, although those tend to work best with waypoints that have tag names set up to be iterated through. If you have a look at some of the vanilla scripts you'll see how this is done.

Just be aware though that you probably don't want to attach the DLG directly to the UTC, and that trying to deal with a bunch of different objects all with the same tag in a script can get a bit messy if you need to grab a specific one.

As far as module transitions go, again the vanilla game should give you plenty of examples to use as a guide. How you go about it really depends on what sort of transition it is. A doorway or other entrance/exit in a module that the player is manually moving through? Or a forced transition at the end of a cutscene/conversation?

Share this post


Link to post
Share on other sites

@DarthParametric

I have some troubles to identify by its name useful Scripts that could help me but I'll try again later. By now the idea is spawn the NPCs in pairs with the NPCs close each other.

The spawned NPCs are (is) hostile from the start (well, will be, by now just stands there asking what the h... is doing...) and has no attached dialogues but thanks for the warning (if I'm able to remember it) for future talking spawned NPCs.

Due the problems building new walls in existing rooms around the exit/transition doors (my first attempt) and adding existing rooms as news (specifically the one with the exit/transition doors)(my second attempt) I have to settle with a (not so attractive as the first attempts) simplest solution. I've placed close to the end door of the passage a Placeable button panel and I've attached a dialog to it. According the choice (use/do not ) this dialog must fire the transition script.

Share this post


Link to post
Share on other sites

If you want the creatures to be hostile straight away then you should probably just set their faction to hostile in the UTC. The standard hostile faction is 1 (2 is friendly, 5 is neutral).

You can set up triggers as area transitions. The Taris Undercity has some examples of this. If you want to do it via a script, then the function you need is StartNewModule:

// 509: Shut down the currently loaded module and start a new one (moving all
// currently-connected players to the starting point.
void StartNewModule(string sModuleName, string sWayPoint="", string sMovie1="", string sMovie2="", string sMovie3="", string sMovie4="", string sMovie5="", string sMovie6="");

As per the above, you need to specify the destination module name. You can also specify the tag of a waypoint you want the party to spawn at. If left blank then they will spawn at the Mod_Entry point defined in the module's IFO. You can also specify a movie (or multiple movies) to cover the load sequence.

A vanilla example is on Kashyyyk when you side with Chuundar. After finishing in the Shadowlands and returning to him, at the end of the conversation you get kicked out of the village. The script that does that is k_pkas_leavetown in the Chieftain's Hall (kas_m23ad) which sends you to a waypoint right outside the village entrance on the Great Walkway:

void main() {
	StartNewModule("kas_m22ab", "kas23ab_kas22ab");
}

If you want to fire it from a DLG, you can put the script on the exit node (i.e. the one that says End Dialogue).

Share this post


Link to post
Share on other sites
14 minutes ago, DarthParametric said:

If you want the creatures to be hostile straight away then you should probably just set their faction to hostile in the UTC.

Oh, yeah, I knew that. It's just that I dont' want fight (and sometimes die) every time I warp  to the module for to check something... :lol:

----------------------

The set of the exit/transition doors of "end_m01aa" module to "end_m01ab" are "end_door11" and "13.utd". Double clicking (or extracting) the files, "11.utd" is the only one with a script attached, "k_pend_door09", but I don't find it in the Kotor Tool-->(module)-->Script Compiled list.

----------------------

I'll check the exemples asap!!

THNX again

Share this post


Link to post
Share on other sites

That script is global, so you'll find it in scripts.bif (original source included). It has nothing to do with transitions though:

#include "k_inc_end"
void main()
{
    SetTraskState(TRASK_NOTHING_02);
}

It just sets a global number:

void SetTraskState(int nValue)
{
  //  AurPostString("New State" + IntToString(nValue),5,7,2.0);
    SetGlobalNumber("END_TRASK_DLG",nValue);
   // AurPostString("Set: " + IntToString(nValue),5,10,3.0);
}

There are a few modules that utilise global scripts for things that really should be module-specific. Manaan is notorious for doing this.

I'd suggest permanently extracting scripts.bif somewhere so you don't need to use KTool. I'd also highly recommend installing Notepad++ along with JC's NWScript language definitions if you haven't already. It makes working with scripts much easier. With the global scripts extracted, you can try doing a Search in Files for examples of a particular function:

1529786388_N_Find_in_Files.jpg.4d92c385920ab8743ef89c6effac17a8.jpg

  • Like 1

Share this post


Link to post
Share on other sites

----------------------------

Oops!! A doubt reading the instances. Where says "StartNewModule" I guess doesn't mean "Start" and have to run the entire Module again and means that the game engine loads the Module (as was the last time we were there if we have been there already). In fact, my transition must make me come back to a Module that I have already run. In a Playthrough the sequence would be 'Command Module' (end_m01aa) --> Starboard Section (end_m01ab) --> 'My Module' --> Come back Starboard Section (end_m01ab) --> then Taris.

Share this post


Link to post
Share on other sites

It just means unload the current module and load the specified module. If you have been there before then that module's GIT/ARE/IFO is stored in your save file, recording whatever state changes occurred.

  • Thanks 1

Share this post


Link to post
Share on other sites

I've found things about Spawn Increment (in 'k_inc_utitility') and spawns the number of (...) (in 'k_inc_dan') but I've been unable to reproduce it in the script I need for to spawn 2 Objects.

When my mouse was already looking me terrified fearful to have to learn to fly I tried something by my own. Sure it's not the most accurate manner but it works, even with different Tag Objects, and at least I can use it even if only for tests purposes until I learn to make correctly a script.

void main() {

    object oEntering = GetEnteringObject();
    location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);

    if (GetIsPC(oEntering))
          {
            CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
            CreateObject(OBJECT_TYPE_CREATURE, "d_end_sith02", lLoc);
            DestroyObject(OBJECT_SELF);
          }
}

(I have could not try yet with the transition script).

Share this post


Link to post
Share on other sites

You can just stack multiple CreateObject lines like that, it will work. The more 'correct' way would be to have a loop like this

int nCount = 3;

for (nCount; nCount != 0; nCount--)
{
	CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
}

This would loop through the CreateObject line 3 times, creating 3 of your test guys.

  • Thanks 1

Share this post


Link to post
Share on other sites

Here again with another little question. I'm searching here and there but I've found nothing about.

How can I change the orientation of the spawning NPCs?

I'm trying changing it in the Location/Vector line of the Spawn Script and I think that the variable is in radians but it doesn't work.

Share this post


Link to post
Share on other sites

Location uses degrees. 0 degrees is East.

You can also script facing commands to force an NPC to reorient and face in a specific direction:

AssignCommand(oNPC, SetFacing(90.0));

You can also use fixed cardinal direction constants:

float  DIRECTION_EAST   = 0.0;
float  DIRECTION_NORTH  = 90.0;
float  DIRECTION_WEST   = 180.0;
float  DIRECTION_SOUTH  = 270.0;

Alternatively, you can face them towards another object:

AssignCommand(oNPC, SetFacingPoint(GetPosition(oObject)));

This can be temperamental though. Often they won't change their facing until they perform an animation, so adding a short anim to a script is something necessary if you are trying to assign facings in a conversation, especially with interjections from companions where the NPC may be changing their facing to look at multiple different speakers.

  • Thanks 1

Share this post


Link to post
Share on other sites

Perfect!!

I read some time ago that the map orientations can differ from one module to another. Specifically in the Endar Spire's map and its North pointing "Up" (so South is "Down" of the map, bla, bla...), 0.0 is South and, e.g., West is 270.0

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.