Modding in Exult the Ultima VII engine part 3: Usecode scripting basics

Previous articles:

In the last two articles, we have learned the basics about shapes, the item data unit in Exult Studio. With the editor alone we can achieve some simple tasks like item editing, face editing and so on, but what we can do until now is still limited to the art model and their basic parameters. Game development and modding could achieve more ambitious goals with scripting. We can add more custom functionalities in game, such as dialogue, new NPC, quests, new scripted event and items with special effects out of editor functionalities.

Ultima VII used a scripting language called Usecode, in Exult this scripting language is wrapped in a C-like variation called Usecode C Complier, for short we still call it Usecode in this article. There are some, but not very detailed documentation and examples for Usecode, and they are scattered around so getting the knowledge of Usecode basics is not extremely easy for someone unfamiliar with Exult scripting. Thus, this article is aimed to introduce the very basic aspects of Usecode. For more information, please refer to the intrinsic function list, UCC documentation, and example mods such as source code of BG Keyring mod.

1. How to create and compile a usecode script

A usecode script is a file with .uc format, but actually the compiler won’t complain if you try to compile with other formats, such as .txt files. We can create a .txt file (or change it to .uc if you like) and write script in any text editors like notepad or Visual Studio Code. When we finish and ready to compile, find ucc.exe in Exult tools, and in command line, run ucc.exe with the file we try to compile. We will get another file with format .ucc, then we delete the .ucc and put it in the \patch folder. By convention the main script file should be named as Usecode.

Without an IDE for Usecode scripting, it’s hard to spot bugs or debug in usecode script. However, some syntax errors would be caught when compiling, so you should pay attention to the errors if it didn’t compile normally.

2. Basics of usecode script

When scripting for a mod, we must understand that just like item editing, scripting is done on top of base game, what we do is adding and overwriting the base game. When reading mod script we need to keep in mind some of the functions and parameters are internal used in the base game. Without decompilation we won’t be knowing what the internal functions look like, but some mod that worked closely with Exult team reveal some of the internal parameters. When we see parameters that looks like magic numbers, sometimes they are how the base game defined. And for internal functions there’s a list for known such functions.

The first line we need to define is the game the script is worked with. If we are making a Black Gate mod, we need to claim this line at the very beginning of the script:

#game "blackgate"

Or if it’s for Serpent Isle, add

#game "serpentisle"

For larger code where you break the script into several files, the notation is similar to C:

#include "scriptName.uc"

Next part is defining variables. Usecode support type keywords such as int and var. We can also define groups of parameters as enum like in C.

Some examples are as below:

const int AVATAR = -356;
var target = UI_click_on_item();
enum events
{
	PROXIMITY		= 0,	
	DOUBLECLICK		= 1,	
	SCRIPTED		= 2,	
	EGG			= 3,	
	WEAPON			= 4
};

Exult Usecode supports many types of common logic blocks, such as if/else, while. The syntax is similar to C where curly braces and semicolons are needed in C style. The difference in Usecode scripting is each function need a hex index for the game and Exult editor to recognize, so every function has several parts:

(return type) (function name) (function hex index) ((parameters)){}

In the next section we will talk about the functions more in detail.

3. Some common functions in Exult modding

In this article we won’t be talking about detailed use of internal functions, but here we talk about two types of function that are very important in Exult modding: one is functions for objects/shapes, the other is converse block.

When writing a function for specific item or NPC, we need to add object(0x***) or shape(0x***) after the function name. Function names can be defined as you like, but the hex needs to correspond to the item you want the function to affect. If it’s an item, the format is shape(the hex of parameter in editor), and for NPC, it’s usually object(the hex of parameter in editor + 0x400). You can’t see NPC index without the game running, and for NPCs already in base game, they have internal parameters which are negative integers, and it’s recommended to use the internal index rather than the calculated values. You can find the full list in BG Keyring source code.

Another useful unique tool in usecode in converse block. It works like switch case blocks in common programming languages, but it’s specifically used for creating a U7 style branched conversation.

The structure of the blocks is like:

converse (["initialOption1", "initialOption2", "Bye"]) 
{ 
case "Bye": 
  say("something");
  break; // if the converse ends here
case "initialOption1" (remove): //if the option doesn't appear next, add (remove)
  say("something something"); 
  add("option3"); // new option appear
...
} 

By using case, say, add, remove keywords, we can control the structure of a conversation freely just like in U7. Note that a useful syntax in conversation is the double quote mark in conversation is noted as a pair of @…@ symbol.

4. Case study: talking Guardian puppet

This is actually simpler than you might think. Usecode has an event for double clicking an item, we can take advantage of it and enter a converse when we trigger the event double click. The internal parameter for double click event is 1, for convenience I didn’t use the full parameter list for event, and only state the event DOUBLECLICK as 1.

We will be double-clicking the shape of Guardian puppet glove, so this is a function of the puppet shape. From Exult Studio we can find the index of this shape and turn it into hex number (here it is 0x40c), and write a block that if we double click on the shape, we trigger a converse.

Here’s the final script that made the Guardian puppet alive:

#game "serpentisle"
const int DOUBLECLICK = 1;
const int GUARDIAN_PUPPET_FACE = 315;
void GuardianPuppet shape#(0x40c) ()
{
GUARDIAN_PUPPET_FACE->show_npc_face(0);
if (event == DOUBLECLICK)
{
item.say("You used the puppet and imitate Guardian voice. @Avatar!@");
converse (["Name", "Job", "Bye"])
{
case "Bye":
say("@I'm not going anywhere, Avatar!@");
break;
case "Name" (remove):
say("@Avatar! Thou shall know your Lord Guardian! Hahahaha!@");
add("Guardian");
add("Puppet");
case "Guardian" (remove):
say("@Do you really know where you're going, Avatar?@");
case "Puppet" (remove):
say("@Hahahaha!!!@");
case "Job":
say("@I am helping you, my friend.@");
}
item.hide();
}
}

5. Scripted animation

Scripted animation is another important tool for making your own original plot or spice up the environment. It’s also an important part of scripted events. It’s also straightforward but with some unique syntax that need to pay attention.

Usually the animation frames will be contained in the frames of a shape. Then the scripted animation is basically controlling the flow and timing of showing different frames.

The syntax for a script block looks like:

script itemThatDoTheThing  
{  
sfx 100; // play sound effect No.100
next frame; // show frame number +1
previous frame; // show frame number -1 
frame 4; // show frame No.4 
wait 1; // wait for 1 tick; The unit of the number is the game frame/tick of U7   
say("something"); // say that not in converse block will show on top of the target item  
repeat 3{ }; // repeat 3 times of the commands in brace 
... 
} 

For the full list of script commands please refer to http://exult.sourceforge.net/seventowers/code.php?TITLE_IMAGE=usecodetitle.png&DATAFILE=ucc_scripting.dat

With the combination of the different options in script block, it’s possible to control the animation of items as well as NPCs when we needed.

These are only the basics of Usecode scripting, but with this knowledge you are already being able to do a lot more in Exult modding. At this point I’m not sure if there will be more of the tutorials for now, but if people want to know more, there might be topics on barges, egg events or more detailed Usecode scripting. If you are interested in more about Exult modding, please tell me and I will see what else I can do to help the community!

Leave a comment

Blog at WordPress.com.

Up ↑

Design a site like this with WordPress.com
Get started