This tutorial will describe the steps you need to go through in order to add a brand new interaction to an object you have made. It does not assume any previous knowledge of BHAVs, but it does assume familiarity with the SimPE program. Ideally, you should be at a level where you would feel comfortable creating a new mesh object or something of similar complexity using the SimPE software. This is not a tutorial on creating new mesh objects, recolours, skins, etc. You should also note that, while these instructions are quite generic, they will not work for all objects. Think of this as a first step in BHAV editing, far from the be-all and end-all.
Finally, if you are having trouble understanding a section, take some time to get familiar with it. Each new part builds on knowledge from the previous parts, so if you're having trouble now it'll probably only get worse. If something really doesn't make sense, you're welcome to email me or post a question on MTS2 (there is a thread there for this tutorial if you have a specific question).
Best of luck! Can't wait to see what you end up building.
While some people will argue that this is one of the last things you should learn to do, I find it helps enormously to be able to add new menu options from the start. If you are not familiar with the terminology, the "pie menu" is the menu that pops up in game when you click on an object, listing all the interactions that object offers (Fig 1.1).
Before we get too ahead of ourselves, we're going to need an object to add all our new code to. Make a clone of the "Red vs. Blue" Oil Portrait . (If you feel confident you may choose a different base object, but some steps may differ). Assign it a new GUID as you normally would to create a new object.
The information for the pie menu is stored across two files in a package - the "Pie Menu Strings", and the "Pie Menu Functions". You'll notice that in this painting, there are no such files present in the package. (If you cloned another object that does have these files, you may skip this step and go ahead). What you must do is import these files from a semi-global library, then ensure that they are correctly linked to your file.
First, find out what semi-global library your package is using. Open the GLOB file in your package, and take note of the name listed. In the case of the painting, it lists "PaintingGlobals" (Fig1.2)
Now that you know where to import from, open up the "Import Semi Globals" control from the menus "Tools" > "Object Tools", "Import Semi Globals". This should open a small window with a drop down menu and a large list box. From the drop down menu, select "PaintingGlobals" and select "Scan". The list box should fill up with many items. Select the "Uncheck all" option for now, as we are not concerned with most of these files at this time. What we are looking for are the pie menu files. If you scroll down the list, you should find them. Check their boxes, then select "import" (Fig 1.3). If you get a dialog asking if you want to save, then select "yes".
When you look down your object's list of files now, you should see that you have two new files to use for your pie menu. Before you use them though, you have to make sure that they don't override anything else in the game. To do this, click on each of the new files, and select the "Resource" tab. You need to change the "Group" number to 0xFFFFFFFF for both of the imported files (Fig 1.4). This change makes the files affect only the package they are in, and not all objects in game.
Now, your pie menu is ready to be expanded. (If your object already had the pie menu files, this is where you should start reading from.)
Open the "Pie Menu Strings" file in the plugin view. You'll see that a few of the lines have already been filled in, including one for "View". Don't change any of these at the moment, just click "Add String". A new space will be added to the end of the list. Click on this space, then in the box near the top of the window marked "String", give your interaction a name. I've called mine "My New Interaction" (Fig 1.5). Commit the file and save.
It's important to remember that you've only set the string in one language. To set it to a different value for each of the other languages, you can use the drop-down list of languages and edit the value in each one. If you want the same language to be used for all different versions of the game, you can just press the button "Default Lang Only". This wipes all but the default English text, so everyone will see the same values.
Now, open up the "Pie Menu Functions" file. On the left hand side of the plugins window, you'll see a list of all the interactions the object currently has - in the case of the painting, just the "View" option. Click on the "view" option, and press the "Add" button. An exact copy of the "View" option will be added onto the end of the list. Make sure this copy is selected.
Across to the right you should see a drop down list labeled "Pie String ID". Click on this, and you should get a list of all the lines in the "Pie Menu Strings" file. Find the one you just added, and select it. The name of the interaction on the left should change to match it. Now, look at the list of "flags". These are very simple pre-checks for whether an option is available to a sim. Leave "Adults", "Elders", "Teens" and "Visitor" checked for now, but uncheck the rest. This means that the interaction will only be available to these groups of people. You'll notice that the autonomy field has a value of 0x32. This means that it allows sims to autonomously perform this action. A value of 0x64 stops them from doing this. Just leave it for now.
Finally, set the value in the "Guardian BHAV" to 0x0. The purpose for this box will be described a little later, but for now, just set it to 0.
Finally, look at the fields for "Action BHAV" and "Guardian BHAV". Don't change these for now, but look at the values that are stored in them. They are pointing to the code for the "View" behaviours. That is because we copied it from the "View" menu option originally. So when this pie menu option is selected in game, the code that will run will be the "View" code. Commit all your changes, save your object, and try it out in game. You should have a nice new pie menu option showing up on your object!
While your pie menu shows up in game now, it just runs the same code as the original option. This is pretty pointless, so now it's time to create a new behaviour to run when your option is clicked.
Select the "Behaviour Function" (BHAV) files from the menu on the left. You should find two functions already in your object: "Function - Init" and "Function - Main". Don't worry too much about the contents of these, they are being used elsewhere in your object. We want to add a brand new function to this object though.
Right click on "Function - Init" and select "Clone". A new BHAV file should appear at the end of the list. We're going to use this new file to store our new interaction. Select the new file, and look in the plugin window. It should look a little like figure 2.1.
The first thing to do is to change the "Filename" section to suit what your new function will do. Change the text in that field to say "Interaction - Come do stuff". Commit and save. Now, click on the first (and only) command in the BHAV. At the moment, it probably says something like "0: [semi 0x2000] Function - Init". When you click on a command, the values it represents will be displayed on the right hand side, in the box labeled "Instruction Settings". These are the values you have to change to get the commands to do something different.
Next to the box labeled "OpCode", there is a button with a small arrow on it. Click on this arrow, and wait a few seconds while the window loads. You should get a window called the "Resource Chooser", which has several tabs across the top. Open the tab called "Primitives". The list you get contains all the commands that are built into the SimAntics engine at the lowest level. You want to select "Go To Relative Position" from this list, then click the "Okay" button. The value in the OpCode box should now be 0x001B, and the text of the command and the description should say "Go To Relative Position".
The "Go To Relative Position" primitive tells the sim to walk to a position relative to the object, but it needs a bit more information before it can do its job properly. A little further down from the OpCode box, you should see a set of boxes called "Operands". The values you enter here give the game specific details about what it should be doing. Fill all the boxes with zeros, and read the description text underneath. It should say "Go To Relative Position (Location: In front of, Direction: Same direction; no failure trees: False, allow different altitudes: False)" or something similar. (Fig 2.2) Try changing different values, and seeing what happens to this descriptive text. The third and fourth boxes in the top row are particularly interesting! When you've played for a bit, set them all back to zero, then change the fourth box in the top row to 04. These values should have your sim move to the front of the painting, then stand facing it.
In the drop down list for "True Target", make sure that "Return True" is selected. Under "False Target", select "Return False". When a command does this, it means that it's done and the game can go on with what it's doing. I'll explain this a bit better later on.
When you have a set of values that you are happy with, commit the file and save the package. Now it's time to get the pie menu function to call your new interaction.
In the game, BHAV functions are normally refered to by number. The number for any particular BHAV is its instance number, which you can see on the right in the file list window. But here we have a problem. The instance number for the new BHAV you created is still the same one as "Function - Init". If two functions have the number "0x1000", and the game tries to run the BHAV with the number "0x1000", it's anyone's guess as to which one will actually get run! What you need to do is to change the instance number on your new BHAV function.
Make sure your interaction is still selected, then open the "Resource" tab in the main window. One of the boxes in this window is labeled "Instance". Pick a number between 0x1000 and 0x1FFF, make sure it isn't already used by a BHAV file, then put it in the instance box (Fig 2.3). Commit and save.
You're almost there now, all you have to do is connect your pie menu option with your BHAV. Go back to the Pie Menu Functions file, open the plugin view, and highlight the line with your text on it. There are two boxes in the "Settings" section that refer to BHAVs: "Action BHAV" and "Guardian BHAV". The Action BHAV is what gets run when the interaction happens. The Guardian BHAV is used to check whether the option should be available at a particular time. You don't need a Guardian BHAV yet, so set this field to 0x0. In the Action BHAV box, type the instance number from the BHAV you just wrote (Fig 2.4). Commit your changes and save.
Now, try your object out in game. When you select the pie menu option, the current sim should walk over to your object! Congratulations, you've just made your first interaction!
If you've made it this far, well done! The first few steps are always the hardest. Now you actually get to make your object do something a bit more worthwile: max out a motive!
Open the interaction's BHAV file. At the moment, you have one command which directs the sim to approach the painting. What we need to do is add a second command which should happen when the sim has arrived at the painting. Look for the check box that says "Special Buttons" and select it. A set of extra buttons should appear at the bottom of the screen. Now, select the first command in the list, then click the "Insert Via True" button. An identical command should appear underneath the first. You'll notice that the commands are linked with a small green arrow on their right hand sides. This arrow says "When the first command finishes correctly, run the second command". The red arrows pointing to "E" are saying "If the first command doesn't finish correctly, create an error log entry". This is exactly what you want.
Select the second command in the list, and use the OpCode arrow button to display the primitives list again. From the list, select "Expression" and select "Okay".
Expression is an extremely useful OpCode. It lets you read, write, change and test all sorts of values in game. Right now, we're going to use it to max out one of the sim's motives.
Look at the Operands section (the part with several small text boxes). On the right of this area you'll see two buttons. One has a single arrow, and the other has a double arrow. Click on the single arrow, and a window should appear called the "Instruction Wizard". Most commands don't have an instruction wizard yet, but Expression fortunately does. These wizards let you use drop down lists and check boxes to fill in the operands rather than manually changing the values.
In the first drop down list, select "My motive". This option describes one of the sets of values that all sim's have, but there are several other sets of data. In the second drop down list, select "Hygene". In the third drop down list, select the option ":=". In computer programming terms, this means "store the following value". In the next box select "Literal" then type the value 0x64 in the final box. It should now look like figure 3.1.
If you check the "Decimal" box, you should notice that the value 0x64 changes to 100. 0x64 is the hex value of 100, and all sim motives span from -100 (complete failure) to 100 (max). A motive value of 0 is dead center. Click the "Okay" button and the operands should be filled in automatically (Fig 3_2).
Commit, save, and try the object in game. Your sim should now walk over to the painting, and their hygene need should go full green.
See if you can change your code to max out a different need. Why not try maxing multiple different needs by adding more commands on the end to the list? Play around a bit and see what you can come up with.
This next section is one of the most time consuming, but also one of the most fun sections of creating new interactions. This is how you get the sim to do something! An animation is a set of instructions on how a sim needs to move its body. If you select an animation for waving, then the sim will appear to wave.
The first thing you need to do is to go to the end of your interaction, then add and link in a new command. The opcode for this command is 0x6A, "Animate Sim". You can just type the number in the opcode box, or you can select it from the list of primitives like you did previously.
Now, as a starting point, enter these operands into the operand box:
00 00 00 20 00 00 81 00
00 0A 00 00 00 FF 00 00
The description of this command will probably look very long and complicated, something like this:
[prim 0x006A] Animate Sim (Animation: [No AdultAnims: Private STR# 0x0081 file]:0x0000, No event tree, Flipped: False, Anim Speed in Temp 2: False, Interruptible: False, Start at tag in Temp 0: False, Trans to Idle: False, No Blend out: False, No Blend in: False, Flip Flag in Temp 3: False, Synch to last anim: False, Use controlling object as anim source: False, Not hurryable: False, IK Object: Stack Object ID, Priority: 0x00 (low))
Most of this isn't important to us at the moment, we're only really worried about that very first bit: "Animation: [No AdultAnims: Private STR# 0x0081 file]:0x0000"
This part of the descriptor is supposed to tell us which animation is going to be played, but instead it's telling us that it can't find Private STR# 0x0081, which it uses to look up which animation it is going to play. Let's go check it out.
Select "Text Lists (STR#)" from the file types list, and take a look at the instance numbers. Can you see one with the instance number 0x81? No? That's probably why the animation command couldn't find it! But we know that paintings do have interactions that animate the sims, so they have to be able to pull animations from somewhere. That means that there is probably going to be a Text List 0x81 in the semi-global library.
Open up the semi-globals library again like you did when you were importing the pie menus. Uncheck all, then scan down the list until you find "STR#: Anims - Adult". You'll notice that the last number in the brackets after this is 00000081. That's its instance number, and consequently the text list we were looking for. Check that file, and import it. Now if you go back to the text lists, you should have "Anims - Adult" listed there.
Because you imported it from a semi-global library, it will probably still have the wrong group number. Go back to the text lists, click on text list 0x81, and use the resource tab to change its group number to 0xFFFFFFFF. Commit your changes and save.
Now, go back and take a look at the Animate Sim BHAV. It's found the STR# now, so it's stopped complaining about that. However, it now says "Animation: AdultAnims: Private STR# 0x0081:0x0000 "" ". It says it's looking for the name of the animation in Private STR# 0x0081:0x0000. Now, we have imported private STR# 0x0081, but we haven't looked at that second half where it says the line number. In this case, it's looking at line number 0x0.
Look back at the text list. Line 0x0 of the "Anims - Adult" file is empty! We need to find an animation to put in it.
At this point, you need to save your object so we can go animation hunting. So save, then close your object.
Now, open up "C:\Program Files\EA GAMES\The Sims 2\TSData\Res\Sims3D\Sims00.package". This is the file that contains all the standard animations in the sims games. (Animations from each of the expansion packs can be found in the same general location in their respective directories). Open the "Name Map" file.
You should get a huge long list of all the animations in game. Look through the list. While you're reading them, think about their names. If they start with an "a", they're probably for an adult which makes them ideal for your purpose. If they start with a "c", they're for children, "t" for teens, "e" for elders, "p" for toddlers, and "o" for objects. If they have a "2" in them, then read it as "to". For example "a2c" is an animation that an adult plays to a child, like a social. "a2o" is something an adult is doing to an object, and so on.
We're going to use the hula dance that the hula zombies play. Scan through the list until you find the reference to "a-dance-hula_anim". Copy all the text before the "_anim", so we can put it in the text list of our object. Now, close this file, but don't save anything.
Reopen your object, and paste the text we just copied into line 0 of text list 0x81.
Commit, then go check out the command in the BHAV. It should now say the name of the animation in its description! Save your object, and try it out. The sim should now do a little hula dance next to your painting!
Now, why not try adding another animation to play straight after the first? You'll need to add another command in, but this time you're going to have to point it to a different line in text list 0x81. The very first operand in the "Animate Sim" command is the one that says which line in the text list to look at. Remember to add a different animation to the text list, a new command in the BHAV, and to make sure the command is pointing to the right line in the text list.
Before I leave you to play with animations, I'll mention one thing. Some animations will not work when you try them. If you turn testing cheats on, you'll see that some animations will cause an error that mentions "IK Objects". Animations that require a sim to do something perfectly synchronized with an object or another sim, (for example, when opening a door on a microwave - the door has to move in time to the sim opening it,) have special characteristics which allow them to do this . These animations generally won't work in interactions with different objects. If this happens with one of the animations you try, just find a different one to use instead.
So far so good, but an object that does exactly the same thing each time gets a little boring. Plus, it's important to know how to write a function that isn't just a single sequence of steps. Different things should happen under different conditions. In other words, your behaviour needs multiple possible paths to follow.
When we first started adding commands, we briefly discussed the green and red lines that connected the commands together. At the time, I explained that the green lines were followed when the command finished correctly, and the red lines were followed when the commands didn't finish correctly. While this was true of the commands we've used so far, this was something of an oversimplification. Whenever a command is run, it reports back one of two values: true (green), or false (red). In a lot of functions, true means that everything went according to plan, and false means something went wrong. In other commands though, they can have different meanings.
One of the simplest examples of this is "Coin Flip". This is a global, which means that you should look under the "Globals" tab rather than the "Primitives" tab when you select it in the Resource chooser. It doesn't use any operands, so go ahead and add/link it to the end of your list of commands.
Coin flip will return true 50% of the time, and return false 50% of the time. That means that half of the times your sim runs the interaction they will follow the green arrow and the other half of the time they will follow the red arrow.
While you've got coin flip selected, click "Insert via false". Use this new command to run a different dancing animation. Now, go back up to the coin flip command and click "Insert via true". Find another dancing animation, and use this command to run it. Set the True Target of both of the two new commands to "Return True", and the False Targets of each to "Return False".
Now when you run your interaction, half the time one option will run, and half the time the other option will be run. Try it out!
Once a path has been chosen, the game will follow the lines from the place you ended up. If you insert more commands after a decision point, then they will only be run when that path is taken. Don't worry though, you can join them back together again.
Add a command to the end of one of the paths, using the "true" (green) path, and give it a job to do. Take a note of the line number at the start of the command. Now, go up to the last command in the other path. Instead of selecting "Return True" or "Return False" from the True Target box, try typing a number. The green line jumps to the command with the number you just entered. Type in the number you took a note of earlier. The green line should now point to the last command.
Now if you run your object in game it will always do the same thing at the start, then randomly choose a path for the middle section, before coming back to do the same thing at the end! Well done! Your object now has multiple paths of execution!
Coin Flip isn't the only command that helps you start different paths. "Expression",
the command we used earlier to change motive scores, can also help you to make
decisions. Find the command in your object that ran "Coin Flip", and
change it to "Expression". Now use the instruction wizard to edit
it so that it says:
[prim 0x0002] Expression (My person data 0x0011 (Body Skill) > Literal 0x0064)
0x64 is the hex value of 100 (a sim gets a skill point for every 100 in this field; 100 -> 1 skill point, 200 -> 2 skill points etc). This command is now making the statement "The sim using this interaction has gained at least one body skill point". If this statement is true, then the green line will be followed. If this statement is false, then the red line will be followed. In other words, if the sim using the object has *at least* one skill point they will follow one path, otherwise they will follow the other.
Congratulations! You've got an object which successfully changes its behaviour based on decisions in the code! Why not try making sims do different things based on how high their motives are? Or see if you can figure out how to change what they do based on their gender? (hint: if you replace > with ==, it means "is equal to")
So far, the object we've created does something then stops. But a lot of interactions just keep going until you cancel the interaction or the sim reaches a desperation point. This is done using loops, but there are a few tricks to make sure that your loop doesn't cause any error messages.
At its simplest level, a loop just means that once a sequence of events is complete, they repeat over and over again until something happens to make them stop. To see how this works, let's make our sim just keep on dancing until we tell him or her to stop.
Find the last command in the list, the one that is returning true. Now, change its true target to point to the first animation you added, the hula dance. If you follow the lines now, you'll see that the sim is just going to keep animating the whole time! This is a very simple loop.
There are a few problems with this loop though. The first is a problem with the sims game engine, and the second is a problem with the user's ability to continue using their sim. Let's deal with each of these in turn.
The first problem is with the sim's game engine. Whenever a BHAV is run by the sims game, it takes control of a lot of resources in the game. That means that if you had a loop that went forever doing a lot of calculations and processing, you could cause the game to lock up! This is especially likely in BHAVs that don't have animations or other slow commands to slow them down. Locking up is really unlikely with a loop like this, but under other conditions it's quite possible. To prevent this from happening, Maxis made a special rule that if any BHAV looks like it's stuck in a loop, it will force the BHAV to error and quit.
If we don't want this to happen, we have to give the game an opportunity to pause our interaction for a moment, so that the game can let other BHAVs use those resources for a moment. The theory for this is quite complicated (if you're curious, try googling "threaded programming",) but the changes you have to make are fairly simple.
At some point inside the loop, the BHAV has to make a call to a control relinquishing function. The one we're going to use is called "Idle". Go to the last command, and insert a new command via true. Set the opcode to 0x0118, which is the global function "Idle". Set the first operand to 0x01, and all the rext to 0. Commit and save.
That's the first problem taken care of, but what about the second problem? Once a sim starts using the object, they never stop - not even to die! We need a command to check whether the sim needs to stop what its doing, either because someone has canceled the interaction or because the sim has reached motive desperation.
Add another command to the loop, just after the idle. Set this command to opcode 0x0119, which is the global "Wait For Notify". Just set all the operands for this one to 0. This command is a bit like the commands we used when we were making decisions. This one is making the statement "I need to stop looping". If this is true, then the BHAV will follow the green line. If this is false, then the red line will be followed.
That means that we should only keep looping if the "Wait For Notify" is false. Select the Wait command, then set its False Target to the first command in the loop. Now, set its True Target to "Return True". If the statement "I need to stop looping" is true, then this will make the sim stop interacting.
Try the object out in game. The sim should just keep on looping until you either tell them to stop, or one of their needs drops to desperation level!
If you click on a bed while your sim isn't tired, you'll probably notice that there is no option to "Sleep". When a female sim tries to click on a urinal, there are no options available. The reason for this is guard functions.
Every time your roll your mouse over an object, the game builds up a hidden copy of the pie menu, so that if you click on it the menu appears straight away. For each entry in the pie menu, the game will have to determine if the entry should be available to the current sim. Some of this information is set in the Pie Menu Functions file itself - for example, what life stages it can be used by, and whether visitors are allowed to use it or not. For more complex things though, the game looks to a specific BHAV to determine whether an option is allowed. This BHAV is called the "Guard", because it guards access to the BHAV.
Create a new BHAV by cloning an existing one. Remember to give it a new instance number that hasn't been used yet! Give it the name "Interaction - Come do stuff TEST".
Now, delete all but the first command in this guard BHAV, then use the Expression command (opcode 0x2) to create the command "My motive 0x0007 (Hunger) >= Literal 0x0032". 0x32 is the Hex value of 50, so this command is making the statement "the current sim's hunger is greater than 50". Remember that motives range from -100 to +100.
This step is very similar to the process of making decisions that was described at the end of part 5. If this statement is true, we want the sim to be able to use the function. If it is false, we don't want the sim to be able to use the function. While you have the command selected, go to the "True Target" box, and open the drop down menu. You'll see an option saying "Return True". Select that. You'll see that the green arrow coming out of the box now points to a green "T". If the command is evaluated to true, then this command will send the message "True" back to the part of the game that called it. In this case, it will tell the game that the menu can appear.
Now, select "Return False" from the "False Target" drop down menu. If the statement turns out to be false, then this will tell the game that the behaviour option should not be available. Commit your BHAV and save your file.
All we need to do now is tell your pie menu which BHAV you want to use as the Guard function. Open up your pie menu functions file, and select the menu item that you added to the option. Underneath the area where you had to put in the instance number of your first BHAV is another, similar box. This one is labelled "Guardian BHAV". Enter into here the instance number you assigned to your new guard function. Save, commit, and try in game.
When your sim tries to use the object, then the pie menu will check to see if your sim's hunger is higher than 50 (that's in the top quarter of the bar). If it is, then the pie menu will appear. If it isn't, then the menu item won't show up!
Guard functions don't have to be just one line, they can be as long (or even longer) than the action BHAV if you like. Just remember that as soon as you return either true or false (the outgoing arrows point to either a "T" or an "F") the game will assume that you are finished and will respond to it. Think about how (or try, if you want,) to make a guard that will only allow men with a low bladder score to use an object. How about an option that is only allowed for sims who are very tired?
If you've made it this far, understand what you've done, and feel you can apply it again in different ways, then you are officially a BHAV modder! You have the knowledge to make well built, interesting, variable custom interactions. Congratulations!
Before you worry about anything else, go play with what you've learned. Make an object do something cool. Show it off. Consolidation of knowledge is good for the brain, and showing off is good for the ego. ;)
After you've done that, it's probably a good time for you to look into some of the other documentation out there on BHAVs. If I'm allowed a little self promotion, the "Programmer's Guide to BHAVs", while a little old now, does explain some of the theory behind the stuff you've done so far. There are also several discussions on how to do specific things floating around in various tutorial forums which will help a lot.
You should also start doing some digging into Maxis code. The best way to learn new tricks is to copy from the people who make this stuff for a living. Maxis code works (most of the time) so it's a really good place to get new insights.
If you have more questions about doing new things, the best place to ask your question is on a general modders forum like ModTheSims2. There are a great many people on there who know more and different things, and if asked nicely they're normally very happy to share that information!
Remember, what is written here is not necessarily the best way to achieve a goal, just a simple and straightforward way. There's a whole lot more out there to learn and discover.
Thanks for reading, and let me know if you make anything really cool!
Version 1, 25 March 2006
This site is not endorsed by or affiliated with Electronic Arts, or its licensors. Trademarks are the property of their respective owners. Game content and materials copyright Electronic Arts Inc. and its licensors. All Rights Reserved.