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!

Doing Project Euler as a new programmer: what and how am I learning from these math problems

When I first heard about Project Euler it was almost 6 years ago. There was a time I was fascinated by Mathematica, while knowing nothing about programming, then I heard people says Project Euler is good for practicing. I have forgotten what happened back then, I don’t even remember I have ever made an account. And for some reasons I can’t remember, I gave up real fast like most of the others, along with Mathematica studying, and programming in general. 6 years later, I finally get to do some REAL programming because I’m trying to learn how to make games.

At first, programming was just a part of game development that I like equally in every discipline, then as I want to improve my skills, it suddenly clicked on me. Game development let me see what is love of doing one thing, and programming let me see what is passion. As I go deeper in programming and game development, I’m feeling it’s necessary for me to learn a new and very important language. I studied about the syntax and algorithm at the same time, and when I’m at the 1/3 of both books, Zoggins told me that I shouldn’t be only reading, but practicing is also important. After I did several toy projects, I was confused what to do next. Then I happened to rediscover Project Euler, and after asking Zoggins, he said it can help me be familiar with the C++ syntax so I gave it a try as toy projects. And I definitely didn’t expect I have gone so far.

Until I write this article, I have done 170+ problems and all of the first 100 problems, as well as getting my first ranking in newly published problems.

(According to the rules of Project Euler, any spoilers after problem 100 is not allowed, so I won’t state any concrete problems, but sharing what I learned from the problems in general.)

⁃ The basis of a programming language

The first few problems are just a warm up, even for someone like me who is unfamiliar with the language can get it done quickly. The solutions are usually straightforward too, people usually call it “brute force”. ⁃ the first experience of problem solving in programming But at 11-20, I first began to face some challenges. The first was knowing the data type limit and writing not so straightforward functions, such as bigInt calculations. I figured out myself by applying pen&paper calculation rules. The other is file reading and parsing. I bugged Zoggins to teach me filestream but he was busy so I eventually figured out myself. Now looking back it’s simple for me, but I spent days on the problem when I couldn’t understand.

STL containers

I didn’t do Project Euler in order because I have all kinds of questions and problems at times, but I can keep the speed of 3 problems a day on average up till now. There are more variant of problems between 20-50, but still almost all number theory. At times I can come up clever solutions or math solutions, and other times it’s quite clumsy brute force, and there were almost no fancy algorithms I learned from the book. I was confused and hesitant if I should continue. But think back about it, that period was also beneficial for a beginner like me, as I’m thinking a lot about the usage of STL containers, the difference between them and their characteristics. For example, I was really excited when I find out I can use set to collide repeating data, or write files into a set/map and get it naturally sorted. And of course, without even noticing, I became comfortable using iterators.

“Real algorithms”

I have a lot to say about this. There are a lot of buzzword saying Project Euler is all about mathematics and nothing programming. After going into 50+ problems, I disagree with this opinion. First, if we are talking about those algorithms in book, there are even problems so straightforward just as directly coming from textbook. There’s a problem that is so obviously minimum spanning tree, and while I didn’t have the knowledge, I saw it and immediately know what I should learn. There are many problems very obviously being dynamic programming, and there are problems of just finding shortest/longest path. When I see those problems I know what I should learn and go for that direction to solve the problem. There are problems using very specific algorithms, such as square root algorithms, and I was surprised seeing there are so many algorithms just for solving that one specific problem. Other algorithms are quite “mathy” and not so obvious to see it’s actually algorithm. People complain about project Euler being playing with prime numbers, and I learn later that I figured out prime algorithm as well as balancing between checking prime and generating prime all by myself. Other times there are problems which look like number theory but actually being a graph, etc.

What I’m most impressed with was I learned 3 important things doing Project Euler: recursion, dynamic programming and graph. Zoggins taught me about the shortest path algorithm, which inspired me about storing information of the states. He also taught me the recursion but it was a hard topic to understand, the first backtracking problem using recursion took me a whole day to try, revise, and solve, and I definitely learned it in a hard way. Learning about dynamic programming was a long story, I had many eureka moments exploring it, yet I still feel I haven’t seen the end of it. There were dynamic programming problems as early as in the first 50 problems (and I still think one of them is harder to figure out than some ~150 DP problems…), and when I first figure out a problem using DP, I was so happy because when I read the book, I felt it was a hard to understand algorithm. Then there was a time I need to deal with very large range, but I figured out a DP method with both time and space complexity small, and the speed just shocked me… it was like a magical moment, and I was so excited even want to tell everyone! The best thing about learning algorithm through Project Euler is, it’s possible to “reinvent” the algorithm by yourself. The problems themselves, as well as the connections of problems, might naturally guide you to the correct solution.

When I just went to 50-100 problems, I felt they were so difficult, but with some searching for the maths, some help with the needed knowledge, and mostly a lot of thinking and bouncing back and forth, I was able to do the seemingly impossible task, which is a wonderful experience!

⁃ Learning and feeling what computer can do

Don’t laugh, but even brute force can teach you things. Sometimes I’m very nervous that it seems hard to find an analytical solution to simplify the program, but when I have no choice but to brute force a problem, sometimes it’s not as slow as expected! The algorithm do tell us about the importance of reducing complexity when the bound is large, but you won’t get a feeling of how large is large by just reading the book.

By doing Project Euler, I saw that million scale and billions can have a huge difference while millions and below are usually acceptable even with n^2. The one-minute rule really gives a guidance that encourage us to optimize, but not always need to over-optimize. I stick to one minute rule strictly even the rule clearly allows the submission over 1 minute run time. As a beginner learning algorithm, seeing polynomial complexity makes me panic a lot, but I can see sometimes it’s actually not that bad, even for computers 20 years ago according to the discussion thread. Then I also heard of the concept of NP complete and know I don’t need to over-panic for every problem with high theoretical complexity. Computers are powerful, they’re here to deal with the enumeration job for people sometimes, so just use them if we can.

But the opposite side is, I also see how powerful algorithm can be. While I’m always get in touch with math and numbers, it’s not easy to get the feeling of scales. I know log scale for long, but not until I did a problem with very large bound using log(n) DP method, did I really learn how small, how fast the log(n) run time is. There’s again the one minute rules, it’s both relaxed and can be very strict, I sometimes need to suppress the run time from 2 minutes to 1 minutes, but end up changing the algorithm and did it in a few milliseconds. That was another surprising moment!

Another example is even jumping out of the thought that computer just help with theoretical model. When I forgot all about probability and have to do a simulation for the answer, I happened to use Monte Carlo method without knowing it, and I was like, I can actually do simulations to solve problems! That’s another moment that opens my mind.

⁃ Breaking down problems

While I sometimes ask Zoggins for some algorithm help or just want some rubber ducking, I never start with the original problem except I just want to show and scare/impress him, because… well, Zoggins is afraid of math 😛 But more importantly, often for project Euler problems, the core problem that needs to solve by algorithm or analysis is not what we look like. It can actually be very different sometimes. Sometimes the method we use for a problem could be surprising, such as, finding common factor algorithm in a prime problem?! It can really be surprising at times, where the algorithm is not even related to the field of the topic, but by breaking down we can see what the problem really is, and as a beginner with not enough knowledge, I would know the direction where I should look for information.

⁃ Being less frightened to explore new area of knowledge

Searching for math knowledge is encouraged in Project Euler. As a new programmer, I need to learn new algorithms often too. There are concepts that I felt too difficult to understand because they sound hard, but when I want to learn how to solve a problem, I got a lot of new knowledge in those fields. If it weren’t Project Euler, I was even frightened to learn dynamic programming which is textbook content, not to mention all the new math and algorithms to me.

⁃ Learning and growing naturally

The rule of Project Euler is strict, even too strict sometimes I feel. Of course there are people don’t follow rules, but I’m the kind of person even stick to the 1 minute rule and have high standard to myself, I won’t let myself just look at the answer. Sometimes I feel it would be better to allow giving some hints to new people like me, but when I go to other communities, where people claim I won’t come back to a previous problem despite I did 90+ problems already and suggested me to look at the answers if I can’t figure out in 15 minutes, I feel I still agree with Project Euler’s rule more. If it wasn’t all come by my thinking and active learning, I won’t be able to have so many impressive moments and feel the charm of math and algorithms like this. Sometimes it’s not easy to feel I’m improving, but when the difficulty bar becomes longer and longer, the people who solved are fewer and fewer, and I can still keep the solving rate and move forward, maybe I have really grown naturally. Plus I like how the problems inspire people to discover the knowledge either to search and learn, or to figure out myself, it’s unreplaceable by just showing you the answers.

⁃ Algorithm is math, in a good way

People criticize Project Euler being too incline to math, but I think it’s a good thing. Being all math problems (but still sometimes string manipulation, games, or even physics) let me see the relationship between math and algorithms, when I find I can see DP problems from combinatorics point of view, or solve combinatorics by DP, I was so thrilled finding that relationship and get to find a discrete math book immediately. Then of course I see even more relationships, graphs and trees are just math concepts, and I refine my recursion knowledge from the math book. When I open the algorithm book the first time, I didn’t know anything but feeling algorithm is a hard topic, then I found surprisingly it’s just like a math book. Project Euler gave me more feelings like this, it let me see algorithms come from math and go back to math to solve math problems.

I am really excited to do project Euler more and clearly obsessed about it. I’m feeling solving the first 100 problems is an important milestone, so I write this to summarize what I learned in the first 40 days doing Project Euler. I don’t know when the problems will be too difficult for me and I will be inevitably slowing down, but I’m still planning to learn and move forward as much as I can!

If you’re doing or consider to do Project Euler on projecteuler.net, here’s my friend code:

740067_jmjGx7Fr8yqkyY2X5k8fUggojgjqoQ4o

I am a game developer! If you are interested, you can play my games at yulotomorrow.itch.io 😀

Create a free website or blog at WordPress.com.

Up ↑

Design a site like this with WordPress.com
Get started