Hi there! You are currently browsing as a guest. Why not create an account? Then you get less ads, can thank creators, post feedback, keep a list of your favourites, and more!
Quick Reply
Search this Thread
Retired Duck
retired moderator
Original Poster
#1 Old 25th Dec 2006 at 8:30 AM Last edited by Echo : 25th Dec 2006 at 12:45 PM.
Default Data Types for Simantics Users
TS2 Data Types for Simantics Users

Overview

If you've never made a custom BHAV before, this is not the document for you. I'd suggest one of the Beginners' Tutorials instead. The information here will probably only be helpful for those people who have been playing with BHAVs for a while, but who want to get a better understanding of the different ways in-game data can be stored and changed using BHAVs. It starts out with fairly basic stuff, but gets a little more complicated near the end.

At its simplest level, almost all programming is about manipulating data in some way or another, and SimAntics is no different. If you really want to create extraordinary hacks, it's important to understand the way the game stores this data, and when and how you should use it.

Everything written here is entirely based on observation of the game's behaviour, error logs, and general software architecture theory. If you find anything incorrect or unclear, please let me know asap and I'll try to correct it.

Enjoy, and good luck!

Literals, Variables and Constants

Before delving into the specifics of the Sims data model, it's important to have a very general grasp of data structures and their theory. If you have previous programming experience and can confidently say that you understand literals, variables and constants, please feel free to skip ahead.

Calling something a "literal value" is a fancy way of saying it's a regular, normal value. For example, the number 5 is a literal. The number 3.142 is also a literal. The phrase "the cat sat on the mat" is also a literal. This may seem a very odd idea, but it will make more sense shortly. At this point in time, just understand that the equation:
1 + 5
can be read a bit like this
literal(1) + literal(5)
which says "find the value of literal 1 plus literal 5".

For the purposes of my ongoing analogy, a literal is like a number that is written on a piece of paper in pen. Fair enough?

Now, variables are a bit different. Variables are names we give to a place where a literal can be stored. If you're imagining a literal as a value on a piece of paper, then imagine a variable as a plastic sleeve. You can put the literal into the plastic sleeve, you can take the literal out of the plastic sleeve, and you can put a different literal back into the plastic sleeve afterwards. But here's the clever bit - you can also put a label on that plastic sleeve. For example, you could label the plastic sleeve "Number of days until my birthday", and put a literal into it saying 50. If someone asks you "how many days until your birthday", then you can find the right plastic sleeve, then tell them what literal is stored in it. Tomorrow morning, you can take out the literal value you put in there, find the literal that is one lower, then put that into the sleeve instead. Now if someone asks you "how many days until your birthday", you can follow the exact same set of steps to find out, but the value you give them back will have changed.
In the Sims, variables don't always have such sensible names (although you can give them names if you wish). By default, they just have numbers. So if you have three variables, then you can access the values in them by number. For example:
variable(0) := literal(1)
variable(1) := literal(5)

variable(0) + variable(1)
is much the same as the equation listed under "literals" above. Note that the ":=" symbol means "gets the value of". The first line says "variable 0 gets the value of 1". The second line says "variable 1 gets the value of 5". The third line says "find the value of what's in variable 0 plus what's in variable 1".

All good? Good. If you're fine with that, then you should be okay with the rest of this document.

Finally, constants are special types of variables. You can only put a literal into them once. Then they can never be changed (ie - they can not "vary", they are "constant"). Instead of being like a plastic sleeve, this is more like encasing the literal in a layer of perspex. You can pick the value initially, but once it's in the perspex you can't change it again. For example, you might have a constant "how many days in January", which would hold the value 31. This shouldn't ever change, but putting it in a constant makes sure that you can always get at it when you need it.

So that's the three simplest ways of representing data that you will encounter when you're programming, and you'll find that most common programming language around today use them. So, if you want more information about how they work then documentation exists for it all over the Internet.

Now we get to the interesting bit - how this all works in the Sims.

Using built in variables

If you've done any BHAV tutorials before, you're probably familiar with the "Expression" command. This is a primitive command (ie - it's built into the game at the lowest level) which lets you manipulate variables directly. For example, you may know by now that if you enter:
Expression (My motive 0x0008 (Hygiene) := Literal 0x64)
in an interaction, then it will make the current sim's hygene value get set to maximum; 100 points (0x64 is hexadecimal for 100). But take a closer look at it given what you now know about literals and variables. Obviously, the second half is a literal, it is the literal value 0x64 or 100. But what about the left hand side? That has got to be some sort of variable it's storing it in. The variable is called "hygiene", and we're putting the literal value 100 into it.

Motives are one of the groups of variables that all sims get when they are created. Person data and Object Data are also groups of variables that all sims have. You can read the values in them, and you can write new values into them. Because they are variables, you can do all sorts of useful stuff. For example:
Expression (My motive 0x0008 (Hygiene) := My motive 0x000F (Fun))
will set the current sim's hygiene value to whatever their fun value is.

You can also use the Expression command with variables and constants to make decisions. For example:
Expression (My motive 0x0008 (Hygiene) > My motive 0x000F (Fun))
asks "is the value in My motive 0x0008 bigger than the value in My motive 0x000F?". If this is true, then the "true" execution path will be followed. If it is false, then the false path will be followed.

Objects also have similar groups of variables. The Object Data variables that exist in sims also exist in objects. However, the Person Data and Motives groups do not exist in regular objects (obviously). If you play around with the instruction wizard for Expression, you can see what sort of values you can manipulate.

Finally, there is a group of variables that cover information about the lot as a whole. These are called "globals". For example, there is a global variable for the time of day. They can be very handy to read, although you should be very careful when writing to them because they can affect a lot of different things.

Using constants

Constants in the sims are stored in BCON files. Most of the time, they are used to store values that get used in a lot different places in an object. The simple reason for this is that if you initially want the value 0x3 to be used in eight different BHAVs, then a few weeks later decide that 0x3 is too low and you want to change it to 0x5, it's a lot easier to change one number in a BCON file than it is to find all the places in the eight BHAVs where you used the number 0x3 and change them there.

Constant values get stored one to a line in a BCON file, but can be used in almost all the same places that literals can be used. You can specify which constant you're looking for using the instance number of the BCON file (eg - 0x1001) and the line number within the BCON file of the particular constant you want (eg - :0x00). To add constants to your project, you just have to add a BCON file to your package, and give it an instance number in the range 0x1000 to 0x1FFF that hasn't already been used by an existing BCON.

You can also name the constants in your BCON files if you want. Simply open your BCON and click the "Make Labels" button. This will create a new file in your package called a "Behaviour Constant Label". TRCNs are linked to BCONs by their instance number, so TRCN with instance 0x1000 holds the names of the constants defined in BCON 0x1000.

If you open this TRCN file, you can change the labels for each of the lines in your BCON.

Using local variables

Local variables, or "locals" are variables with a very short life span. They are created when a BHAV first starts, and as soon as the BHAV returns it is destroyed. However, you can use it to store and change values for as long as that BHAV runs.

This may seem fairly useless, but locals can be extremely useful. Use them to keep track of how many times you've gone through a loop, or to hold the object ID of a particular object so you can use it later in the function. They're really very handy!

If you want to use locals in your function, then you need to make sure they are created when the function is first called. You can do that by entering the number of local variables you will need into the "Local Var Count" box in the BHAV editor. Once that is done, you can use those variables in any way you wish within the function. It's important to remember that while the number in the "Local Var Count" box is the number of variables you will need, the identifying numbers for the variables start at zero. That is, if you say you need one local variable, it will be called local 0x0. If you say you need two local variables, you will get local 0x0 and local 0x1.

Passing variables to functions

A parameter is a value that you can send to a BHAV that you are calling, so that BHAV can use it like a local. For example, if you were writing a BHAV to give skill points to every sim on the lot, then you might have a parameter which said which skill type to give points to, and another to say how many skill points. That way, you could reuse that function for all sorts of different skills and values.

The function calling a BHAV can specify all of these values using parameters, and then the BHAV which is called will modify its behaviour based on them. These parameters are entered into the "operands" boxes. For any non-primitive functions, the order of the values follows one of two patterns.

The first option allows only literal values. If the parameters are being read this way, then two operand boxes represent one parameter. The first parameter goes in boxes one and two, the second parameter goes in boxes three and four, and so on. The only hitch is that the two boxes need to be read in reverse order. For example, if boxes one and two read 0x01 and 0x23 respectively, then the value of parameter one is 0x2301. (There is a very good reason for this which I won't go into now. If you're curious, ask some time!)

The second way to pass parameters is even more useful though, because it allows you send values from within variables. If the thirteenth operand box (fifth on the second row) is set to '1', this tells the game that instead of using two operand boxes per parameter, it should use three. In this case, the first of each set of three boxes is the "data owner", and the remaining two represent the data value. The "data owner" is the part that says what sort of data to use - literals, locals, constants, sim and object attributes, etc. The remaining two boxes specify the data value, that is, local *0x00* or, literal *0x05*. Like the first way of passing parameters, the two boxes need to be read in reverse order to get the actual value.

Using parameters in your own functions

Making your function use parameters is almost exactly like making your function use variables. You have to make sure that the function knows that it will have parameters, so you need to enter the number of parameters into the box labelled "Arg count". Once you have declared them in this box, you can use them anywhere in your code where you would use locals, but instead of selecting "Local 0x1" you would select "Param 0x1". Like locals, parameter labels start counting at 0x0.

Naming locals and parameters

In the same way that you can label each record in a BCON, you can also label each parameter and local you create for your functions. Simply open up the BHAV you wish to provide labels for, and click the "Make Labels" button. This will create a "Edith Simantics Behaviour Label" file, or "TPRP". You can then use this file to enter names for your locals and parameters, which should show up when you're reading through your code. This can be extremely useful if you have a few variables in your code - you're much less likely to forget what is going on!

Creating new attributes

If you've got a cloned or custom object, you can create new attributes for it, or change existing attributes. All of the attributes for an object are stored within the package, in one of two places. The first is in the OBJD file for the object's master tile. Under the "Attribute Number" field in the OBJD is a number representing how many attributes the object has.

The second place attributes are stored is in the text lists. Text list 0x100 contains one entry for each attribute the object has. If you add records to this text file in your package, you should get more attributes.

In most situations, the actual number of attributes in the object will be whichever is greater out of the OBJD record and the count of records in the text list. In some very rare circumstances though this may not be the case, so it's not a bad idea to make sure the values match across both locations.

Understanding the call stack

I'm afraid we're going to lapse into a bit more programming theory here, and for that I apologise. However, it's important to know a bit about how the game keeps track of what's running at any particular time, because a lot of other things are related to it.

The first thing to understand is what a "stack" is in computing terms. If you can picture a stack of open books, you're pretty much on the right track. A stack is a way of representing all the things that have happened, the order in which they happened, and what thing is currently happening.

For example, say you're reading a book, and you come across a word you don't know. You have to look that word up, but you don't want to lose your place in the book. So what you do is leave the book open on the right page, then grab a dictionary, put the dictionary on top of the open book, and look up the word. Once you've found the word, you can close the dictionary and put it away, the go back to reading the first book right from where you left off. The other thing you'll realise about this sort of stack is that you can only see what's in the top book of the stack. You can't see the text in the bottom book, because there are other books in the way.

A call stack is a lot like this, except instead of books it has functions that are being run. Every time a BHAV gets called, it gets put on the top of the call stack. The space on the stack that each BHAV takes up is called a "frame". The game can only see the frame (BHAV/book) on the very top of the stack, so it will only run code in the top BHAV. Consequently, it starts running that code from the beginning. Now, if that code makes a call to another BHAV, then the game will load a copy of the BHAV which is being called, and put that one on top of the stack. Because it's on the top of the stack now, the game will start executing that one until it either reaches another function call (in which case it will stack another BHAV on top and run that) or until it returns.

When you return from a function, you're saying "I'm finished with this BHAV", and so the game will take it off the top of the stack and get rid of it, revealing the BHAV which called it. The game will then keep going from wherever it left off. If your BHAV returned "true", then when the calling function starts up again it will follow the true path. If your BHAV returned "false", the calling function will follow the false path.

"Me" and the "Stack Object"

In the game, all objects (including Sims) have their own call stack. Any code that runs can tell which object's stack it is running in by looking at "Me" or "My". For example, "My 0x000B (Object ID)" is the variable holding the object ID of whichever object owns the stack the code is being run in. If you have an object which runs an "init" function, then that function will be run in its own object's stack. That's why "My" in an init function refers to the object itself. However, if you have code in an interaction, that code is run in the stack of the sim interacting with the object. That's why "My" in interactions refers to the sim. Because Me/My is always the owner of the stack, it's not something that you can change very easily in a function.

"Stack Object" behaves quite a bit differently though. The "Stack Object ID" is a variable that is created when every BHAV begins execution, and is local to that function. However, unlike most local variables, when the function starts this variable gets defaulted to the value that was in the "Stack Object ID" variable of the BHAV that called it. For example, if function "FirstFunction" does something like:
Stack Object ID := literal 0x5
Call SomeOtherFunction
Then when SomeOtherFunction starts, its stack object ID variable will be set to 5. This only works one way though! Once SomeOtherFunction starts, Stack Object ID behaves like a local. The function can change the Stack Object ID all it wants within its own code, but when it returns those changes will not appear in FirstFunction. FirstFunction will still have the value 0x5.

But why bother with Stack Object ID if it's really just a fancy version of a local variable?

Whenever an object is created in the sim game, it is assigned a number. This is called its object ID, and that number is unique to that object within any particular lot. Say you get a new sim on the lot. The game will automatically give it an object ID - let's say, 0x30. If you ran this code:
Stack Object ID := 30
Then the Stack Object would now be that sim. That means that if you looked at the variable:
Stack Object's motive 0x0008 (Hygiene)
you would get the Hygiene value of that sim. Handy, huh?

When you first enter an interaction, the stack object ID is set to the object that you clicked on to start the interaction. That means that if you don't change the stack object ID in the code, the stack object will point to the object the sim is interacting with.

A great many commands work based on what the stack object ID is. Others will store values into the stack object directly. For example:
0: Stack Object := 0 [True: 0x1, False: Error]
1: Set to Next (Object in room) [True: 0x2, False: Return True]
2: Go to Relative Position (Anywhere near, Stack Object) [True: 0x1, False: 0x1]

"Set to next" changes the value in Stack Object ID to the next highest value that meets the criteria that you provide, for example, objects in the same room as the sim. This piece of code will have sims walk to every object in their current room, one after the other.

A quick side note: an object's ID is only guaranteed to stay the same from the time you enter the lot until the time you leave it. While the numbers don't necessarily change between loads, they can do. Also, a Sim's object ID on one lot is not necessarily the same as it is on another lot. If you want to keep track of Sims uniquely, use their "Neighbour ID" number instead.

Using temps

Temps are stored at the stack level, like attributes, but they are only meant to be used to hold things temporarily.

Now that's not very useful if you're storing values just for use inside a function - it's generally better to use locals for that (although there are exceptions to this rule). Since they're only meant for temporary use, they're no good for holding values you want to keep for very long either. But they do have one important use - transferring values between different function calls.

If you use parameters then it is possible for a calling function to give values to the function it is calling, but that only works one way. The only way for a function to return a value back to its calling function is for it to store that value in a stack level variable, so that once the function has finished and returned to its calling function, the calling function can retrieve the value from the stack-level variable. This is the ideal use for temps.

As it happens, a lot of global functions use this technique to make coding complex behaviours easier. For example, if you call global 0x403 ("Get in Temp 0 - Aspiration") then the aspiration of the "me" sim will be stored in the temp 0x0 variable of your stack. Global 0x151 ("Get in Temp 3 - My Handedness") will store a different value in temp 0x3 depending on whether your sim is left or right handed. (As a side note to this, the "Animate Sim" primitive reads the value in temp 0x3 to determine whether an animation should be flipped. That means that if you call "Get in Temp 3 - My Handedness" then run an animate sim command straight after, then a left handed sim will use their left hand and a right handed sim their right!)

Reading and writing temps is much the same as attributes. Just select "temp" as the data owner, rather than "attribute"! Remember that they are really only good for temporary storage of data though, and any time you call a global, semi-global or primitive function it is possible that it might change the values without warning. You also mustn't assume that the value will stay the same after your function has finished. If you do use temps to communicate values across functions, and you want to keep those values or reuse them later, it's a very good idea to copy them into locals or attributes until you need them to be in the temps again.

How this relates to your error log

Once you've made sense of all of the above, then the error log will become your instant best friend when you're trying to edit BHAVS.

If you have a BHAV which is causing an error in game, then the game is able to create an error log telling you all sorts of information about what state the game was in when it happened. If you're not sure how to create an error log, check out this thread:
http://www.modthesims2.com/showthread.php?t=198229

The first (and probably most useful) section of an error log tells you what has actually gone wrong, and roughly where. The Object id row specifies which object owns the stack running the code with the error. That is, the id of the object treated as "Me" in the code. The "name" field directly following this holds the name of that object.

The stack size states the number of frames currently stored in the stack. Don't worry too much about this line, it's not very helpful for debugging.

The next line, "Error", will give you a hint as to what has actually gone wrong. There are a limited range of messages that can be reported, but most of the time it's still a good indication of what has caused the problem. As a quick side note, the two most frequently encountered errors here for beginning BHAV modders are:

- Undefined Transition: That means that execution has followed a path out of a function which is pointing to "Error", or to a node which does not exist.

- Too many iterations: The code is probably stuck in a loop. The game automatically forces an error on any object which gets stuck in a loop, because otherwise the game would hang.

The last line in this section is the number of iterations that the code has been running. Generally this isn't very helpful unless you're looking at very slowly performing loops.

The next section is a very simple summary of everything in the call stack at that moment in time. It is divided into frames, where each frame represents a function call. The frame at the top of the list is the one which was executing when the log was created.

The first two lines let you know what number is stored in the Stack Object ID variable, and which object that number represents. The next line, "Node", reports on which line of code failed. This number is in decimal, so you will need to change it to hexadecimal before you look it up in your BHAV editor.

The next line says which function was being run. The tree id is the decimal equivalent of the instance number of the function, and the name is, oddly enough, the name of the function.

The "from" line says what grouping of functions it comes from. If it is a local function, this will include the NREF name of the package that contains the BHAV. If it comes from a semiglobal or global library, it will name that library.

There's not a lot of information about the prim state at the moment, but it seems to be a way for primitives to report back when something goes wrong inside them. Normally when a primitive fails, it just follows the "false" execution path (unless there is a specific error message which can be associated with the problem) so this field makes it possible to tell which particular error occurred inside the primitive. Unfortunately information about the this field is fairly scarce, so this line isn't really very helpful.

The last line of each frame lists the values of each of the parameters and local variables. They are printed in order, starting from zero, with a space between each variable.

You'll notice that each of the lower frames is showing the state that the data was in when the next function was called - right down to the node (line) number of that particular function call. That's so that when the top frame finishes and returns either true or false, the next frame down can pick up right where it left off.

Underneath the stack trace is a list of all the globals, then dump of data stored in the stack owner (Me), and then a similar dump for the stack object. These potentially have subsections for person data, motives, contained objects (objects which are in its slots), object data, attributes, arrays, temps and inventory. Given what we've already covered above, these should be fairly self explanatory.

Below this section is a complete listing of all the objects in the currently active lot. You'll probably find a whole lot of objects you never realised you had in your lot, because they are invisible and non-interactable. That includes objects like careers, social plugins and meal options. Each object includes information about its object ID, its name and whether it is currently contained inside another object. This is useful if you need to look up an object ID stored in a local variable or a parameter.

Finally, there is a list of the game settings. It's pretty unusual for this to contain the solution to a BHAV problem, but it's handy to know that it's there.

The End?

So that's it. Well, not really - there's a heap more still to learn about the coding, but this information should make it a lot easier to figure out how objects do what they do!

If you have any questions about anything here, feel free to ask!
Advertisement
Instructor
#2 Old 25th Dec 2006 at 9:53 AM
Great Job! Wish I'd had something that was this easy to read and understand when I first started modding, it would have saved me a lot of headaches.
Anyway I have question, in an error log there is a section for data relating to My Object and another for the current stack object. My question is, what is the difference between the list of temps that appear in each of those sections?
Retired Duck
retired moderator
Original Poster
#3 Old 25th Dec 2006 at 10:06 AM
Hey Smonaff!

Because the temps are stored at a stack level, the temps listed under "My Object" will be the temps stored in the "Me" stack. The list of temps under the "Stack Object" will be the temps in the Stack Object's stack. If your code is reading or writing to a temp, then I believe it will be looking at the "My Object" temps.

If you've set the Stack object to point to "Me", then the two lists of temps should be the same.
Instructor
#4 Old 25th Dec 2006 at 10:23 AM
Ah, I get it now, thanks Echo.
Scholar
#5 Old 8th Jan 2007 at 10:50 AM
Echo, thank you for dedicating your time just so newbies like me (not entirely :P) can understand modding a bit better.

Call me Paco!
Rhymes with Taco

I'm currently taking requests until August 12th.
Forum Resident
#6 Old 8th Jan 2007 at 12:14 PM
That certainly makes it easier to understand alot of functions, Thank you Echo, for putting the time and effort into writing this.
Instructor
#7 Old 8th Jan 2007 at 12:15 PM
Thank you so much. I cannot wait to really sit down with this and work through something.

Cogito ergo nupta non sum.
Lab Assistant
#8 Old 24th Jan 2007 at 11:37 PM Last edited by linolino : 24th Jan 2007 at 11:43 PM.
ECHO!!! This is simply a great post! It makes all the sense in the world! Thanks a lot!

So, i have a question.

You said that i can create a new attribute for a object, so it stores for example how many slices of cake there is left, right?
Can I create a new attribute for a Sim too? For eg: When a sim interacts with a object, i want a new attribute to be created in that sim so i can store there some "value" related to that object. But i want that value to be stored even if I exit the game.

What i actually want to know is a way to "mark" a sim so i can identify it in the future with an other behavior that will look for that mark
Retired Duck
retired moderator
Original Poster
#9 Old 25th Jan 2007 at 9:15 AM
Hi linolino! Glad you found it helpful!

Technically speaking, yes it is possible to add an attribute to a sim. Sims are just a special case of objects, and so they have attributes the same as everything else. The problem is that you would actually have to make it a global hack for all sims to have it, which means that you would instantly make your hack incompatible with future expansions and any other hacks trying to do something similar, so not ideal.

However! There's a system which is used in the game to deal with exactly this problem. You can create an object called a "token", which is invisible. That object can have attributes in it just like any item. You can then hide that object in a sim's inventory, and set its attributes to whatever you want. Then, if you want to check or update the value for any given sim, you can loop through all the sim's tokens until you find the one you want, then look at "Stack Object's Attribute" to find the value in all those attributes.

If you want to see an example of this in action in a modded object, check out the "magic skill" and cauldron in the Harry Potter set. In this case, the number of skill points a sim has is stored in the "magicskill" token's attribute, which is created in the sim's inventory the first time they try to use a magic skill-building item, then updated as they gain skill.
Lab Assistant
#10 Old 25th Jan 2007 at 7:41 PM
Great! At first i thought i was wanting somehing not possible, i'm happy it can be done, and easily!
I'm going to check the Harry potter set right away. Thanks for the tip.
By the way, great set!
Instructor
#11 Old 25th Jan 2007 at 7:47 PM
Cool! I never thought of adding attributes to a token, I've always stored data on a token by using the Manage Inventory primitive to add properties to the token and then use the same primitive to read or change the data stored in the properties. Using attributes would certainly be a lot easier.

Tired of getting ripped off by paysites?
http://paysites.mustbedestroyed.org/
Lab Assistant
#12 Old 25th Jan 2007 at 9:11 PM
How is that different Smonaff? I coundn't really understand. whats the difference between adding properties to a token and adding attributes to it?
Retired Duck
retired moderator
Original Poster
#13 Old 25th Jan 2007 at 11:44 PM
Smonoff - That's actually how I've done it in the past too (using the properties option in the inventory primitive), simply because that's how Maxis has always done it. I think it's probably more efficient too... I'm not actually 100% sure how well the attributes technique works, but I do remember seeing tokens with attributes set up on them, which is what I'm basing the above information on. Possibly the ability to use the attributes on inventory items came with the ability to have non-token type objects in the inventory (was that uni that brought it in)?

lino - As a side note, it's not easy in the sense that creating a new attribute in a custom object is easy, it's actually a good deal harder than that. But it has certainly been done and it's not impossible. It's the same ways sim's memories are stored. Properties are like attributes, but they're managed differently in the game I believe, and only exist for certain types of object (like tokens).

I'm afraid my experience with them is fairly brief, so that's about as technical as I'm willing to commit to. If I were guessing though, I'd guess that the property set for a token is stored in an internal stack (can properties be pushed and popped?), accessed by an offset from the bottom. Smonoff, does that sound right to you?
Instructor
#14 Old 26th Jan 2007 at 2:51 AM
Yes, pushing a new property on a token adds it to the bottom of the list or stack of properties. Also when you add the new property you assign a value to it which can then later be read or changed by setting the index to point to the properties position in the stack. And properties can be popped off the stack by setting the index to point to the property you want to remove and using the pop property off token function of the Manage Inventory primitive.

My understanding of the Manage Inventory primitive is basically limited to it's use with tokens and even somewhat limited in that area, but it can also be used for managing the other parts of the inventory system such as memories, and objects stored in the sim's inventory.

With Uni the cell phone, handheld game and the MP3 player were able to be stored similar to the way tokens are, but it was Nightlife that introduced the full inventory system where you can store and retrieve any object in the inventory.

Tired of getting ripped off by paysites?
http://paysites.mustbedestroyed.org/
Lab Assistant
#15 Old 26th Jan 2007 at 7:33 PM Last edited by linolino : 26th Jan 2007 at 7:57 PM.
oh yes, now i remember, the cellphone, handheld and mp3 player were indeed introduced before the full inventory system. that's why they are managed strangely different from other items.

If properties can be pushed and popped, can attributes be too?
I'm guessing thye can't, they have to be set in the token's package right?
so wouldn't it be more flexible to work with properties than with attributes of the token?

Oh and please, can you help with this:
The following is from the SetToNext tutorial from AdidasSG2
Quote:
So looking at our DataOwners for a value of 0x0A we come up with “Stack Object ID”. Now as you may have learned there are no DataTypes for Stack Object ID. So then Op7 must be a variable location. Which in this case is 0x0000.
So for our translation we have
Set To Next(Stack Object ID 0x0000 := object of type GUID of 0x6D6B4BDD “Zit’s Tracker”)
I didn't understand the hex code 0x0000 in front of the Stack Object ID. Does it mean anything?
One horse disagreer of the Apocalypse
#16 Old 26th Jan 2007 at 8:00 PM
All I know is that if you change it to anything other than zero, it throws up an error.

"You can do refraction by raymarching through the depth buffer" (c. Reddeyfish 2017)
Retired Duck
retired moderator
Original Poster
#17 Old 26th Jan 2007 at 11:28 PM
Quote: Originally posted by linolino
If properties can be pushed and popped, can attributes be too?
I'm guessing thye can't, they have to be set in the token's package right?
so wouldn't it be more flexible to work with properties than with attributes of the token?
Right. Attributes have to be created at design time. Properties in a token can be created at run time.

Quote: Originally posted by linolino
I didn't understand the hex code 0x0000 in front of the Stack Object ID. Does it mean anything?
There is only one Stack Object ID variable, so if you're accessing it it has to be 0x0000. That's the same everywhere - if you're using the Stack Object ID as the data owner, then the data value will be 0x0000.
Scholar
#18 Old 18th May 2007 at 5:18 AM
Wow Echo you did a fantastic job on this tutorial. You are so easy to understand. You have been a major help to me. Thanks so much for this.
Lab Assistant
#19 Old 19th May 2007 at 10:17 PM
Thank you so much for taking the time to write this Echo! Lots of things is slowly getting clearer! As usual very well written!
Space Pony
#20 Old 29th Jun 2007 at 4:06 AM
Aloha Echo,

I did your tutorials again (thank you!) because I was trying to figure something out. I'm trying to get this stack object thing down. Thanks to your excellent analogy about a stack of books I see how the stack works, how it passes stuff off & gets control back.

Where I'm having a problem is with figuring out what the stack object is (I know, it can change - sometimes several times) but..... when you click on a picture, the picture is the stack object, right?

Then, if you do the command "Go to Relative Position" immediately, it seems that it's the sim that is the stack object- so is "Go to Relative Position" a command that just automatically changes the stack object? I think the sim must become the stack object because it's the sim that actually goes to the picture.

Is that what you meant by this:

A great many commands work based on what the stack object ID is. Others will store values into the stack object directly. For example:
0: Stack Object := 0 [True: 0x1, False: Error]
1: Set to Next (Object in room) [True: 0x2, False: Return True]
2: Go to Relative Position (Anywhere near, Stack Object) [True: 0x1, False: 0x1]

In line 0, you are setting a literal value of 0 into the stack. Line 1 whatever object is next in the room is the stack object, then line 2: the sim becomes the stack object while it goes to the object in line 1, so the stack object switches back & forth until there aren't anymore objects left in the room for the sim to go to.

Am I understanding this right?
One horse disagreer of the Apocalypse
#21 Old 29th Jun 2007 at 8:24 AM
All the menu test BHAVs and Action BHAVs start off assuming the stack object is the object the sim has selected or the player has clicked on, that's right.

In your line 2, I am sure stack object is the object the Sim is meant to be going to, not the sim himself. Stack object in that context could be a sim, if the current sim is meant to be walking over to another sim. No BHAV can *change* the stack object permanently. As soon as the script returns from a called BHAV, the stack is "popped" and the stack object is the same as it was before the called BHAV ran.

"You can do refraction by raymarching through the depth buffer" (c. Reddeyfish 2017)
Instructor
#22 Old 29th Jun 2007 at 11:48 AM
Quote:
2: Go to Relative Position (Anywhere near, Stack Object) [True: 0x1, False: 0x1]

In line 0, you are setting a literal value of 0 into the stack. Line 1 whatever object is next in the room is the stack object, then line 2: the sim becomes the stack object while it goes to the object in line 1
In this particular case, sim is Me object, Stack Object is whatever returned by previous SetToNext call.
In object interactions, on start of BHAV, Me is the sim who started interaction, and Stack Object is the id of objecdt tile which was clicked.
Retired Duck
retired moderator
Original Poster
#23 Old 29th Jun 2007 at 3:29 PM
Inge and Jasana have summarized it pretty clearly, so I won't go into too much detail.

Basically, for an interaction, the stack object starts out as the object itself, and Me is the sim. "Go to relative position" actually means 'Make the "Me" sim move to a position relative to the "Stack Object" object'. It's not actually changing the value.

In the case of your second code snippit, line 0 is setting the stack object to point at object 0 (ie - no object at all). Line 1 is a "set to next", which looks through all the object ids in order from whatever the stack object id is set to at the moment, and if it finds one which matches the criteria you have set it will set the stack object ID to that. This is mostly useful for loops of code. If you specify a particular criteron (eg - set to next person) then it will only pick up objects which are sims, and set the stack id to point to the person with the next highest object id. If you then loop back it will pick up where it left off and find the next person and so on until it can't find any more people.

Finally, the Stack Object variable itself only gets copied one way. When you add a new bhav/book to the stack, you copy the value of the stack object ID into the new bhav/book. You can change it all you want here, but when you return and the new bhav/book gets taken off the stack, then the old bhav/book's stack object ID hasn't been changed.

And yes, these are quite tricky concepts to understand if you don't have a strong programming background. You're learning them remarkably well! :D
Space Pony
#24 Old 30th Jun 2007 at 1:13 AM
Thank again for all of your help! I am finally getting this

Thank you!
Instructor
#25 Old 22nd Aug 2007 at 10:32 AM
Hey Echo...reading this helped me solve part of my University issue with my clothes changing easel. Thanks for such intellengent words! Have you ever thought of becoming a programming instructor? The way you explain things makes it so easy to learn! I took programming classes - C++. Had to drop out of the advanced class though because the instructor barely spoke english and I needed good explanations - like yours! Oh well, I really like the design side of things better - although I think I am better with the logic of programming, I just find it somewhat teadious and boring - except for the sims stuff I am doing....done rambling now...LOL.

By the way...is there a pdf version of this - its just that its sooo handy!
Page 1 of 2
Back to top