255 points by mountainplus 0 days ago
I noticed this (the original code, and your implementation) seems to only describe the "state of feelings" for a simulant and how they generally only get worse over time. I'm now keen to see the code that then provides direction and action for the sim based on this state; e.g. "I'm feeling hungry, I should eat, what should I eat?" and the process that determines what it should eat - and how to go about it. I know The Sims employed more than just A*-towards-nearest-unoccupied-food-source, but what makes a Sim choose hamburgers from the outdoor grill over making dinner in the kitchen?
This demo (starting at 13:06) shows how the SimAntics visual programming language works, and how objects publish advertisements for their available actions (which show up on the pie menus that the user can select, or which the characters can autonomously choose to perform).
Advertisements appeal to characters based on their current motivations (feelings, hunger, etc), their distance from the object, their relationship with the object (so you prefer to sleep in your own bed), and SimAntics scoring functions that can perform arbitrary calculations.
Then it shows how all that works together in the "Food Chain", a complex Rube Goldberg device comprised of many different objects, that compels characters to perform the many sequential steps required to prepare and eat food (when then compels them to poop, which makes them need a shower, which makes them tired, and so on).
The main loop of the "autonomy" algorithm that decides what to do next (if you don't tell them what to do) searches for the top several advertisements with the highest score, and then chooses randomly between them. If they always chose the top scoring best thing to do, then their lives would be too mechanically optimized, lacking in whimsey and spontaneity, and anything the user told them to do would deviate from the optimal path, making their lives less efficient, more miserable.
So for better game play and happier users, we randomly dumbed them down a bit so they needed the user's guidance to have a better life (but we didn't make them so dumb that users couldn't fuck up their lives even more, either).
> If they always chose the top scoring best thing to do, then their lives would be too mechanically optimized, lacking in whimsey and spontaneity, and anything the user told them to do would deviate from the optimal path, making their lives less efficient, more miserable.
Couldn't they add a "monotony" factor to the SimMotive struct that increases as their daily life becomes too uniform, which in-turn leads to greater overall unhappiness if it's too monotonous, or greater overall stress if their days become entirely unpredictable?
That would cost more CPU for the same result.
The trick of optimizing games is to off-load as much as the simulation from the computer into the user's brain, which is MUCH more powerful and creative. Implication is more efficient (and richer) than simulation.
During development, when we first added Astrological signs to the characters, there was a discussion about whether we should invent our own original "Sim Zodiac" signs, or use the traditional ones, which have a lot of baggage and history (which some of the designers thought might be a problem).
Will Wright argued that we actually wanted to leverage the baggage and history of the traditional Astrological signs of the Zodiac, so we should just use those and not invent our own.
The way it works is that Will came up with twelve archetypal vectors of personality traits corresponding to each of the twelve Astrological signs, so when you set their personality traits, it looks up the sign with the nearest euclidian distance to the character's personality, and displays that as their sign. But there was absolutely no actual effect on their behavior.
That decision paid off almost instantly and measurably in testing, after we implemented the user interface for showing the Astrological sign in the character creation screen, without writing any code to make their sign affect their behavior: The testers immediately started reporting bugs that their character's sign had too much of an effect on their personality, and claimed that the non-existent effect of astrological signs on behavior needed to be tuned down. But that effect was totally coming from their imagination!
They should call them Astrillogical Signs!
The create-a-sim user interface hid the corresponding astrological sign for the initial all-zero personality you first see before you've spent any points, because that would be insulting to 1/12th of the players (implying [your sign] has zero personality)!
Most likely you can infer a really complex set of events from this logic. For example, perform a "dice roll" while at a certain level of hunger (similar to how there's two dice rolls in the linked code that can cause the sim to freak out if stress goes too low). Additionally, the type of food can be inferred from the severity of the sim's state and time of day (e.g. snack vs breakfast vs dinner, etc).
All these "tricks" together, combined with a human's tendency to rationalize observations ("X must've happened because of Y"), can make for something that seems alive. :)
It's also quite mesmerizing to watch the relationships between the different numbers (e.g., the alertness value fluctuates, causing energy to either fall slowly or rise quickly), and all these layers add to the apparent complexity.
"combined with a human's tendency to rationalize observations" -- yes, that's a great explanation of what I meant by "implication is more efficient that simulation"!
One reason SimCity and The Sims were successful was because they were about domains that everyone has a lot of first hand common sense experience with, so players can richly and creatively fill in the gaps with their imagination. But SimEarth and Spore, for example, weren't as successful, because most people don't have first hand day-to-day experience with plate tectonics or space exploration to draw from.
The Sims only has a few things it can do at any point in time, but by rolling some dice and choosing randomly between discrete options weighed by dynamically calculated scores, the otherwise robotic obsessive compulsive behavior gets "dithered" into a smoother more organic stream of life choices.
I think of it like error diffusion dithering, where you only have a palette of 256 colors (or black and white, or an ugly web palette, or whatever), but you're trying to render a full color picture, so you choose the discrete color that's closest enough, then diffuse the error into the surrounding pixels. The human eye blurs those 256 colors into continuous gradients of smooth true colors, and the human brain then recognizes details that aren't actually there, which you can't see if you zoom in on the individual pixels.
The Sims diffuses the errors over time instead of space. For example, if you've gotten a bit grubby, you might wash your hands or take a shower. If you're nearby a sink and the shower is upstairs, then you'll probably just wash your hands, and you won't get as clean as you would have if you'd taken a shower. But then you're left over with some dirtiness that "diffuses" into the next time you wash somehow. If you only washed your hands, then you'll need to wash again sooner somehow, but if you took a shower, you get a longer period of time before your need to wash outweighs your other needs at the moment (or gets lucky thanks to dithering).
The Sims uses random numbers to choose between dynamically scored actions, to achieve "behavioral dithering" to avoid large scale patterns like "behavioral banding" (obsessive compulsive robotic behavior).
The art is in choosing a good spanning "behavior palette" of possible objects and actions, and tuning the scoring parameters and functions of each action that map the character's dynamic state to a numeric score.
The action scores can depend on your motives, and can attenuate based on your distance, and can take into account your relationship and past interactions with the object (so you prefer to sleep on the same side of your own bed instead of on the couch, and you're not allowed to play in bed with your enemies).
Action scores can also be unrealistically contrived to compel desired high level behaviors like leading Sims through the food chain (like a delicious carrot on a stick leading them around the kitchen and into the dining room to finally sit down and eat), or the irresistible "comeandseeme" object (shown in the video demo) that makes everyone in the house drop what they're doing and fawn over a newly born baby, or the diabolical "Crowd Sitter" I made for controlling large crowds of people at weddings and cult meetings.
When in play mode, you can turn a Crowd Sitter on and off with a pie menu, and it directs all people to sit down in front of it, or stand up facing it if there aren't any seats left. It has an effective radius of about 7 tiles (more now), with a quarter pie slice shaped footprint. You can strategically deploy as many sitters as you need, to cover all the seats you want people to sit in or areas you want them to stand (like rows of pews in a church or a circle of benches in a stadium). I made a special routing slot that has a maximum size 54 tile footprint (more now), based on the TV set's routing slot, but on steroids.
Dither is an intentionally applied form of noise used to randomize quantization error, preventing large-scale patterns such as color banding in images. Dither is routinely used in processing of both digital audio and video data, and is often one of the last stages of mastering audio to a CD.
The algorithm achieves dithering using error diffusion, meaning it pushes (adds) the residual quantization error of a pixel onto its neighboring pixels, to be dealt with later. It spreads the debt out according to the distribution (shown as a map of the neighboring pixels)
Here's some more Sims stuff:
Something about this program reminds me of the text-mode BASIC games that used to be published in books and magazines in the 1980s.
I remember typing the programs and simultaneously trying to imagine how the simple logic I was entering might build up to something awesome that could be lurking there, just out of my sight between the numbered lines. Most of the time it was a disappointment, but a few of those games did manage to elevate themselves to some kind of unexpected, exciting life that I couldn't have known from just reading the program.
(Of course my standard for excitement was very low.)
You have a point. In a certain light, The Sims is a more complex version of Conway's Game of Life, with its simple life-or-death rules for the cells in the game.
Could be one of the few lines of source code survived, as an small office fire in 2001 caused troubles.
Basically the predecessor of The Sims was SimTown (also by Maxis). It was a smaller scale SimCity meets The Sims gameplay. https://en.wikipedia.org/wiki/SimTown
Later SimsVille was meant to evolve the gameplay in the same direction again, though it go canceled (source code lost due office fire). https://en.wikipedia.org/wiki/SimsVille
Almost all the [Maxis] games development data was lost during a small office server room fire [in 2001], that resulted in most of the game being developed again from scratch, according to this source: https://www.unseen64.net/tag/maxis/
Initial 1996 design document of The Sims, when it was still called "Happy-Friends-Home" from the same website: http://donhopkins.com/home/TheSimsDesignDocuments/HappyFrien...
I had a revelation while playing the Sims, and this code lays it bare. I found I was spending more time managing these values for my Sim than I was for myself. I have not enjoyed most single player games since.
Realizing that Sims games are really meta-games about life is how you actually win any Sims game. The only winning move is not to play.
Love how simple it is. A good lesson for anyone trying to kaie a gake. Make the core simple and that will allow complex interactions hetween them.
> kaie a gake
What does that mean?
It sounds Simlish, like "kaie a covfefe gake".
I assumed "make a game" as typed on a mobile device without autocorrect.
m->k and k->i looks like the right hand on the keyboard was misaligned one row too high.
Wouldnt that be "jaie a gaje"? The k and m are offset in different directions. This looks like the kind of havoc a mobile keyboard would wreak.
Nah. Depends if you're going slightly "north-east" or slightly "north-west". Also probably depends on your locale.
I'm guessing 'make a game'
I think he meant bake a cake.
Make the core simple --> complex interactions
I always thought sims borrowed the idea from Little Computer People (~1985)
looks like someone copied the code over here: https://github.com/AlexanderPatrick/MPhil/blob/7592cd0dfe7c4...
Is there an advantage to storing this as an array, indexed by enum, rather than a strict of 16 floats?
I can't think of a reason. Having to index by enum seems like it could be error prone.
Also, in the init(), instead of looping over all indexes of the array and setting 0, couldn't a memset be used?
It enables the coder to engage in some late binding without engaging in a lot of casts or more elaborate metaprogramming: the enum index used for assignment is itself an assignable value and therefore can be passed around and manipulated if the algorithm needs it. It's a very intentional tradeoff of structure and long-term clarity for a faster turnaround to make design changes.
I haven't even checked to see if the final program uses it. It's the kind of thing, though, that you might go in thinking, "maybe I will need that", and it doesn't add too much overhead to your prototype.
OMG - I am so old school I can tell you!
You can have functions iterate through the array. You may want have special functions for each indexed item, but if there is something you want to do for all of them -- say save or load, you can iterate through the list.
It gives a consistent layout in memory, meaning you can save/load very simply. Using a struct puts you at the mercy of the compiler's struct packing and alignment settings.
The other stuff is more stylistic but I'd guess he writes a lot of assembly code, and the enum style translates easily to asm.
I would agree with you. Stuff like `changeMotive` could just take a pointer rather then an index and then you wouldn't need it to be an array. More-over, if you still want to be able to do that loop to check for underflow/overflow at the end, you could just `union` it with an array - use the regular member variables throughout the code, and then use array at the end.
But it was written in 97 so personally I'd give him a break. It might be a style he picked-up from coding on some earlier projects where it made sense (Say, for speed, or because the compiler was garbage).
See ChangeMotive for some use of it.
Is there a bug in the line computing Motive[mHappyWeek]? It seems like it should have Motive[mHappyDay] instead of Motive[mHappyNow] on the right hand side.
What would this look like if it were using behavior trees, hierarchical fsm, or whatever the prevailing pattern is used today?
That code is just a prototype, the seed around which the rest of the game nucleated. There is a big thick layer of behavior trees, hierarchal state machines and lots of whatever layered on top, including a visual behavior tree programming language called "SimAntics" and an editing tool called "Edith", which is described and demonstrated here (starting at 11:20):
Here's another demo of some tools for making and managing user created content for The Sims, and SimSlices's amazing version of SimCity embedded in The Sims!
To clarify: SimAntics, the behavior tree visual programming language actually existed before Will wrote the "Soul of the Sims".
SimAntics was used in SimCopter for controlling the little Sims with simpler souls who walked around the city, for dispatching the police, firemen and medics who picked up injured Sims and brought them back to the helicopter, as well for implementing the notorious gay easter-egg with a bug that caused hundreds of shirtless "himbos" in fluorescent fog-piercing speedos (using the same special render as runway lights) to swarm all over the city hugging and kissing on Friday the 13th!
The simplicity makes it beautiful.
The formatting in this code is atrocious. It's so much harder to find bugs when the code itself is so disorganized
This code was not made for bug fixing though, it’s just a prototype - the expression of an idea. The accompanying text even says as much - of course the final game couldn’t possibly have a single sim’s mood in a global variable.