Thor110

[TUTORIAL] - KotOR Modding Tutorial Series

Recommended Posts

[TUTORIAL] - KotOR Modding Tutorial Series

These tutorials should be enough to get anybody started making levels for the game using the available resources and tutorials / tools etc

Available Source Material & Tools

These are the tools I use for modding the game.

tools.thumb.png.25733fa23cdbf8f2c2bcbf6f6841ec69.png

I also use the KotOR Level Editor which requires Unity, but I started modding using many of these tools and tried to make sure I had a tool for working with each and every filetype if possible.

 

Lots of source material is available as well as many tutorials, some old, some new and very detailed information on the filetypes and the game itself.

.nss scripts for every script I have been able to access from both games are included within the .mod files for my project which can be opened with the latest ERFEdit.exe available via the KotOR Modding Tools Section on the Downloads page of this site. ( NOTE : I will be removing them when the project reaches a final release, but I will make sure to post them somewhere for people to access )

 

If there are not then I have either not included them for some reason and will do in future as soon as I notice or I have not been able to decompile them using DeNCS.jar and nwnnsscomp.exe. ( I think below is an example of the only scripts that I haven't included .nss counterparts for and they can easily be decompiled using the following tutorial anyway, I believe the .nss scripts for them exist in another level and I chose not to put them into multiple levels, either way I have them in my source scripts folder )

 

Some scripts from KotOR1 require the files to be trimmed of some excess bytes, there is some information on it around here somewhere and I will post a link to it when I next find it, the scripts in question are some of those from Tatooine, Manaan, Kashyyyk and the Unknown World.

Actually Decompiling Scripts

Spoiler

In order to decompile scripts you are going to need DeNCS and nwnnsscomp.exe which can be obtained via the downloads section of this site amongst the modding tools section.

dencs.png.1280db2b8c742ce37715243079261d70.png

Then you can open the javascript runtime file which will launch the decompiler.

nwnnsscomp.thumb.png.ab0310338b1540dccafc08a88000b6c6.png

From here as an example I am using ERFEdit to open a level from my project, which also contains the .nss scripts for every script which people are free to use to learn from and make their own mods with.

erfedit.png.d539f4a38498272b8db759510c9d4cd6.png

Using ERFEdit or another method obtain the script you wish to decompile.

483341213_nssscriptsincluded.thumb.png.92b569c1b4bc03487d36d25a568e6201.png

Once you have done so, drag and drop it into the DeNCS window.

dencswindow.png.5a522ce646711cbceca0bc51fb590cbf.png

Once you have dropped it into the programs window it will look like the image below.

draganddrop.thumb.png.6b26219b80090100428a6185d5a33332.png

From here you can right click and select "View Decompiled Code" or you can the options to set the default directory to save the files to and then select File and Save As appropriately.

decompiling.png.7456f269381ce06f08b3de50322941cc.png

If you view the decompiled code you can take a look and check out the script before you decide to save it, you can also decompile multiple scripts at a time as well as save them all at once.

The log at the bottom of the window will notify you of any failed attempts at decompiling scripts, it will always give a warning about a partial issue recompiling the script.

decompiled.png.d85f72bad12655928dac8288edc8481f.png

Hopefully that helps and will help anybody figuring out how to decompile scripts for the game.

Feel free to use any of the source scripts available in any part of my project to learn from or create new mods with and please give credit appropriately if and where necessary.

KotOR1 ( Port )

https://www.moddb.com/mods/kotor-ii-tsl-expanded-galaxy/downloads/k1-port-install-104

KotOR2 ( Main )

https://www.moddb.com/mods/kotor-ii-tsl-expanded-galaxy/downloads/k2-main-install-104

 

PLEASE do not redistribute the entire project anywhere without my express permission, but feel free to learn from the source material to make as many modifications to the game as you wish.

If you wish to work on the project or contribute by offering or allowing your mod to be included with the project feel free to contact me on here or elsewhere.

 

In future I might go beyond these basic scripting tutorials and add other types of tutorials such as texturing and modelling that are focused around KotOR2 TSL or working with others towards making a comprehensive KotOR modding guide.

Most material I write will be aimed at KotOR 2 TSL, though alot of the structure of the game is very similar between them both if not almost identical.

 

For now here are some really basic written tutorials for getting setup with Blender and modding for KotOR or just messing around with the models from the game.

I will continue to work on these providing screenshots and more as necessary.

Blender Tutorial 00 - Getting Blender Setup

Spoiler

Getting Setup

I suggest using Blender 2.92 and the latest version of the kotorblender plugin.

Blender 2.92 ( 3D Modelling Software )

https://www.blender.org/download/releases/2-92/

kotorblender ( \addons\kotorblender\plugin-files )

This plugin is used for blender and needs to be placed in C:\Users\your-user-name-here\AppData\Roaming\Blender Foundation\Blender\2.92\scripts\addons

https://deadlystream.com/files/file/1853-kotorblender-for-blender-28/

NWN Model Viewer

This can load all the models for quick / easy viewing provided you have the .mdl, .mdx & .tga files associated with the model in the folder.

https://neverwintervault.org/project/nwn2/other/tool/simple-model-viewer-64-bit-patch

Folder full of Assets

Getting set up with a folder full of assets takes but a moment and a bit of space.

Use KotOR Tool to extract the following archives. ( models.bif, textures.bif, lightmaps.bif, swpc_tex_gui.erf & swpc_tex_tpa.erf )

models.png.3643a5d9f1cbb09110069f0c4ef8fc11.pngtextures.png.e5fcd71b48a36ed477bc6c8de3599ff7.pnglightmaps.png.7c31d03c99f4321c770fbbba4ba9909e.png2084373610_guitextures.png.6c6d182b393c20b7055cd56f0e1ddb4d.pngtpa.png.e8004e3e3e3808e7e3ac4a206999a2e6.png

Then convert these using the batch tool from MDLEdit ( make sure it is set to the correct mode for whichever game you are converting files for, I have shown extracting K2 files above, but the process is almost identical for K1 )

mdledit.png.9ff9fb828dfb2677fff54bf8029ce38b.png

After having converted them to ASCII and having converted all of the textures from .tpc to .tga you should have no problem getting them loaded up into Blender 2.92 using the kotorblender plugin.

The following is a description of how I converted the textures from .tpc to .tga

I used xoreos tools and the tpc2tga.bat that is available somewhere on the DeadlyStream Forums.

Basically download xoreos tools and get the above mentioned batch file ( tpc2tga.bat ) and or find a similar method to convert all of the .tpc files to .tga files, you can then delete the remaining .tpc files, if you put them back into the game you might require the .txi data which will have to be extracted separately, they exist within the .tpc files, but not the .tga files.

Below is a link to the relevant topic and solution mentioned by DarthParametric

https://deadlystream.com/topic/6075-anyone-still-have-the-tpc-to-tga-executable/

From here it should be as simple as turning on the kotorblender and importing a model.

kotorblender.png.b317d5f590ccf41ee1f7e6b9d6f06908.png

Provided you put the files in the correct location you will be able to tick the box in the preferences menu.

preferences.png.4089f75ef0b35c6ea30a5a255d4b0df4.png

From here you will be able to import an ASCII model and the associated textures.

import.png.bba7daf5eb2380aae02ada5b3b1623b5.png

I imported 3dgui.mdl

3dgui.thumb.png.216f3700570f836c8ccd67c1d9368f69.png

From here it should be fairly straightforward to learn from all the existing in-game models from both games as examples to work from regarding how to structure assets.

Assets are generally listed throughout the various 2DA files associated with the game.

Blender Tutorial 01 - Asset Editing ( INCOMPLETE TUTORIAL )

Spoiler

In general I suggest learning to model in Blender from YouTube tutorial or other online resources, then using what you can to learn from the existing models of the game and make whatever you want using them as an example to work from.

 

Opening and editing a level, character or asset from within the game.

In order to do this you will need to first use KotOR Tool to extract all of the models and textures to a directory on your computer.

The textures need to be in .tga format, which unfortunately means extracting them one at a time, or using some of the tools around to convert them all at once from .tpc to .tga

You will also need to extract the lightmaps to that same directory if you are planning on working with the levels and the layout or .lyt files if you are planning to load an entire level at once into Blender.

I also use the NWNModelViewer to quickly view the various models throughout the game using a directory full of it's binary file format models.

You will then need to use MDLEdit to convert the model you want to an ASCII file format model. ( Or batch convert to convert lots of models at once )

From here you should easily be able to open any asset from within the game via .mdl or .lyt

Once you have modelled what you wanted and used click + shift drag to place it within the heirarchy of the asset

You will then be able to select the asset and it's entire heirarchy and export it to .mdl

Blender Tutorial 02 - Creating A Placeable

Spoiler

In order to create a placeable I suggest importing a placeable to use as your template to work with.

keeping the "lookathook" and using click + shift and drag to place your model within the correct heirarchy for the model.

modelling the walkmesh area to match and moving the lookathook to where you want the player to be able to click on the placeable object.

linking.png.f7c28e1aa2716f333b3c4b7e210ee44d.png

I kept the existing walkmesh ( PLC_*_pwk  ) and renamed it to match the placeable I was making.

Moved the lookathook to where I wanted it to be or where I want it to be for now.

And selected then the object I had pasted over from the Ebon Hawk and held shift on the keyboard to add it to the heirarchy of the main object "PLC_baoplace"

from here you will need to click on the placeable and make sure that the entire heirarchy is selected and export it to .mdl format ( ASCII )

then use MDLEdit to convert it back to binary.

mdleditagain.png.3ee34c6495c06e91a5b86a1176a212fe.png

and add it to the placeables.2da in order to be able to place it somewhere in a level.

baoplace.thumb.png.64a310e6849f6f3788aef69a8f3be0e2.png

Blender Tutorial 03 - Character Editing

Spoiler

As with all the above tutorials I suggest getting a folder full of all the models ( .mdl, .mdx, .wok, .pwk, .tga, .lyt ) as well as the .mdl.ascii files made by MDLEdit in order to quickly load any model you want into Blender and be able to edit it or alter it as necessary.

From here editing any asset within the game shouldn't be too difficult as well as making new assets provided you are able to make use of existing materials, tutorials, resources and the tools available in order to achieve your goal.

Sorry these tutorials are not very in-depth or detailed, I will work on them more in the future.

For now getting assets loaded into Blender is often peoples first trouble step.

As soon as I find the relevant links I will post about how to use Xoreos tools and the tpc2tga.bat file to convert all the textures for easily loading them up.

 

When converting a character model make sure to have the relevant supermodel in the same folder as the model being converted.

The supermodel can also be seen if you highlight or click on the header section of the model in MDLEdit at the bottom of the program. As shown for this the Supermodel is NULL meaning there isn't one.

header.png.70c0a44f0d278a7c790e5fc81c4bb607.png

Hopefully this will help anybody get characters or other assets loaded into Blender for whatever they need them for.

Outdated Tutorials & Intro

Spoiler

Download Downloads for my KotOR Modding Tutorial Series are available on the ModDB page. https://www.moddb.com/mods/kotor-ii-tsl-expanded-galaxy/downloads/kotor-modding-tutorial-series
NOTE : I was writing / organising the tutorials differently when I started the document versions and so they are a little outdated / incomplete in comparison to what is here, but I still have plans to go back and cover some of the topics I planned to in the documents. ( DOWNLOADABLE VERSION IS OUTDATED FOR NOW )

Update Please let me know how you get on with these tutorials, if you have any problems or suggestions for how I could improve anything even grammar / formatting I would really appreciate it, I hope to construct a tutorial series that covers modding of both the Expanded Galaxy Project and both KotOR games from basic modifications to Total Conversion Modifications set in the Old Republic Era of the Star Wars Universe, anything beyond this would require more work on your part, I believe it would be possible to make some interesting stories using the Odyssey engine for Point & Click type games or RPGs in general, but I believe it is better suited towards the Star Wars Universe, more specifically the Old Republic Era due to the abundance of content available in both games, but it could also be re-purposed for other Star Wars Stories from any time.

https://www.moddb.com/mods/expanded-galaxy-project-kotor-12/downloads/kotor-modding-tutorial-series

I will be posting my tutorials on ModDB as well, here is my first link which is a rough tutorial and overview of the future tutorials I have planned, both mods pages on ModDB will also have files to go alongside each mod and help streamline the process of creating levels for both games in the KotOR series and for the Expanded Galaxy Project.

https://www.moddb.com/mods/kotor-ii-tsl-expanded-galaxy/tutorials/streamlining-module-creation

Individually written and quite specific tutorials, mostly scripts and guidance towards achieving specific goals or tasks.

01 - [TUTORIAL] - Creating a Module for TSL using a KotOR Map!

The first tutorial should be a great guide for porting a level from the first game into the second game as well as that it shouldn't be too difficult to work out how to do it the other way around from there on out!

Spoiler

Previous This tutorial has been updated and I have released it as an .odt series on KotOR modding I am starting to write, I am going to be writing a lot more tutorials throughout the process of creating my mods, documenting the entire process and writing a tutorial for each individual element of the game that I learn to modify, change or add to in order to help others create great content for both of the KotOR games and the Expanded Galaxy Project.

Tools Required

Kotor Tool
MDLEdit
K-GFF Editor
Bulk Rename Utility ( or Patience )

A copy of K1 & K2 ( Steam, GoG or original 4 CD version )

This tutorial will cover how to port the first module of the Endar Spire from K1 into K2, but the steps are very much the same for any module in the game. ( Open Spoilers to reveal images and instructions )

Layout Files - First open Kotor Tool, make sure your game directories are set, then open up BIF's>layouts.bif & extract "m01aa.lyt".

Spoiler

Extract "m01aa.lyt" to the override directory for your module"

Screenshot_4.png

The Lightmaps

Spoiler

Extract "lightmaps.bif" ( not numbered, the first one ) to a folder, delete everything in the folder except m01aa, so click the first m01ab file and scroll to the bottom, then hold shift and click the last file to make this easier.Screenshot_5.png

Model Files

Spoiler

Then extract the entire "models.bif" directory ( this will save you a lot of time ) and delete everything except m01aa ( .mdl, .mdx and .wok files )Screenshot_6.png

Module File Contents

Spoiler

Then open RIM's>Modules> and extract end_m01aa.rim & end_m01aa_s.rim directories.Screenshot_1.pngScreenshot_2.png

MDLEdit - Converting Map Files!

Spoiler

Open MDLEdit, set it to KOTOR1 mode, then batch > convert > to ascii, all of the models for m01aa.

Make sure to set the mode for K1 before converting to ascii and then set the mode back to K2 when converting to binary.
Screenshot_14.png.b733d75d1ca2922074216cf17a149042.pngScreenshot_13.png.5b123d1702f44e59bd970674b2855811.png
Screenshot_11.png.bb15831e9f8c90f9fad69eb450d59961.pngScreenshot_12.png.349b130892ad1510cc9a5b292b70b05c.png

When it is complete, set the program to KOTOR2 mode, then batch > convert > to binary all the ascii files you just converted ( arrange by type to easily select the ascii files )

You will also need to extract the relevant texture pack you wish to use.

Texture Packs, Loading Screen & Minimap.

Spoiler

Extract "swpc_text_tpa" ( these are the high resolution textures )

"tpb" & "tpc" are medium and low resolution versions of the same textures.

if you want to individually single out which .tpc files you need for the module you are welcome to do so.

At some point I will also write a short / easy and quick way to get just the .tga's necessary for an individual module.Screenshot_3.png
Minimap
Screenshot_7.png.fc4a475a6f2cde4c50b2ff037336684a.png
Loading Screen
Screenshot_8.png.cc5e733763971f264ca2c561700428d5.png

 

I have just extracted the three texture packs ( lightmaps, gui and tpa ) in their entirety in order to save singling out which files go to which modules because it is easier for the moment and suits the purpose of my project.

Use K-GFF Editor to remove any references to scripts in the .are, .git and .ifo files. Change the Name String Reference to -1, right click and Add String, change this string to "Endar Spire - Above Taris" ( but you do not have to remove the entries for this module to work )

Spoiler

Use K-GFF Editor to remove these references.

Use Kotor Tool, click the ERF button, save the modules as "end_m01aa.mod"(make sure to include the .mod extension) set the dropdown to MOD and select add files, then add the .are, .ifo, .git, .pth and .utd files.

Spoiler

Use the ERF button and build the module.
Screenshot_10.png.0dacf1f0c7759c76b5d39f0f9762c1c6.png
Screenshot_9.png

Make sure to delete the original maps and ascii conversions, as well as to rename all of the files using patience or I suggest Bulk Rename Utility and remove every reference of "-mdledit-mdledit" from the .mdl, .mdx and .wok files. ( you may also want the .dwk & .pwk files )

After creating the module copy it to your Modules folder and copy the rest of the files over to the override folder, you can then use the warp cheat to access the level "warp end_m01aa"

This is just a rough write up of the tutorial I have just converted this module again from scratch at the same time and will do it again taking screenshots and rewriting this short tutorial.~
Download Link  https://drive.google.com/file/d/1NWCbdvb4mk44EHVOYPUfUdgKTJh7bBxD/view?usp=sharing
You will need 7zip to extract the contents.

Currently the stars and lasers / anything going on outside does not appear, if you wish to fix this just extract the missing contents from the texture packs.

K1 & K2 You should also be able to use this tutorial to make a module for both KotOR games as well as my Expanded Galaxy Mod, I will also update it so that completely custom areas can be made using parts already in the game allowing for much more diverse level creation.

Note It seems the process is the same for porting TSLmodules to KotOR, but for the moment I am unable to port the outside areas of Telos, Dxun or Dantooine due to foliage being spread across the map due to Vector Calculations being off during the conversion process. ( Noting that you need to be in K2 mode using MDLEdit when converting to ASCII then K1 mode when converting back to binary, exactly the same process I used for KotOR to TSL works in reverse )

Spoiler

These are the current results, very similar to Telos Restoration Zone and Dantooine.

DXUN_K1_0001a.thumb.png.72f072211c0c37dec50385973cdae6b6.png

Us

These are some useful links that I have found around that might guide you towards making mods for the game.

Useful Links for learning to mod TSL & KotOR

Spoiler

Links that I have found helpful

My most recent attempts have lead me to this tutorial - Adding Planets To Galaxy Map in TSL
https://web.archive.org/web/20130124075620/http://www.lucasforums.com/showthread.php?t=169825
I have also used this tutorial to name the module - Naming a custom module
https://web.archive.org/web/20121204061936/http://www.lucasforums.com/showthread.php?t=194986
This tutorial helped me add loading screens to my modules - Custom Loadscreens
https://web.archive.org/web/20150911045357/http://www.lucasforums.com/showthread.php?t=194903
Thanks to this next tutorial I was able to add custom music to my module - Adding Custom Music to KOTOR
https://web.archive.org/web/20121016090124/http://www.lucasforums.com/showthread.php?t=180773
This tutorial I have not used yet but looks really well made and is for adding custom doors - Door Modelling Tutorial
https://web.archive.org/web/20151120115337/http://www.lucasforums.com/showthread.php?t=186921&highlight=door
A long series of video tutorials for modelling a new area - Modelling an new area!
https://web.archive.org/web/20150912222837/http://www.lucasforums.com/showthread.php?t=195261
some of the tutorials link to downloads for the actual tutorial itself, luckily some if not most of the mediafire links are still active, you just have to edit out the wayback machine portion of the url after following the link.

I have also come across these tutorials on youtube which others might find handy and I am noting down here for reference / credit to any tutorials that have helped me along my way.
New Area in KotOR Part 1/3 - I haven't used any of these videos yet but they cover information I might need.
https://www.youtube.com/watch?v=NvXEX1acl4I
Modules Part 1 Overview - The uploader of this video also has lot's of other kotor related modding videos that look and sound useful.
https://www.youtube.com/watch?v=ykvg3Bqohqs
KotOR 1 & 2 Animated Texture Tutorial - This tutorial will definitely be helpful for making modifications to the game.
https://www.youtube.com/watch?v=GBjWzNFdgg8
Using an example set by Effix in the Mod Requests section I have made a little more progress and managed to load the map correctly by including the .mdx, .wok and .lyt files.
https://deadlystream.com/topic/6665-tsl-yavin-station/

Useful Tutorials & Information From DeadlyStream ( There are quite a few in the Tutorials Section worth reading )

https://deadlystream.com/topic/4748-lightmapping-an-area-model/
https://deadlystream.com/topic/4743-how-to-reskin-a-module/
https://deadlystream.com/topic/4034-setting-a-spawn-point-in-a-custom-module/
https://deadlystream.com/topic/524-conditional-scripts/
https://deadlystream.com/topic/4506-plot-usable-items-in-k2/

Thor110

In the following post in this topic are many more tutorials that I am working on to guide people through the process of making mods for KotOR.

Edited by Thor110
Decompiling Scripts
  • Like 4
  • Light Side Points 1

Share this post


Link to post
Share on other sites

02 - [TUTORIAL] - Creating a Merchant - TSL

Spoiler

Merchants

In order to add a merchant, you will need to first add a character to whatever module you want and create a .dlg (Dialog) file which is used by the .utc (Character) you will then need to add any relevant lines of dialog for your character to speak.

628377620_thorutc.png.fccf2152946d08b3ba0fe2c791695098.png

Make sure to name the dialog file in the Conversation section of the utc file.

1083054639_thordlg.thumb.png.af2da43ef5204bd9c5f0d0b815fbae47.png

From there you will need to link it to a script using a line of dialog.

The following is an example of the script you will need to use to launch the merchants inventory window.


void main()
{
  object oStore = GetObjectByTag("merchant_file"); // this is the .utm file listing your merchants inventory
  if(!GetIsObjectValid(oStore))
  	oStore = CreateObject(OBJECT_TYPE_STORE, "merchant_file", GetLocation(OBJECT_SELF));
  if(GetIsObjectValid(oStore))
  	DelayCommand(0.5, OpenStore(oStore, GetPCSpeaker()));
}

this script then needs to be compiled using the KotOR Scripting Tool. ( Make sure to set it to KotOR 2 Mode )

It will open the .utm (Merchant) file which contains a list of the items which are available for purchase.

1026145840_thorutm.thumb.png.9db2c1b42681e8885a858681df5235c1.png

Another example is to use global variables as conditions to determine what stock your merchant has available.

The next example is a script I am using for the Yavin Orbital Station, it determines which merchant script to load dependant on how many Jedi Masters the Exile has already encountered during their playthrough. ( Between 0 & 4 )


void main()
{
  if((GetGlobalNumber("000_Jedi_Found") == 0))
  {
    object oStore = GetObjectByTag("thor0");
    if (!GetIsObjectValid(oStore))
    oStore = CreateObject(OBJECT_TYPE_STORE, "thor0", GetLocation(OBJECT_SELF));
    if (GetIsObjectValid(oStore))
    DelayCommand(0.5, OpenStore(oStore, GetPCSpeaker()));
  }
  else if((GetGlobalNumber("000_Jedi_Found") == 1))
  {
    object oStore = GetObjectByTag("thor1");
    if (!GetIsObjectValid(oStore))
    oStore = CreateObject(OBJECT_TYPE_STORE, "thor1", GetLocation(OBJECT_SELF));
    if (GetIsObjectValid(oStore))
    DelayCommand(0.5, OpenStore(oStore, GetPCSpeaker()));
  }
  else if((GetGlobalNumber("000_Jedi_Found") == 2))
  {
    object oStore = GetObjectByTag("thor2");
    if (!GetIsObjectValid(oStore))
    oStore = CreateObject(OBJECT_TYPE_STORE, "thor2", GetLocation(OBJECT_SELF));
    if (GetIsObjectValid(oStore))
    DelayCommand(0.5, OpenStore(oStore, GetPCSpeaker()));
  }
  else if((GetGlobalNumber("000_Jedi_Found") == 3))
  {
    object oStore = GetObjectByTag("thor3");
    if (!GetIsObjectValid(oStore))
    oStore = CreateObject(OBJECT_TYPE_STORE, "thor3", GetLocation(OBJECT_SELF));
    if (GetIsObjectValid(oStore))
    DelayCommand(0.5, OpenStore(oStore, GetPCSpeaker()));
  }
  else if((GetGlobalNumber("000_Jedi_Found") == 4))
  {
    object oStore = GetObjectByTag("thor4");
    if (!GetIsObjectValid(oStore))
    oStore = CreateObject(OBJECT_TYPE_STORE, "thor4", GetLocation(OBJECT_SELF));
    if (GetIsObjectValid(oStore))
    DelayCommand(0.5, OpenStore(oStore, GetPCSpeaker()));
  }
}

This script is used in the same way as the previous script which has only one merchant file but it will require 5 merchant scripts.

1124842862_thorstorenss.png.41ed69e1cef04f4f603c16c6a07c452b.png

Using the source script from the games files “a_playpazaak” you can also start a game of pazaak using the same process.

The following script will open a door on the map when you interact with a placeable, it could also be used in a dialog if you wish.


void main()
{
  object oDoor = GetObjectByTag("yav50_airlock");
  ActionOpenDoor(oDoor);
}

In this example the placeable “yav_panel50x.utp” which is an invisible placeable loads the above script “yav_panel05” in the OnUsed section which can be found using the KGFF editor on a “.utp” (Placeable) file, the script then opens the door called “yav50_airlock”.

Another useful property to note is the Static property of the doors, which can be used to determine whether or not the door can be selected by the player.

03 - [ADDITIONAL] - Using ERFEdit

Spoiler

ERFEdit is useful for extracting the contents of other module files, this can be handy to look up an example from another level.

In order to make use of the following three examples, you will want to use ERFEdit to extract the contents of the module, you will also need DLGEdit & K-GFF Editor, extract the files and examine them to hopefully save others time from searching through the Characters, Placeables and Alien Voice Overs.

You can also just spawn in each module and look around, each character or placeable will have their number references as their name.

Characters 0-700 approx

Placeables 0-400 approx

Dialog 0-42

With all of these testing rooms I have still had the main three mods I am planning to provide compatibility for ( TSLRCM, M478EP & Jedi Temple ( Coruscant ) Mods ) installed to the game, so if you do not some of their appearances may be missing.

04 - [ADDITIONAL] - Picking an NPC to place in your level - TSL

Spoiler

I was dreading finding a specific NPC to place around any of the levels I am working on so I drafted up these test levels with every NPC from TSL in them.

Using these modules you should have no trouble picking an NPC and identifying what number entry they are in the appearance.2da file.

Testing Rooms.7z

Screenshots

Spoiler

099dia

099dia.thumb.png.6e7b868b7357f68521edea0a356e7e0e.png

199dia199dia.thumb.png.19e4558213ccd58b88eee33b5aefd46c.png

299dia299dia.thumb.png.d6f9959f01f4034c569870adc976c37f.png

399dia399dia.thumb.png.49f43e4a919aa2efdcb8e0930e13e245.png

499dia499dia.thumb.png.c1499317e123261f17dda6aed437d965.png599dia599dia.thumb.png.34fdb632b850b7609df874b6f1fc61bb.png699dia699dia.thumb.png.0d82fc86889322975b8125661c0f136a.png

I hope this will be useful for others, I haven't made full use of it yet, but I can now roam around and pick out which NPC's I would like to place and not have to worry about finding their entry number, as well as having the ability to view nearly all of them at once.

05 - [ADDITIONAL] - Picking Placeables to fill your level with - TSL

Spoiler

I decided to do the same thing for placeables, so that I could not only look through them all at once but hopefully find it easier to populate the levels I am working on with placeables and NPC's.

Testing Placeable Rooms.7z

 

Screenshots

Spoiler

699plc699plc.thumb.png.e2a1d2a81e0e6b9b56b07cf28a782262.png

799plc799plc.thumb.png.c4495f0911addb109c564f4b44f8a78d.png

899plc899plc.thumb.png.d664401a36422973ca33e92731a2ea36.png

999plc999plc.thumb.png.48d33fa6f512a2b2b197baafcd3899c6.png

 

06 - [ADDITIONAL] - Picking Alien Voice Over Dialog for your level - TSL

Spoiler

In the same style as the placeables and characters, but contains one character per alien in the "alienvo.2da" file and a dialog entry for each type of voice over they can use, excluding null entries.

Alien VO Dialog Testing Room.7z

The Rakata & I think a few others don't have voice files even though the 2da file states that they do, I will go through these at some point.

Screenshots

Spoiler

000voi

1860657292_ALIENVOTESTINGROOM.thumb.jpg.a0640474c48174f01018943c68472d51.jpg

 

07 - [ADDITIONAL] - Placement & Rotation

Spoiler

The bearing of a placeable is it's rotation, characters have an X orientation and a Y orientation which also pertains to their rotation.

The below co-ordinates are what I am using for making a placeable rotate to face any of the cardinal directions.

I have seen that sometimes people over rotate from these numbers until they get to the right position, for example to face East can also be 4.5 approximately, but I have found the below values to be the best, if someone knows better please let me know.

I generally use KotOR Toolset to locate an item in an existing module and record its co-ordinates then I edit its co-ordinates using K-GFF Editor, from there I tend to test the level over and over again until I get the placement just right.

North
-3.1415901184082

West
-1.5707950592041

South
0

East
1.5707950592041

I realise they are using Radians or Pi, so this can be positive or negative accordingly, Pi itself is *3.14159265359 ( so that might be a more accurate value to use ) though I haven't used that just yet, but it will be such a minute change in rotation that it would be practically impossible to notice anyway.

But I have noticed some things in the game over rotate to get to the correct position, so I thought this might be worth noting for other users, I used other objects in game to determine North & South and went from there.

 

I also found the below example which is probably a lot more detailed, quoted from Lucas Forums by e-varmint

Spoiler

The "bearing" measurements for doors
and placeables in the .git file use radians instead of degrees. 

Degrees Radians
15= 0.261799388
30= 0.523598776
45= 0.785398163
60= 1.047197551
75= 1.308996939
90= 1.570796327
105= 1.832595715
120= 2.094395102
135= 2.35619449
150= 2.617993878
165= 2.879793266
180= 3.141592654
195= 3.403392041
210= 3.665191429
225= 3.926990817
240= 4.188790205
255= 4.450589593
270= 4.71238898
285= 4.974188368
300= 5.235987756
315= 5.497787144
330= 5.759586532
345= 6.021385919


by e-varmint

 

08 - [TUTORIAL] - Waypoint Markers

Spoiler

Below is the documentation left within the blueprint waypoint files within the game, when I have actually placed some myself and am more familiar with the process I will try to write a step by step for it as well.

"This is the default waypoint you may place to set a patrol path for a creature or NPC.
1. Create the creature and either use its current Tag or fill in a new one.
2. Place or make sure the WalkWayPoints() is within the body of the On Spawn script for the creature.
3. Place a series of waypoints along the route you wish the creature to walk.
4. Select all of the newly created waypoints and right click. Choose the Create Set option. ( The set will be defined by their numbers )
5. The waypoint set will have a set name of "WP_" + NPC Tag. Thus if an NPC with the Tag "Guard" will have a waypoint set called "WP_Guard". Note that Tags are case sensitive."

Bullet Point #1 Create your creature. ( .utc file which will be spawned using the .git file for the module )
Bullet Point #2 refers to what will be needed in the script. ( Example Scripts Below )
Bullet Point #3 Place your waypoints. ( placing the .utw files along a specified path using the .git file of the module )
Bullet Point #4 will be referring to the software they would have been using during development.
Bullet Point #5 refers to naming the waypoint files. ( "WP_Guard_01.utc" etc )

I have three script examples so far for NPC's walking, but I haven't used any of them yet so cannot confirm they work until I start populating the areas I am working with.

Continue Walking Waypoints - "walk_continue.nss"

Spoiler

#include "k_inc_generic"
#include "k_inc_debug"
#include "k_inc_treas_k2"

void main() {
    // Force them to continue walking waypoints. onEndDialog
  GN_WalkWayPoints();
}

Walk Around Randomly - "walk_random.nss"

Spoiler

void main() {
  // onHeartbeat
    AssignCommand(OBJECT_SELF,ActionRandomWalk())
}

Walk Waypoints On Spawn - "walk_spawn.nss"

Spoiler

#include "k_inc_generic"
#include "k_inc_debug"
#include "k_inc_treas_k2"

void main()
{
    GN_SetDayNightPresence(AMBIENT_PRESENCE_ALWAYS_PRESENT);
    GN_SetListeningPatterns();
    GN_WalkWayPoints();
}

 

09 - [TUTORIAL] - Scripting Basics

Spoiler

I will not cover much scripting, but when I am finished with the project all the source will be made available.

You will need KotOR Scripting Tool & possibly DeNCS if you plan to use it ( it can be helpful to get examples from other scripts already in the game to see how they handle certain events and to get an idea of the common operators, functions and the syntax )

The script is saved as a .nss file and then compiled into a .ncs file, I use KotOR Scripting Tool but I think KotOR Tools Text Editor can also compile scripts.

Remotely Opening A Door

Spoiler

void main()
{
    object oDoor = GetObjectByTag("yav50_airlock");
    ActionOpenDoor(oDoor);
}

The above script is called by an invisible placeable in front of the computer screens on the Yavin Orbital Station and the script itself is referenced in the OnUsed section of the associated .utp file, it is also getting the relevant door by its tag which is declared in the relevant doors .utd file.

That's a very basic script, you can also scroll through the KotOR Scripting Tool to see all the available commands on the right hand side, I will be posting basic scripts in this section and hopefully they might be useful for others.

Upon typing the command there is also a description shown in the bottom window of the program.

If you have trouble compiling a script, make sure that "nwscript.nss" is located in the games override folder, also check that the tool is set to KotOR 1 or KotOR 2 accordingly, another possible problem is your relevant registry entry which can either be added back in manually, or just run the "swupdate.exe" and it will update the registry entry ( I had this problem as I was using two seperate installs of KotOR 2 for testing )

10 - [EXAMPLE SCRIPT] - Spawning NPC's on Enter

Spoiler

Below is an example of an on Enter script spawning four NPC's via their utc file packaged with the .module but not placed in the levels git file.

In order to do this you will also need to add a waypoint to the git file to point to where to spawn your NPC.

This code can be used to spawn NPC's dependant on a Global Variable, it is also checking if the leader of the group already exists ( I should check if they all exist, but this works for the moment )

Spoiler

void main() {
  if(GetGlobalNumber("SLE_FIREBLOODS") == 1)
  {
    if (!GetIsObjectValid(GetObjectByTag("rodian2", 0))) {
      CreateObject(1, "rodian2", GetLocation(GetObjectByTag("wp_rodian2", 0)), 0);
      CreateObject(1, "rodian1", GetLocation(GetObjectByTag("wp_rodian1", 0)), 0);
      CreateObject(1, "rodian3", GetLocation(GetObjectByTag("wp_rodian3", 0)), 0);
      CreateObject(1, "rodian4", GetLocation(GetObjectByTag("wp_rodian4", 0)), 0);
    }
  }
}

Hopefully this short example helps.

11 - [EXAMPLE SCRIPT] - Making NPC's Hostile!

Spoiler

The below code changes the above spawned NPC's to being hostile and changes the Global Number for the Variable storing the state of that questline / encounter.

Spoiler

void main() {
  object oRodian2 = GetObjectByTag("rodian2", 0);
  object oRodian1 = GetObjectByTag("rodian1", 0);
  object oRodian3 = GetObjectByTag("rodian3", 0);
  object oRodian4 = GetObjectByTag("rodian4", 0);
  ChangeToStandardFaction(oRodian2, 1);
  AssignCommand(oRodian2, ActionAttack(GetFirstPC(), 0));
  ChangeToStandardFaction(oRodian1, 1);
  AssignCommand(oRodian1, ActionAttack(GetFirstPC(), 0));
  ChangeToStandardFaction(oRodian3, 1);
  AssignCommand(oRodian3, ActionAttack(GetFirstPC(), 0));
  ChangeToStandardFaction(oRodian4, 1);
  AssignCommand(oRodian4, ActionAttack(GetFirstPC(), 0));
  SetAreaUnescapable(1);
  SetGlobalNumber("SLE_FIREBLOODS", 2);
}
 

 

12 - [EXAMPLE SCRIPT] - Trigger talking to an NPC!

Spoiler

The below code requires a trigger to be placed in the level, on entering the trigger this script will fire.

It starts a conversation with the lead Rodian from the above examples.

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);
  }
}

 

13 - [EXAMPLE SCRIPT] - Make an NPC walk randomly

Spoiler

This script is assigned to the heartbeat function of the utc file for the NPC.

Spoiler

void main() {
  // onHeartbeat
    AssignCommand(OBJECT_SELF,ActionRandomWalk());
}

 

14 - [EXAMPLE SCRIPT] - Place a dead NPC

Spoiler

This script needs to be set in the spawn function for the NPC in the relevant .utc file.

Spoiler

void main() {
    effect efDeath = EffectDeath(0, 0, 1);
    ApplyEffectToObject(2, efDeath, OBJECT_SELF, 0.0);
}

 

15 - [EXAMPLE SCRIPT] - Starting Conditional

Spoiler

This script is an example of a starting conditional that can be used to check what module the player is in, this could be used for companion dialogs to check you are in a specific area in order to engage in a certain dialog option.

Spoiler

int StartingConditional()
{
    if ( ( GetModuleName() == "end_m01aa") ||
         ( GetModuleName() == "end_m01ab") ||
         ( GetModuleName() == "tar_m11ab")) {
    return TRUE;
  }
  return FALSE;
}

The example I have provided checks if it is any of the three named modules, if so it returns TRUE to the DLG, if not it returns FALSE.

It can be modified to check as many modules as required, I included three as an example to either cut down or expand upon.

16 - [TUTORIAL] - Companion Vendor

Spoiler

I recently came up with an idea for a "Droid Companion Vendor" which will sell droids to the player to replace any lost or missed companions throughout the game.

Screenshot_4.thumb.png.77a07860bc4e3ff6e4f6d13b9626a3bf.png

Also given that it demonstrates control of the party / companions, I thought I would work this into a tutorial.

When I have completed the level / vendor itself, I will come back here to write a tutorial, provide the files and give examples on how this could be used to create a Total Conversion

Screenshot_6.thumb.png.d4295410266a24ecd6410e637fe69334.png

There are a total of 50-55 Droid Types, the plan is to have either all or a select set of the best droids as options.

Screenshot_9.thumb.png.c21aeb02d2bfa405753e615a9c361a68.png

Maybe even spawning the droid next to the Vendor so that you can see them before buying them, or housing them in a store house with the droids you can purchase on display in the area.

Screenshot_7.thumb.png.4c83c0d0d76815caf4fa5a97fcb212ed.png

From here you will be able to purchase a new companion for any slot in the game.

Screenshot_8.thumb.png.45a05cb4af648a0ddef10278523336fa.png

for anybody interested here is the code for the conditional script I wrote to check if a specific players companion slot is free.

Spoiler

#include "k_inc_debug"

int StartingConditional()
{
    int nComp = GetScriptParameter( 1 );
    if ((IsAvailableCreature(nComp)) == FALSE)
        return TRUE;
    else
    return FALSE;
}

Here is a slightly different version that checks all companion slots at once.

Spoiler

#include "k_inc_debug"

int StartingConditional()
{
    if ((GetNPCSelectability(9)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(8)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(7)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(6)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(5)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(4)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(3)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(2)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(1)) == -1)
        return TRUE;
    else if ((GetNPCSelectability(0)) == -1)
        return TRUE;
    else
    return FALSE;
}

here is the code I use to preview the droid, spawning them at the location of the vendor.

Spoiler

void main() {
  string nDroid = GetScriptStringParameter();
  CreateObject(1, nDroid, GetLocation(GetObjectByTag("blackmarket", 0)), 0);
}

this code is then used to destroy them, if you don't purchase them.

Spoiler

void main() {
  string nDroid = GetScriptStringParameter();
  DelayCommand(0.1, DestroyObject(GetObjectByTag(nDroid), 0.0, 1, 0.0));
}

and here is the code I used to make them join the party.

Spoiler

void main() {
  string nDroid = GetScriptStringParameter();
  if ((IsAvailableCreature(9)) == FALSE) {
    AddAvailableNPCByTemplate(9, nDroid);
        ShowPartySelectionGUI("k_pend_reset", 9, 0xFFFFFFFF);
    }
    else if ((IsAvailableCreature(8)) == FALSE) {
    AddAvailableNPCByTemplate(8, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 8, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(7)) == FALSE) {
    AddAvailableNPCByTemplate(7, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 7, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(6)) == FALSE) {
        AddAvailableNPCByTemplate(6, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 6, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(5)) == FALSE) {
        AddAvailableNPCByTemplate(5, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 5, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(4)) == FALSE) {
        AddAvailableNPCByTemplate(4, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 4, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(3)) == FALSE) {
        AddAvailableNPCByTemplate(3, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 3, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(2)) == FALSE) {
        AddAvailableNPCByTemplate(2, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 2, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(1)) == FALSE) {
        AddAvailableNPCByTemplate(1, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 1, 0xFFFFFFFF));
    }
    else if ((IsAvailableCreature(0)) == FALSE) {
        AddAvailableNPCByTemplate(0, nDroid);
        DelayCommand(0.1, ShowPartySelectionGUI("k_pend_reset", 0, 0xFFFFFFFF));
    }
}

This checks if the companion is available, it then adds the NPC to the party and shows the selection screen making sure that the correct slot is selected.

For now this is a very roughly written idea for a tutorial, but I have created the level and when it is finished I will upload it here as a tutorial for people to make use of.

I plan to continue to expand upon this idea and fill the level with scripts and examples provided here for people to pull apart and make use of.

Fow now there is a bug that means if you buy the same droid twice, they remain there because it tries to destroy the NPC in your Party, instead of the one being previewed, this is a side-effect of the fact I wanted to try and have all 55 available droids in the game as options, but it seems without using a global variable the best way to do this will be to individually select each droid for the list. ( there might still be a better way, I have yet to try again )

000dia.mod

Feel free to learn from this example, the idea itself I plan to use and release as either a stand-alone mod or as a part of the Expanded Galaxy Project.

17 - [TUTORIAL] - Upgradeable Items

Spoiler

Below is a list of the UpgradeLevel numbers that can be used in .uti files that I found posted by another user on DeadlyStream, I thought I would link through to it and repost it here.

In order to make an item upgradeable the below entry needs editing in the associated .uti file to be in line with the numbers below by item type.

Untitled.png.a4ce02069b3fae6e73ac3acd40c25020.png

Robes (Knight & Master)        1
Armored Robes (Zal Shey)    2
Light Armors            2
Medium Armors            3
Heavy Armors            4

Regular  (Non-Powered)        1
Vibro Weapons (Powered)        2
Lightsabers  (All Types)    3

Blasters (Scope Only)        1
Blasters (Scope,Chamber)    2
Blasters (All Upgrades)        3

 

Below is a link to the source from which I found this information.

Source : https://deadlystream.com/topic/1488-question-on-making-an-item-upgradeable-in-game/

I will continue to provide examples that I think might be useful to people, these are all for TSL so far.

 

I hope these tutorials and any others I write will help people continue to make mods for KotOR 1 & 2.

These tutorials are getting shorter and less detailed, I may or may not go back and re-write them at some point but if anyone struggles with anything feel free to message me and let me know what I haven't covered very well.

 

Feel free to join the Discord for my project if you need help with anything related to KotOR modding and I will do my best to assist.

Discord https://discord.gg/S3YyfTjMV8

Base Game Scripts & How To Use Them

Spoiler

I am considering working on an index for the base game scripts and how they all function so that people can more easily use them in dialog files without having to constantly look up how they work, what parameters need to be passed along to the script and other such details.

For now here is one such example that I discussed with another user recently.

a_hitman.nss/.ncs - is used to turn an NPC hostile, if they are already hostile it will turn them insane.

Spoiler

//:: FileName a_hostile
//:: Created By: Kevin Saunders
//:: Created On: 07/20/04
//::
//:: Object with Tag = ScriptStringParameter becomes hostile.
//  Modified: Tony Evans 9/9/04  (Added nInst parameter)
//  Modified: Tony Evans 9/15/04 (Added OBJECT_SELF default and nSane param)

void main()
{

    string sCritter = GetScriptStringParameter();
    int nInst = GetScriptParameter(1);
    int nSane = GetScriptParameter(2);

    object oTarg;

    if (sCritter == "") oTarg = OBJECT_SELF;
    else oTarg = GetObjectByTag(sCritter, nInst);

    if (!nSane) ChangeToStandardFaction(oTarg,STANDARD_FACTION_HOSTILE_1);
    else ChangeToStandardFaction(oTarg,STANDARD_FACTION_INSANE);
}

a_hitman.png.d0b8cea6d1f81a4e016a31d3106541c7.png

The above image shows how you would use this in a dialog file, example is from the Entertainment Promenade on Nar Shaddaa.

KotOR Modding - Crash Course

This 2 hour stream covers the basics of KotOR modding and some of the programs involved, I also regularly stream development of my mod project on Twitch/YouTube.

Not all of this covers KotOR modding, there is about 10-20 minutes during the first hour where I get distracted and the second hour of it is mostly me playing games.

Spoiler

By the basics, I mean the very basics. An overview of the programs and filetypes associated with KotOR as well as the structure of level files.

These are the testing rooms but for K1 the room is lacking a texture but I find this just makes it easier to look through the characters.

 

Edited by Thor110
Upgradeable Items
  • Like 3

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.
Note: Your post will require moderator approval before it will be visible.

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.