Usecode howtos
Forum rules
NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Usecode howtos
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.
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.
Re: Usecode howtos
The correct would be "ultima/mods/modname/patch"."ultima/mods/modname/data" folder.
With lots of workHow can I edit usecode in exult script format and recompile it?
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.
UCC-written usecode would be the best bet; rip/wud/wuc are better left to edit the originals directly. More below.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"?
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).Can I replace existing functions by creating my own function using an already existing function 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()".
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.What is the difference between wuc and ucc?
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.
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.What else is good to know?
------
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]
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]
Re: Usecode howtos
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
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
Re: Usecode howtos
"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
"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
Re: Usecode howtos
Ahem:
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:
* 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:
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).
(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:Quote:
"ultima/mods/modname/data" folder.
The correct would be "ultima/mods/modname/patch".
(emphasis added) the "usecode" file gets placed in the wrong directory.ucc -o ..data/usecode usecode.uc
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:
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.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?
Something I forgot to mention: there are only four classes of functions for which you *really* must specify a function number:upper Limit of U7 bg & si function numbers
* 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
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).a list of what each existing U7 function is for
The only "reserved" numbers would be those of the original functions; since mods must be manually merged anyway, you can use what you want.function numbers that have been used or are reserved for existing mods
------
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]
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]
Re: Usecode howtos
> 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.
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.
Re: Usecode howtos
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.
....
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.
-
- Site Admin
- Posts: 985
- Joined: Thu May 14, 2020 1:34 pm
Re: Usecode howtos
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.
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.
Re: Usecode howtos
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,
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:
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.
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();
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;
------
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]
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]
Re: Usecode howtos
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.
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.
Re: Usecode howtos
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.Is there any direct way to call functions with arguments from within a script{} then?
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]
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]
-
- Site Admin
- Posts: 1310
- Joined: Thu May 14, 2020 1:34 pm
Re: Usecode howtos
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
Artaxerxes
Re: Usecode howtos
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.Maybe Exult should be modified to understand exult-scripts directly.
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.
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).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
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]
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]