Usecode howtos

NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Forum rules
NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Locked
TdI

Usecode howtos

Post by TdI »

I want to edit some U7 usecode, for the fun of it. Unfortunately I found that the info on how to work with usecode and the tools is spread out all over the place, including some sites that no longer exist (esguides.com).

This is what I know, thus far:

----------------------------------------------------------------------------
- Usecode can be edited like this:
----------------------------------------------------------------------------

1. Extract all functions with cmd: "rip all"
2. Decompile .uco files with cmd: "wud compiled.uco -a > decompiled.uc
3. *do some editing*
4. Recompile .uc files with cmd: "wuc decompiled.uc compiled.uco"
5. Recreate usecode using cmd: "rip glue"

Problem with this approach:

1. wud decompiles to assembler-like code
2. rip needs all functions to recreate usecode

----------------------------------------------------------------------------
- ucxt can be used to decompile usecode into "exult script"
----------------------------------------------------------------------------

eg: ucxt -bg -ac -fs -ofile 00B2
creates a "file" containing decompiled function "00B2" in exult script format.

Problem with this approach:

1. ucc doesn't compile exult script correctly (get parse errors all the time)

----------------------------------------------------------------------------
- deploying custom usecode
----------------------------------------------------------------------------

Custom usecode can be put into a
"ultima/mods/modname/data" folder.
Config file for mods can be created with ExultStudio


....this is where my wisdom ends....
----------------------------------------------------------------------------

and this is what I wanted to do:
I decompiled a few functions (conversation functions, because I wanted something that I could change easily to see if it worked) using ucxt:
ucxt -bg -ac -fs -ofile 0415
ucxt -bg -ac -fs -ofile 044A

every call to ucxt created a file named "file", which I renamed to the function number + .uc

I changed the conversation text a little, and tried to recompile using ucc:
ucc 0415.uc Result: 0415.uc:43: parse error
ucc 044A.uc Result: 044A.uc:33: parse error

Then I read in some old form topics that ucc is not compatible with ucxt output.


Now, what I would like to know:

1. How can I edit usecode in exult script format and recompile it?
2. How do I create my custom "usecode" file only containining my own functions, without having to include all 1MB worth of usecode like when using "rip"?
3. Can I replace existing functions by creating my own function using
an already existing function number?
4. What is the difference between wuc and ucc?
5. What else is good to know?


Any help on any of these questions appreciated.
marzo
Site Admin
Posts: 1925
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by marzo »

"ultima/mods/modname/data" folder.
The correct would be "ultima/mods/modname/patch".
How can I edit usecode in exult script format and recompile it?
With lots of work :-)
More seriously: There was a (flawed, VB) utility I wrote which did most of the work. The "flawed" part means that it could (would) lose information in some functions. I had posted it in ES Guides; but I think I still have it laying around somewhere in one old hard drive.

I am also starting to write a much better utility (which I am calling "usecode decompiler") which will output UCC-compatible usecode and which will match the style used in Keyring/TFL/SI Fixes. But note the "starting" part; right now, all it does is dump NPC and shape names (and associated IDs and function IDs) and function, quality and location of usecode eggs. So it won't be an option for a while.
How do I create my custom "usecode" file only containining my own functions, without having to include all 1MB worth of usecode like when using "rip"?
UCC-written usecode would be the best bet; rip/wud/wuc are better left to edit the originals directly. More below.
Can I replace existing functions by creating my own function using an already existing function number?
Yes. In UCC, you just declare the function and specify the function number after the name (although for shapes, you must use the construct "shape#(shapenum)" instead of the number directly, where "shapenum" is the shape's number).

You can also call the original function (if you need it) by appending a ".original" to the function's name; e.g., calling Iolo's original function (defined somewhere to have the name "Iolo"), would be "Iolo.original()".
What is the difference between wuc and ucc?
The rip/wud/wuc/mklink combo are tools best suited to studying/modifying the original games. UCC writes Exult-only usecode -- although a good deal of this usecode would work in the originals, UCC-written usecode has several extensions which would crash the originals.

Exult has the capability of "merging" the usecode files in patch and static dir so that you only need to distribute the new usecode. As mentioned above, you can call the original versions of functions you changed with UCC. And although wuc has most of the capabilities of UCC (and some capabilities UCC doesn't have), it really isn't worth it to use wuc to make mods in Exult.

The problem is that most of this stuff is undocumented; the best source of information on UCC is still the Exult source, but the usecode of the Keyring mod, TFL, SI Fixes and the SF Island mod come very close. I am writing a tutorial, and some UCC documentation, but it will take some time. For now, there is a complete documentation on usecode intrinsics at my website (also in the Exult CVS), and some basic documentation/tutorial on UCC script blocks (also in my website) -- which is a small subset of UCC, used for animating characters and objects.
What else is good to know?
If you know C/C++, Java or PHP (and possibly others, but mostly C/C++), you will find many familiar things in UCC; the syntax is similar in many ways to them.
------
Marzo Sette Torres Junior
aka Geometrodynamic Dragon
[url=http://www.catb.org/~esr/faqs/smart-questions.html]How To Ask Questions The Smart Way[/url]
TdI

Re: Usecode howtos

Post by TdI »

So, what you are saying is, that at the moment, there is no way to decompile existing usecode into a working exult script format that could be recompiled using ucc, and that the best bet is to create usecode "from scratch", right?

So, to do this, I would have to place my *.uc files into a
ultima/mods/modname/data folder
and in ExultStudio, use the menu function "compile usecode". Would this work?

Some other things that would be useful to know:
- upper Limit of U7 bg & si function numbers
- a list of what each existing U7 function is for
- function numbers that have been used or are reserved for existing mods
TdI

Re: Usecode howtos

Post by TdI »

"Compile Usecode" in ExultStudio doesn't seem to work. I loaded my mod and put ucc into the PATH, but I keep getting the message
"Error executing usecode compiler (ucc)"

Then I tried to compile it by hand. My usecode.uc is in the
"mods/mymod/patch" directory and I called

ucc -o ..data/usecode usecode.uc

This creates "usecode" in the data directory. Unfortunately I don't see the changes reflected when running the "mod" with Exult.

My usecode.uc only contains some example code that I found in the Exult source, that supposedly makes Lord British want to join you after talking to him three times. It can be found in the src at:

exult\content\bg\patch.uc
marzo
Site Admin
Posts: 1925
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by marzo »

Ahem:
Quote:

"ultima/mods/modname/data" folder.


The correct would be "ultima/mods/modname/patch".
(emphasis increased) Unless you edited your mod's CFG file to make it use the data folder (like I did for my mods), Exult looks for usecode and other nthings in the patch dir. So when you do this:
ucc -o ..data/usecode usecode.uc
(emphasis added) the "usecode" file gets placed in the wrong directory.

Also: did you create your directory tree by hand or through Exult Studio (File->New Mod)?

As for things you asked in your previous post:
So, what you are saying is, that at the moment, there is no way to decompile existing usecode into a working exult script format that could be recompiled using ucc, and that the best bet is to create usecode "from scratch", right?
In essence, yes; there is no *automated* way of doing what you say. You *could* edit the UCXT output to put it into UCC-compatible form -- like Idid, for example, to discover what several original usecode functions did.
upper Limit of U7 bg & si function numbers
Something I forgot to mention: there are only four classes of functions for which you *really* must specify a function number:
* functions for shapes (which must be specified with "shape#(shapenum)" as I mentioned above);
* functions you are overriding;
* functions called by weapons when they hit;
* functions from the original game which you "extern" so you can call them.

For all others, you should not number them explicitly and instead add the following line to the top of your "master" usecode file:

Code: Select all

autonumber 0xA00
This will take care of everything. And for the record: I don't know exactly what is the highest function number on BG and SI, but is below 0xA00. In the Keyring mod/TFL, I use 0xC00 instead to leave room for weapon functions (i.e., planning for future growth).
a list of what each existing U7 function is for
There is none complete; partial lists exist in Exult CVS in the code for the Keyring mod (content/bgkeyring/src/headers/bg) and SI Fixes (content/sifixes/src/headers/si), and in the TFL CVS (src/headers/bg).
function numbers that have been used or are reserved for existing mods
The only "reserved" numbers would be those of the original functions; since mods must be manually merged anyway, you can use what you want.
------
Marzo Sette Torres Junior
aka Geometrodynamic Dragon
[url=http://www.catb.org/~esr/faqs/smart-questions.html]How To Ask Questions The Smart Way[/url]
TdI

Re: Usecode howtos

Post by TdI »

> The correct would be "ultima/mods/modname/patch".

Yes, sorry, that's what I meant. I just copy/pasted the wrong path from my previous post, but I got it set up correctly and I created the dir structure using ExultStudio.

>Unless you edited your mod's CFG file to make it use the data folder (like I did for my mods), Exult looks for usecode and other nthings in the patch dir

Okay, that was the problem. I looked into the KeyRing mod for guidance and copied the
ucc -o ..data/usecode usecode.uc
command from your makefile.sh, assuming that *.uc files should be in "patch", but "usecode" and all the other files should be in "data".

Now it works and I got Lord British to join. :)

Thanks for being so helpful.
TdI

Re: Usecode howtos

Post by TdI »

I have a problem with this script. Its an excerpt only. This part is contained in a method I call with "gotoObject":

....
script AVATAR
{
nohalt;
call freeze;
face directionFromAvatar(item);
repeat 6
{
actor frame USE; actor frame SWING_1;
actor frame SWING_3; sfx CHURN_SOUND;
actor frame STAND;
};
call unfreeze;
call doSomething;
// first try: doesnt work
//wait 40;
//call item->remove_item();
}
// doesnt work either
script item after 40 ticks call remove_item();


I'm trying to remove "item" after the "repeat 6" animation is finished and "doSomething" was called.
I tried delaying the call to "item->remove_item()" with "wait" or with "after", but it doesnt work and the item is always removed immediately, as if "item->remove_item()" was the first line in the method.
Malignant Manor
Site Admin
Posts: 985
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by Malignant Manor »

Use remove item as a separate function and call it

RemoveItem ()
{
remove_item();
}

or setup the script to do something like this


WhateverFunction ()
{
if (event == DOUBLECLICK)
{
script AVATAR
{
nohalt;
call freeze;
face directionFromAvatar(item);
repeat 6
{
actor frame USE; actor frame SWING_1;
actor frame SWING_3; sfx CHURN_SOUND;
actor frame STAND;
};
call unfreeze;
call doSomething;
// first try: doesnt work
//wait 40;
//call item->remove_item();
}
// doesnt work either
script item after 40 ticks call WhateverFunction, SCRIPTED; //can be any number as long as it is matched later
}
else if (event == SCRIPTED)
remove_item();
else return;
}

Any intrinsic after a script will be used at the same time the script is called.
marzo
Site Admin
Posts: 1925
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by marzo »

Malignant Manor is right about this: wrap the intrinsic in another function and call it instead. You can't call intrinsics directly from scripts.

You also can't have parameters and/or specify an 'item' for script-called functions, it automatically uses the script's actor.

Finally, you must use a *function*, not a function *call* with the 'call' command in a script. The code you wrote, e.g,

Code: Select all

script item after 40 ticks call remove_item();
Will do this:
1) generate code calling "remove_item()" and asking for a return value; since remove_item intrinsic does not return anything, Exult will return 0;
2) use the "return value" from the above call as a function # and try to call it. In this case, Exult will try to call usecode function 0, which does not exist.

Maybe I should have UCC issue warnings about this...

Thus, the code you wrote will immediatelly remove 'item', then try to use it in a script that calls function 0. I would not be surprised if Exult crashed with this...

In the specific case of deleting objects, you can use the 'remove' scrpit command instead of wrapping the intrinsic in a function:

Code: Select all

script item after 40 ticks remove;
For this, and all other script commands, you can check my website: more specifically, the (still incomplete) scripting tutorial. I still need to update it to include the fact that you can now nest repeats in UCC and they will work.
------
Marzo Sette Torres Junior
aka Geometrodynamic Dragon
[url=http://www.catb.org/~esr/faqs/smart-questions.html]How To Ask Questions The Smart Way[/url]
TdI

Re: Usecode howtos

Post by TdI »

Right... I got it working now. Is there any direct way to call functions with arguments from within a script{} then?


I created a script that is working quite nicely now. It involves a two-handed-axe and trees.... :) The script lets you chop off trees in return for "pieces of wood". The tree is removed, a stump is created in its place, and a piece of wood is put in an appropriate location next to the stump.

I know that trees are not independent objects, but are rather linked to chunks, which is why I created the stumps with the "TEMPORARY" flag, assuming that if you leave and return, the tree will be back, the stump gone, and everything back to normal.
Unfortunately "remove_item();" seems to delete items from the chunk permanently, at least until reloading a game. This means that felling a tree will remove that tree from all the places in Britannia where it is used and therefore, the tree will also not reappear once you leave and return.

This is bad :(
Any chance of making remove_item() not remove from the actual chunk?

And I think I found an Exult bug (by chopping trees). If you teleport away from a place with trees, and then teleport right back to that location, all the trees in that area are duplicated (meaning two trees are on the same spot), as if the chunk had been loaded twice or the trees that where previously loaded weren't cleared from memory.

In case anyone is interested, I uploaded the script to this location:
http://files-upload.com/354720/axes.uc.html

It needs to be compiled as part of the KeyRing-Mod, since it uses some constants and other functions defined there.
marzo
Site Admin
Posts: 1925
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by marzo »

Is there any direct way to call functions with arguments from within a script{} then?
Nope. The closest would be to use an event ID for the call, but you can't pass arguments to functions called from script blocks.

I will look into the chunk problems you describe.
------
Marzo Sette Torres Junior
aka Geometrodynamic Dragon
[url=http://www.catb.org/~esr/faqs/smart-questions.html]How To Ask Questions The Smart Way[/url]
artaxerxes
Site Admin
Posts: 1310
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by artaxerxes »

Maybe Exult should be modified to understand exult-scripts directly. This way, we could distribute source code as it's not only easier to play with than compiled source but also way more easily trackable with CVS/subversion (IIRC CVS doesn't do well with binary files).

Artaxerxes
marzo
Site Admin
Posts: 1925
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode howtos

Post by marzo »

Maybe Exult should be modified to understand exult-scripts directly.
I was going to do a long, detailed explanation on why this should not be done; but it all boils down to just this: byte-code machines are already slow enough, no reason to make it so much more slower.

Basically, what you suggest would be best if Exult were to compile the usecode, much as UCC does, when you start a game; doing it any other way would cause significant performance hits. And even doing that would make compilation of Exult and Exult Studio require Bison and Flex (instead of only UCC requiring it), and I don't know how much of a problem that would be.
This way, we could distribute source code as it's not only easier to play with than compiled source but also way more easily trackable with CVS/subversion
There is nothing that prevents you from distributing source and the compiled usecode. In fact, there are, AFAIK, no mods which haven't released the full usecode source -- and only TFL puts the compiled usecode binaries in CVS, together with the source (which, maybe, is something I should talk about with Wizardry Dragon).

In any case, what makes people want to use ucxt and wud is not usecode from mods but usecode from the original game -- this is the one which people usually want to dump.
------
Marzo Sette Torres Junior
aka Geometrodynamic Dragon
[url=http://www.catb.org/~esr/faqs/smart-questions.html]How To Ask Questions The Smart Way[/url]
Locked