Obi Wan Pere

Help adding dialogs and scripting

Recommended Posts

Hi guys

In KotOR 1 how can I add text/dialog to an object/placeable?

I've tried adding a .dlg file in the 'Conversation' field of the object with K-GFF like with an NPC but doesn't work.

Linking with that, how can I launch a Cutscene within/after a dialog? I know that I need a Script attached to a desired line of the Dialog with DLG Editor but I have no idea how to make that Script.

I've been checking with Kotor Tool the lists in BIFs-->scripts, bif-->Script, Compiled and Script Source, and in RIM's-->Modules-->..._s.rim-->Script, Compiled but I've been unable to identify any that I could (re)use.

...and someone can explain how make dissappear a NPC and dissappear fading out?

Thanks in advance

Share this post


Link to post
Share on other sites
58 minutes ago, Obi Wan Pere said:

...and someone can explain how make dissappear a NPC and dissappear fading out?

Thanks in advance

Check out the tutorials section there are some fairly detailed ones in there as well as some simpler ones.

Yes you create a .dlg file, link it in the conversation field of the .utc file, dialogs basically are cutscenes, so .dlg files are used to structure cutscenes.

below is an example of a script I use to start a conversation with the lead rodian of the next example who just left that level.

Spoiler

void main() {
  if(GetGlobalNumber("SLE_FIREBLOODS") == 1)
  {
    object oEntering = GetEnteringObject();
    if ((!GetIsPartyLeader(oEntering))) {
      return;
    }
    object oRodian2 = GetObjectByTag("rodian2", 0);
    AssignCommand(oRodian2, ActionStartConversation(oEntering, "fireblood", 0, 0, 0, "", "", "", "", "", "", 0, 0xFFFFFFFF, 0xFFFFFFFF, 0));
    DestroyObject(OBJECT_SELF, 0.0, 0, 0.0, 0);
  }
}

below is an example of a script I use to have four rodians leave the area and dissapear when they get to the door.

Spoiler

void main() {
    object oRodian2 = GetObjectByTag("rodian2", 0);
    object oRodian1 = GetObjectByTag("rodian1", 0);
    object oRodian3 = GetObjectByTag("rodian3", 0);
    object oRodian4 = GetObjectByTag("rodian4", 0);

    location location1 = Location(Vector((0.1), -14.1, 0.1), 0.0);
    location location2 = Location(Vector((0.1), -11.5, 0.1), 0.0);
    location location3 = Location(Vector((-12.6), -10.5, 0.1), 0.0);

    vector struct4 = Vector(0.1, -15.5, 0.1);
    location location5 = Location(struct4, 0.0);

    AssignCommand(oRodian1, ActionMoveToLocation(location1, 0));
    AssignCommand(oRodian3, ActionMoveToLocation(location1, 0));
    AssignCommand(oRodian4, ActionMoveToLocation(location1, 0));

    AssignCommand(oRodian2, ActionMoveToLocation(location3, 0));
    AssignCommand(oRodian2, ActionMoveToLocation(location2, 0));

    ActionDoCommand(SetCommandable(1, oRodian2));
    ActionDoCommand(SetCommandable(1, oRodian1));
    ActionDoCommand(SetCommandable(1, oRodian3));
    ActionDoCommand(SetCommandable(1, oRodian4));
  
    AssignCommand(oRodian1, ActionMoveToLocation(location5, 0));
    AssignCommand(oRodian3, ActionMoveToLocation(location5, 0));
    AssignCommand(oRodian4, ActionMoveToLocation(location5, 0));
    AssignCommand(oRodian2, ActionMoveToLocation(location5, 0));
    AssignCommand(oRodian4, ActionOpenDoor(GetObjectByTag("sle99_exit01")));

    vector struct5 = Vector(0.1, -17.5, 0.1);
    location location6 = Location(struct5, 0.0);

    AssignCommand(oRodian1, ActionMoveToLocation(location6, 0));
    AssignCommand(oRodian3, ActionMoveToLocation(location6, 0));
    AssignCommand(oRodian4, ActionMoveToLocation(location6, 0));
    AssignCommand(oRodian2, ActionMoveToLocation(location6, 0));

    AssignCommand(oRodian1, ActionDoCommand(DestroyObject(oRodian1, 0.0, 0, 0.0)));
    AssignCommand(oRodian3, ActionDoCommand(DestroyObject(oRodian3, 0.0, 0, 0.0)));
    AssignCommand(oRodian4, ActionDoCommand(DestroyObject(oRodian4, 0.0, 0, 0.0)));
    AssignCommand(oRodian2, ActionDoCommand(DestroyObject(oRodian2, 0.0, 0, 0.0)));

    ActionDoCommand(SetCommandable(0, oRodian1));
    ActionDoCommand(SetCommandable(0, oRodian3));
    ActionDoCommand(SetCommandable(0, oRodian4));
    ActionDoCommand(SetCommandable(0, oRodian2));

  SetGlobalNumber("SLE_FIREBLOODS",1);
}

It has all four of them walk through a set of locations before they get to the door, then has the lead rodian open the door as well as destroys them making them dissapear.

Hopefully that helps or gives you some examples to work with, but there are some decent tutorials available worth checking out.

Note : everything here is scripted for K2, so there may be slight differences to apply before it will compile.

Thor110

Edited by Thor110
Note
  • Thanks 1

Share this post


Link to post
Share on other sites

@Thor110

First, thanks for the fast response!!

Aside a small graphic MOD it's the first time I try with something like this.

Attaching a .dlg file into a Placeable structure (with K-GFF) like is done with a NPC simply doesn' work. I mark the Placeable as "usable" (and in fact it becomes "usable" in game) but no dialog is launched. I don't know if I'm doing something wrong or if the system for make a conversation with a Placeable is another.

The last days I've been searching and reading several tutorials here and there (and found a lot of fallen links), most of them useful, some of them useless or, some time, unable to reproduce for myself what was told. Sure I've overpassed something interesting but I don't find nothing related with what I'm questioning. That's the "why" of the post.

I've been able to compile completely playable, "talkable" and "fightable" NPCs, but after the conversation/fight I want to launch one of the existing .bik (cutscene) and after that make the NPC dissappear fading out (without move).

At this moment almost all I need to continue the work is based in scripts but I don't know make them.

I'll take a careful look at your exemples.

Thanks again

Edit. BTW!!!! your 'KotOR Modding Tutorial Series' has been one of those very useful!!. And a lot of things that I hope can do in a close future.

Edited by Obi Wan Pere
  • Like 1

Share this post


Link to post
Share on other sites
12 minutes ago, Obi Wan Pere said:

Attaching a .dlg file into a Placeable structure (with K-GFF) like is done with a NPC simply doesn' work. I mark the Placeable as "usable" (and in fact it becomes "usable" in game) but no dialog is launched. I don't know if I'm doing something wrong or if the system for make a conversation with a Placeable is another.

Placeables need an extra step to make them talk.

void main()
{
	ActionStartConversation(GetFirstPC());
}

Put that script in the placeable's OnUsed event and it will work.

  • Like 2
  • Light Side Points 1

Share this post


Link to post
Share on other sites

Ah I didn't really think about that part as I thought it was either similar or not too dissimilar to figure out, my bad! But thankfully someone has got you the answer.

1 hour ago, Obi Wan Pere said:

Edit. BTW!!!! your 'KotOR Modding Tutorial Series' has been one of those very useful!!. And a lot of things that I hope can do in a close future.

Good to know they have been helpful, I hope to write more in the future so let me know if there are any topics I can cover.

  • Like 1

Share this post


Link to post
Share on other sites

@TamerBill

One question. Can I use the same compiled Script (as a "generic" Script, even with the same name) with any other "talkable" Placeables (of course in the same module)? Or I need, despite be the same Script, compile different .ncs for each Placeable? I guess I can use the same file.

Share this post


Link to post
Share on other sites
59 minutes ago, Obi Wan Pere said:

@TamerBill

One question. Can I use the same compiled Script (as a "generic" Script, even with the same name) with any other "talkable" Placeables (of course in the same module)? Or I need, despite be the same Script, compile different .ncs for each Placeable? I guess I can use the same file.

Yeah, it's fine, same script file for any placeable that just needs to start a conversation.

  • Like 1

Share this post


Link to post
Share on other sites

Just now I was testing another thing. I found a Script for get XP, I compiled and attached it to the last line of the conversation in DLG Editor and really works fine ...but every time I "talk" with the object it gives me XP...

void main()

{

GiveXPToCreature (GetFirstPC(), XXX);

}

Share this post


Link to post
Share on other sites

Ohh... another small -and maybe stupid- thing. Can I erase the .nss files created by the Kotor Text Editor after compile and get the .ncs files?

They're compiled within the .mod file but I think their not needed.

Share this post


Link to post
Share on other sites

Correct, nss files do absolutely nothing by themselves. Generally modders will keep theirs around for reference (easier to read an nss than an ncs) and in-case they need to make changes and recompile the script. Some people also consider it polite to upload the nss alongside the rest of the mod so that other modders can learn from it/see what you did. But mechanically speaking, the game will work the same whether you delete them or not, the game is only reading the ncs files.

  • Like 1

Share this post


Link to post
Share on other sites

This is the solution and the Scripts provided by @TamerBill that solve the problem getting infinite XP.

First of all is needed add a variable to the Globalcat.2da file (open it with the 2da Editor of Kotor Tool) and at the empty boxes type a subsequent number, a whatever name you want to identify the variable and type Boolean. (Selfexplanative when you see the file open).

Save and overwrite the original Globalcat.2da (as always very recommendable make a backup of the file before touch nothing).

And these are the Scripts for make working the thing:

This is the Script for get XP

void main()
{
	GiveXPToCreature(GetFirstPC(), XXX);
	SetGlobalBoolean("nameofvariable", TRUE);
}

And this is the Conditional Script for avoid get infinite XP

int StartingConditional()
{
	if (GetGlobalBoolean("nameofvariable") == FALSE)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

For sure some things can differe from one user to another but I've thought it can be, at least, orientative.

Share this post


Link to post
Share on other sites

There's no need to create a new global unless you need to track something across multiple modules. If you are only interacting with a single object/creature via one DLG then you can just use one of the existing locals that are set up for that purpose.

Share this post


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

you can just use one of the existing locals that are set up for that purpose.

That means that there are "free" variables already in Globalcat.2da for to use or how it works?

Better said, what and where are these locals? (newbie question)

Share this post


Link to post
Share on other sites
26 minutes ago, Obi Wan Pere said:

First of all is needed add a variable to the Globalcat.2da file (open it with the 2da Editor of Kotor Tool) and at the empty boxes type a subsequent number, a whatever name you want to identify the variable and type Boolean. (Selfexplanative when you see the file open).

You could just use k_con_talkedto.nss for the conditional, it is a global script to check whether or not you have talked to that NPC before, meaning that tree of dialog can only be accessed once. ( if applicable in this situation ) it uses the talked to flag on the NPC.

Edited by Thor110

Share this post


Link to post
Share on other sites
3 minutes ago, Thor110 said:

it is a global script to check whether or not you have talked to that NPC before

Work as well with placeables? that is my case.

Share this post


Link to post
Share on other sites

Like most things in scripting there's more than one way to skin a fish.

Local variables are stored inside each object, while global variables are stored in the save file. If you wanted to have something later in the game check to see if you ever read that datapad then you'd need a global. If it never comes up again then you could get away with using a local.

  • Like 2

Share this post


Link to post
Share on other sites
2 minutes ago, TamerBill said:

Like most things in scripting there's more than one way to skin a fish.

Local variables are stored inside each object, while global variables are stored in the save file. If you wanted to have something later in the game check to see if you ever read that datapad then you'd need a global. If it never comes up again then you could get away with using a local.

You can also just check if they have the datapad in their inventory :)

8 minutes ago, Obi Wan Pere said:

Work as well with placeables? that is my case.

Ah I doubt it / am not sure, I forgot you are working with a placeable, by the sounds of it you might be better off with a new global variable and making sure to continue using that variable more than once. ( depending on the extent of your use or need for the variable anyway ) 

  • Like 1

Share this post


Link to post
Share on other sites

Making it easy...

The object is a Datapad that cannot be taken, just used (Dialog), and never forever you'll see it again, among other things because it's in a ship that is about to crash... :lol:

Share this post


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

You can set a local on a placeable or even the entire area. It's not limited to creatures.

Does that include the talked to flag? To be quite honest, I haven't found a list of the local variables as reference yet, or are you just talking about a variable? As I know there is that large list of numbers that refer to local variables, however I do not know where they are right this second, I think in a 2DA iirc but I am not sure, perhaps you could point me and this newer user towards it?

Share this post


Link to post
Share on other sites

If you are going to get into scripting, you'll be spending lots of time rewriting stuff. Comes with the territory. If you are making something for you self, by all means hack it together however you want. If you are planning on releasing something publicly though then you should be willing to refine it to make sure you don't do anything that isn't strictly necessary. It will make your life easier in the long run anyway when you come to setting up a TSLPatcher config.

TalkedTo isn't anything special or unique. It's just local boolean constant 10. They added an extra utility function for it, but under the hood it's still just Get/SetLocalBoolean. If you want to use the strings and the functions for them outside generic scripts, you'll need to set k_inc_utility as an include.

  • Like 2

Share this post


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

TalkedTo isn't anything special or unique. It's just local boolean constant 10. They added an extra utility function for it, but under the hood it's still just Get/SetLocalBoolean. If you want to use the strings and the functions for them outside generic scripts, you'll need to set k_inc_utility as an include.

Perfect response, thank you and good to know that it can be used on placeables also.

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.