A Programmer’s Guide to Behaviour Editing
Contents
Contents .................................................................................2
Introduction.............................................................................3
What is this document about? .................................................3
Who is this document for? ......................................................3
Why not just make "BHAVs for Dummies"? ...............................3
Getting Started ........................................................................4
Tools....................................................................................4
Tutorials and Walk-throughs ...................................................4
SimAntics ................................................................................5
What is SimAntics? ................................................................5
The SimAntics paradigm.........................................................5
BHAVs = SimAntics? ..............................................................6
Calling a function in a BHAV....................................................6
Changing the contents of an existing BHAV...............................7
Importing Semi-globals.............................................................9
The nature of semi-globals .....................................................9
Adding semi-globals from your object’s semi-global library .........9
Adding semi-globals from a foreign semi-global library.............10
Getting your function called .....................................................10
Calling from an existing function............................................11
Pie Menu Functions ..............................................................11
Object Functions..................................................................12
Overriding default functions ..................................................12
Constant values and BCONS ....................................................13
Expressions and Primitive 0x0002 ............................................13
Where to now?.......................................................................13
Introduction
What is this document about?
This document aims to provide an intermediate level description of
the known background theory behind behaviour editing for The
Sims 2. It is not a guide to any one tool, nor is it an explanation of
how to make new objects. Instead, this document exists to allow
people to come to grips with some of the important fundamentals to
changing the behaviours in The Sims 2.
Who is this document for?
This document is not a "BHAVs for Dummies" guide. It is targeted
at those who have had a play around with the internals of Sim
Packages, tried a few of the tutorials, and want to try something a
little more complicated. It also assumes some degree of
programming understanding. You don’t need to be a computer
genius, but some knowledge about basic programming theory
(selection, function calling, etc) is extremely helpful. This is a
"Programmer’s Guide" after all!
That does not mean that if you can’t program you won’t get
anything out of this, but you will likely come across terminology and
ideas that are strange or unfamiliar to you. There are many
resources online that are excellent at explaining these concepts.
Additionally, there are tutorials available that walk you through the
process of modding The Sims step by step if you find that method
of learning more useful
Why not just make "BHAVs for Dummies"?
Why not indeed? Well the obvious reason for that is that dummies
are probably not the best people to be doing BHAV editing! BHAV
editing isn’t extremely hard, but it is certainly not something you
can pick up after ten minutes and a two-page tutorial.
More seriously speaking, there are a lot of concepts familiar to
programmers that occur in BHAV editing. If this understanding can
be assumed, it saves a lot of explanation on my end.
Getting Started
Tools
As stated earlier, this is not a guide to any specific tool. However,
one or two tools are of particular use while trying to understand
behaviour editing.
SimPE
A package editor for the Sims. At present, this is the
predominant tool used in the modding community. It will let
you get in and modify most parts of Sims packages, and is
reasonably accessible for users.
DatGen
DatGen promises to provide a great many tools to aid in
behaviour modding, particularly for objects, through their
"Lilith" plug-in. This tool does not currently have the same
number of experienced users, but has a lot of potential as a
user friendly package editing tool.
DisaSim2
While I have not used this program myself, it comes very
highly recommended as a tool for examining the contents of
BHAVs in objects.
Tutorials and Walk-throughs
The best way to get a feel for your tools before diving into the
theory is to have a go at a few of the available tutorials and walkthroughs
that already exist for your tool.
If you have not done so already, make yourself an expert on the
process of recolouring and remeshing objects using your chosen
editor (not just wizards!). It does not matter if this isn’t where your
interest truly lies, these are just areas where you have a lot of
support available while you learn. Even more importantly, it will
give you a feel for manipulating the internals of a Sim Package.
Finally, as an introductory tutorial to changing behaviours in SimPE,
I highly recommend Carrigon’s tutorials, listed on the SimPE web
site.
SimAntics
What is SimAntics?
SimAntics is the programming language used in The Sims 2 to
define the behaviour of the Sims. Coding in SimAntics is a bit like
coding in a language half way between assembly and a simple
procedural language, but the language has plenty of little
idiosyncrasies.
The SimAntics paradigm
The structure of a SimAntics function owes a great deal to flow
charts and decision trees. Each function is made up of one or more
discrete lines of code. Every line of code, when run, is evaluated to
return either true or false. If the outcome of the line is true, control
passes to a particular line of code. If the outcome of the line is
false, control passes to a different line of code.
Thinking in terms of selection constructs, it is as though each line is
translated into an "if" statement. That is;
if(line_1 == true)
goto line_3;
else
goto line_4;
These paths make more sense if they are displayed graphically,
using flow charts or directed graphs. For example, given the
following calls:
Line True Target False Target
1 3 2
2 4 Fail
3 Success Success
4 Success Fail
It is possible draw this as a flow chart:
When a function you have written is called by another function, the
success or failure values the function produces are returned as the
true or false values for your function as a whole.
BHAVs = SimAntics?
BHAV files are the files within a package that record the sequences
of SimAntics calls for a particular function. Every BHAV file has its
own start point, and returns a true or false value based on the
success or failure of its code.
Calling a function in a BHAV
Every line in a BHAV represents a function call. Each function call
must include:
The opcode of the function you are calling
The line to jump to if the function returns true
The line to jump to if the function returns false
As well as this, the function may take either eight or sixteen
parameters.
The opcode of a function is the unique identifier for that function.
For any given BHAV, its opcode is the same as its instance id. There
is an important convention in the numbering of opcodes:
Opcodes in the range 0000 – 00FF are primitives
Opcodes in the range 0100 – 0FFF are globals
Opcodes in the range 1000 – 1FFF are locals
Opcodes in the range 2000 – 2FFF are semi-globals
Primitive functions are exactly that: primitive. They are the building
blocks of all other functions and are hard coded into the Sims game
engine. Primitives are available to all functions in all packages.
Global functions are one step up from primitives. They are not hard
coded into the Sims engine, and it is possible to look at their BHAV
code. They use primitives to perform actions that are used across a
wide variety of different areas, and are thus also available to all
functions in all packages.
Local functions are the ones that are most easily accessible and,
initially, the ones you are most likely to be editing. They can call
primitives, globals, and certain semi-globals, but are only really
visible to the object they belong to and to function calls within that
object.
Semi-globals are a little more complicated. They are functions which
have been abstracted for a particular set of objects. They are
common between a particular family of objects, but are only
accessible by objects in that family. For example, the semi-globals
library for chairs includes functions for sitting down and standing
up. Only objects that have been defined within the game as "chairs"
can call these functions. Semi-globals can see both primitives and
globals (and under some very strict circumstances locals). Each
object is able to choose one set of semi-globals that it will access,
generally based on the sort of object it is. Thus a chair would
normally choose to see the "chair semi-globals". Only objects that
have selected a particular semi-global library can call the semiglobal
functions.
Probably the simplest of the function calls you could make would be
the following:
Opcode True Target False Target Parameters
Sleep (0x0000) Success Failure
Sleep is a very simple primitive that takes no parameters, does
nothing and always returns true.
Parameters vary on a per-function basis. They provide the function
with specific details about what you want the function to do. For
example, in the primitive 0x0001 (Generic Sims Call) the first and
only parameter is a number specifying which of the generic Sims
calls it was that you wanted to run.
Changing the contents of an existing BHAV
The specifics to changing the contents of an existing BHAV are
highly dependent on the program you are using to do it, but there
are several elements that are the same regardless.
If you wish to add a new function call, it will generally be added
after all the existing function calls. This is rather like adding a node
to your flowchart that isn’t connected to anything. The node will
never be run, because nothing is directing the function to run it.
Let’s say you have added a new function called ‘b’. You must look at
the existing contents of the BHAV to find the function you want
function ‘b’ to follow on from. Let’s call this function ‘a’.
You should first note down where ‘a’ was pointing, then make at
least one of its true or false targets point to the line containing
function call ‘b’. You must then make sure that ‘b’ does not simply
quit the BHAV (unless you want it to of course!) but rather
continues the execution of the BHAV.
Graphically represented, you must essentially do this:
When bypassing a node (disconnecting it so that it is no longer
used), the process is essentially done in reverse. You must find all
the places that call the node and redirect them so that execution
skips the node in question.
Deleting a node entirely is not really recommended, because it is
very hard to undo. Instead you should bypass nodes you no longer
want. Once you are completely sure that your change is working
with no ill effects then it is safe to delete the node.
Importing Semi-globals
The nature of semi-globals
As described earlier, semi-globals are libraries of common
behaviour for particular types of objects.
You can find which semi-global library your object is using by
looking at your package’s GLOB (aka "Global Data") file. This file
will tell you the name of the library your object is using, as well as
the library’s group ID.
All the functions in semi-global libraries have instance IDs between
0x2000 and 0x2FFF, and each semi-global library has a specific
Group ID. You can find the BHAVs for these libraries by looking
though the Objects.package file for BHAV files with the same Group
ID. Specific functions can be found by filtering these results on
instance ID.
Adding semi-globals from your object’s semiglobal
library
When cloned, many simple objects do not come with all the
behaviours associated with them in the package. That is because
most of the behaviours are located in semi-global functions.
If you want to change one of these behaviours in your clone but
leave the semi-global behaviours intact for all the other objects,
then it is necessary to make a new local copy of the BHAV from the
semi-global library.
Once you have found the semi-global in question, you need to
export it and import it into your own file. Once this is done, it is
vitally important that you change the BHAV’s Group ID to
#FFFFFFFF and the Instance ID to an unused number between
0x1000 and 0x1FFF. If you do not do this, then your imported BHAV
will override the one in the semi-global library.
It is at this point that your detective skills come in to play. You
must now track down all places in your object where the semiglobal
you imported could have been called from. If the pie menu
originally called the semi-global, then you must edit the pie menu
functions so they now call the new local BHAV. Any time the semiglobal
in question was called by a function, that function must be
updated. It is important to note that some Sims tools can perform
this task automatically for you on request (to varying degrees of
success), so investigate your program for this capability.
In some cases, this is all you have to do. Unfortunately, with many
functions (especially the lower level functions), there may actually
be unimported semi-globals that are still referencing the original
semi-global. If this is the case, then you need to import those
offending semi-globals, update the calls in their BHAV files, and
repeat the entire process for each of these. In some cases, the
number of imported BHAVs can grow exponentially.
Not all semi-globals require the same degree of backtracking. A
function that is called from a pie menu is generally only referred to
in a few places, but a function that is only ever called by another
function could be referred to in significantly more places.
Adding semi-globals from a foreign semiglobal
library
The process of importing semi-globals from a foreign semi-global
library (that is, a library that is not the one your object normally
accesses,) is similar to the process of importing from your own
library. However, there is an added complexity involved.
Say, for example, you have a painting (which can only see the
"Paintings" semi-globals) and you import a semi-global BHAV from
the "Stereo" semi-global library. Any function calls that exist in the
imported function are expecting to be called from a Stereo type
object, not a Painting type object. Thus, when the BHAV makes a
call to opcode 0x2009, it thinks it will be getting the Stereo semiglobal
(Stereo – Turn Off/On), but what it will actually get is the
Painting semi-global (Interaction – Critique – Test).
This means that when you are importing semi-globals from a
foreign library, you must also import all the semi-globals that are
called by the function and repeat the same process.
Getting your function called
As is the case with most functions in most languages, code will
never be run unless the function is called by something. If you have
created a new function or imported one from some other object, it
is important to make sure that the object is calling your function at
some point. There are four main ways your function can be called.
Calling from an existing function
The obvious way to get your function to run is to call it from an
existing BHAV function that is already being called. This is done in
the same way as function calls in general which was described
earlier. The function’s opcode is simply the instance ID of the BHAV
you added.
Pie Menu Functions
From the user’s point of view, this is the normal way of getting an
object to do something. Click an object, select an option from the
menu, then the object does something.
The link between the pie menu and an object’s BHAVs can be found
in the TTAB (aka "Pie Menu Functions") file in your object’s
package. There are a great many things that can be tweaked in this
area for different effects, but there are two sections which are vital
to getting your function called.
The first and most obvious is the Action field. This must be set to
the opcode (instance ID) of the BHAV function you want to call.
The second field that is important is the Guardian. This function also
takes an opcode to a BHAV, but serves a different purpose. The
guardian should be a function that evaluates whether a particular
menu item should be shown should the currently selected sim try to
use it. For example, the "Make Breakfast - Pancakes" menu item is
only available early in the morning, to sims with high enough
cooking skill. To check if this is the case, there is a BHAV which
returns true if the currently selected Sim is permitted to run that
menu option, and false if not. If the BHAV returns false, the menu
option will not be displayed.
It is important to note here that Guardian functions are run every
time the mouse even hovers over an object. You don’t even have to
click on the object for the Guardian code to be run! That is why it is
extremely important that a Guardian function does not change
anything in the game, rather it just looks at game settings to
determine if the option should be available.
If you do not want a guardian function for your behaviour, you can
set this field to opcode 0x0000 (Sleep) and it is assumed that your
function can always be run.
There are a few things that Guardians are not responsible for
checking when it comes to opening menus. The game engine itself
is responsible for checking some things, like the age group of the
Sim. The TTAB files have flags specifying what age groups the
function is available to, as well as if it is accessible to visitors and
whether it can be used autonomously. These tweaks are currently
beyond the scope of this document, but should be fairly simple to
change depending your particular editing program.
Adding new pie menu items is relatively simple, but it requires
additional changes in the related TTAs files (aka "Pie Menu
Strings"). Every line in your TTAB should generally have an
accompanying line in the TTAs giving it a name for the menu item.
Object Functions
Where Pie menu items allow users to make an object perform an
action on command, object functions allow the system to call
certain functions automatically. The most common of these is the
"init" function, which is run automatically when an object is created.
There are several engine events that you can assign functions to in
the game, all of which you can find in your object’s OBJf (aka
"Object Functions") file. You will generally have one OBJf to start off
with, and one additional OBJf for every tile your object takes up.
Each event listed in the OBJf file has a pair of corresponding
Guardian and Action calls. In most cases, only an action is needed
for object functions, as they are run automatically by the game. If
you want to remove either or both of these function calls, simply set
them to opcode 0x0000 and they will essentially be ignored.
Overriding default functions
It is possible to write your own functions which replace existing
functions. When you do this, then your function will be called in all
the same places that the default version was called. This style of
hacking is a little more risky than modifying new objects, and is
generally reserved for game-wide hacks.
In user made objects, all the BHAVs should have their Group IDs
set to 0xFFFFFFFF, and have Instance IDs between 0x1000 and
0x1FFF. These values mean that the changes you make will only
affect the object they are placed in.
However, in the case of hacking the game play or fixing game bugs,
you will want the change you make to override the game’s default
behaviour. To do this, simply leave the Group ID and Instance ID
with the same values as the function you are trying to override.
When the game is loaded, it will use your function rather than the
default one.
I will repeat now that this is risky. Changing default behaviours can
have wide ranging and unexpected side effects. If you choose to
distribute a package with elements that override default functions,
it is important that you mention the nature of your changes to your
downloaders.
Constant values and BCONS
It is possible in Sims packages to store constant values for use in
your BHAV functions. For example, if you are creating an object that
increases fun you may want to create a constant value that
represents the speed of the fun increase. If, after testing your
object, you determine that the fun increase is too slow, then you
can change the value of the constant in the package without
hunting down all the relevant lines in your BHAV and modifying
them individually.
Constant values are stored in files called BCONs. Each constant
value is stored in its own line, and can be accessed using a
combination of the BCON’s instance ID and the specific line number
of your value.
Many existing Maxis objects can be tweaked quite easily using the
BCONs, without the need to change the BHAV files at all.
Expressions and Primitive 0x0002
Probably the most important function you will ever come across is
"Expression", with opcode 0x0002. Expression allows you to
evaluate mathematical and Boolean expressions, as well as assign
values to properties in the system and set various system flags,
amongst other things.
Details on primitive 0x0002 and its use can be found in numerous
locations, in particular on the MTS2 Wiki. I strongly recommend you
become familiar with it, as it is a well understood and extremely
useful primitive.
Where to now?
Clearly this is not a complete guide to BHAV modding. There is a lot
of known information about BHAV programming that is not covered
here. There is also a fair amount of information about BHAV
modding that is not known yet.
An excellent resource for modders is the ModTheSims2 forums and
its various sub-forums. Get yourself involved in discussions, and
read everything informative that you can find!
Above all, try things out! Play around with BHAVs and other parts of
your packages just to see what happens. You never know what
great new discovery you might make. And if you discover anything
interesting, then be sure to share it with the rest of the community.
Good luck, we can’t wait to see what exciting new mods you come
up with!
Version 0
5 June 2005
Corrections to echo_eternity84@yahoo.com