Demonstrate the various features of social interactions: testing whether the interaction should appear, using a path for grouping interactions, handling newly created and reset sims

Demonstrate the basics of error trapping

Briefly discuss how to find the game code you want to use in your interaction

Demonstrate interaction with the user

What you'll need:

A working knowledge of C#

Microsoft Visual C# Express (or the equivalent) correctly set up for scripting mods - MS Visual C# Express is free from Microsoft, and the tutorial on how to set up a scripting project is here: http://simswiki.info/wiki.php?title...Getting_Started (The "Getting Started" and "Additional Preparations in Visual Studio" sections. Note that you may have to make copies of the game packages in a work folder before extracting .dll files if S3PE won't open them in the Program Files location.)

Let's begin with the bare bones - a very simple interaction which will add the interaction "Show sim names" to all sims, and when used will display the names of the active sim and the sim being clicked on. Here's the complete code:

Code:

using System;
using System.Collections.Generic;
using System.Text;
using Sims3.Gameplay;
using Sims3.Gameplay.Actors;
using Sims3.Gameplay.Autonomy;
using Sims3.Gameplay.EventSystem;
using Sims3.Gameplay.Interactions;
using Sims3.Gameplay.Utilities;
using Sims3.SimIFace;
using Sims3.UI;

The "using" statements should be obvious if you're familiar with C# - they establish shortcuts so you don't have to spell out the full path to the various parts of the game libraries you'll be using.

Code:

namespace cmarXmods

You should always use a unique namespace to avoid any confusion with other mods or the EA code, and it's not a bad idea to use the same one for all or most of your mods, sort of as a brand name.

Code:

[Tunable]
protected static bool kInstantiator = false;

What this does is set up a tunable variable associated with your script, which also has to be defined in an XML tuning file just like the tuning files used in tuning mods. This is what forces the game to execute your code - it will find the XML tuning file and invoke your script to define the variable kInstantiator. Later I'll show how to set up the XML.

This is the event handler. It iterates through the collection of all the sims in the neighborhood (returned by Sims3.Gameplay.Queries.GetObjects<Sim>()), tests that the sim actually exists, and calls the method to add the interaction.

The interaction definition implements the EA ImmediateInteraction<Sim, Sim> abstract class which inherits from a bunch of other classes. All you really need is to use the format above and substitute your own code in the Run, GetInteractionName, and Test methods.

protected override bool Run() - The code you write to do whatever you want your scripted interaction to do goes here. You must return a true or false value. Note that you can refer to the active sim as "base.Actor" and the sim being clicked on as "base.Target".

protected override string GetInteractionName(Sim actor, Sim target, InteractionObjectPair interaction) - Here, you return a string with the text you want to show up in the pie menu.

protected override bool Test(Sim actor, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) - Here, you can test whether your interaction should show up for a particular sim. "actor" is the active sim, "target" is the sim being clicked on. Return true to show the interaction, false to not show it.

Also note that in the line: private sealed class Definition : ImmediateInteractionDefinition<Sim, Sim, ShowNotification> the last parameter (ShowNotification in the example) must refer to the name of your interaction.

And that's it for this very simple example, as far as coding. Now let's talk about packaging it up for use in the game.

After you've saved your project and successfully compiled it using the Release compile option, you should find a .dll in your project's \bin\Release folder. In this example, I've named my project DemoScript, so I find DemoScript.dll in C:\Users\<myname>\Documents\Visual Studio 2008\Projects\DemoScript\DemoScript\bin\Release.

Use S3PE to create a new, empty package. Click Resource/Add. In the Resource Details window that pops up, set the Type to "S3SA 0x073FAA07". Fill in the Group with 0x00000000. Tick "Use resource name" and the Name field should become active. Now refer back to your script and fill in the Name field with the full path of your class - your Namespace and class name separated by a dot. In this case, that's "cmarXmods.DemoClass". Click the FNV64 button and the Instance will be filled in for you. Click Okay and you'll get an empty S3SA resource. Highlight it and click the Grid button at the bottom of the S3PE window, and you'll get another popup. In the Assembly line, click on "Import/Export/View Hex/Edit...", click the down arrow, then click Import. Browse to the .dll file you located in the last paragraph and import it. Click Commit.

Now use Notepad or any text editor to create and save a text file with the following text:

Hopefully you recognize our friend kInstantiator as the tuning variable in the script. This is the tuning XML to go with it. Drag the text file into S3PE and you'll get another Resource Details popup. This time set the type to "_XML 0x0333406C", the Group again to 0x00000000, and again tick Use Resource Name and fill in the name with your full class path and click FNV64. (Or just copy the Instance of the S3SA.) The Instance ID is important - it MUST be the FNV64 hash of the full class path or the game won't find and execute your script.

Save your package, install it, and test. If all goes well, you'll see a new interaction that will display your active and target sims' names in the notification window.

Next: Enhancements to control when the option shows up, handling newly created sims, etc.

Credits: I've learned from so many people in the forums and tutorials. A partial list: Velocitygrass and Buzzler for being very helpful when I was starting out and for providing examples and tutorials. Much of the code I'm using here originally came from them; all I've done is put it together in tutorial form. Twallan for his generally awesome coding I've so often used for guidance, Peter and Inge Jones for s3pe, and everyone in the Modding Discussion forum.

public static bool Exception(Exception exception) - The primary error handler; it catches the error and tries to write it to the screen. If this works, you get nice ugly error code all over your game which you can read and then dismiss. If it doesn't work, the next method catches that error.

By using a try/catch at the places in your code where an error seems most likely, you can both see debugging information which may help you find the problem, and allow the game to continue past an error without crashing. Here's the code adding interactions to the sims with error handling added:

In real modding practice, there are going to be options that only apply to some sims - only adults, only teens, only horses, etc. It only clutters the pie menu and confuses the user if you add them to the wrong sims. The solution is to add them only to the sims you want. Suppose for some odd reason I only want to add the name-display option to sims who are teens, YA, adults, or elders:

I've added a condition in the AddInteractions method to test for age. The Sim.SimDescription class has many useful fields, methods, and properties, including properties for age, gender, species, and many more things you may want to test for.

But now I decide, for some equally odd reason, I only want the option to show up if the active sim is the same age as the target sim (the sim being clicked). This means I want the option to be available for all sims teen or above, but to show or not show depending on who's clicking whom. To do this, I modify the Test method in the interaction definition:

Now the Test will return true if the two sims are the same age or false if they're different ages. (Or true if the sim clicks him/herself.) If the returned value is false, the option will not show in the pie menu.

Handling newly created sims

During gameplay new sims are born, or created by story progression, or created with a mod like Master Controller. You need to handle that situation by adding your options to them. This creation is called instantiation, and there's a game event that's fired when it happens. In your script, you'll need to add an event handler for that event. First add this line in the main class where it'll persist for the life of the class, to define an event listener:

Bet you were wondering why I have a separate method for adding interactions! This is why: you can call the same method here. Then add the listener in your OnWorldLoadFinished event handler so your code will be called when a sim is created:

But wait; there's more! Suppose a sim gets reset during gameplay. When this happens, the sim is instantiated and the instantiation event is fired even though the sim isn't newly created and already has your interaction added. In order to avoid having your interaction showing up twice (or more), you need to test whether it already exists for that sim:

in the WorldLoadFinished event handler. In this example I'm using the same event handler ListenerAction as for instantiation since it already does what I want, but it could use a different one if necessary. In the next lesson I'll talk a little more about the available game events.

Defining paths and submenus

Okay, things are getting a little more complicated in my mod and I want to add more than one interaction. (Add more interactions by adding a class and definition for them, and add them to the sim in exactly the same way as the first one. There's no limit I know of to how many interactions can be added in one script.) I want to group my interactions so that the initial pie menu shows "MyStuff Options...", you click on it, and then you get the "Show sim names" option along with any others I may have added. Fortunately this is easy. In the interaction Definition class (inside the interaction class), add an override method for GetPath:

What this does is define a path for your interaction - in this case it's "MyStuff Options..." / "Show sim names". If you define more interactions using the same path, those options will show up along with "Show sim names" when you click "MyStuff Options...". Note that GetPath returns a string[] array, so you can define more than one level in your path.

Now to dig a little deeper and discuss interactions with the user and examining game code.

User Interactions

Sometimes you'll want to ask the user to select an option, enter a value, or answer a question as part of your scripted action. I'll show you a few simple ways to do this, and where to look for more. All the demo code goes in the Run() definition of the interaction. In the code below I've changed the interaction text to "Show sim information" since we'll be displaying different kinds of information depending on what the user chooses.

The user dialogs below are defined in game code in Sims3.UI. For convenience, you should include the line:

Code:

using Sims3.UI;

in your 'using' statements at the beginning of your code.

Let's start with a basic two button dialog that gives the user two choices:

In its simplest form, TwoButtonDialog.Show requires a prompt string ("Choose which to show") and labels for the buttons ("Gender" and "Gender Preference"). It returns a boolean you can use in your script - true if the first button is clicked and false if the second button is clicked. It can also be used for a Yes-No dialog.

Note that ThreeButtonDialog returns a ThreeButtonDialog.ButtonPressed enum, which can be tested to find out which button was clicked. This method can also be used to provide two choices and a 'Cancel' button.

If you need the user to enter a value, such as a number, there's a method for that too:

I've included two variations. The first is the simplest form which takes the dialog title text ("Text Entry Dialog"), the prompt text ("Type something:"), and the default text to be displayed when the dialog box pops up (I've left it blank: ""). The second also takes a boolean specifying whether the user input must be numeric. There are other overloads which allow validation and other refinements. And there's also a TwoStringInputDialog method and a ThreeStringInputDialog method that let you prompt for two or three strings.

But what if you need the user to pick from a whole list of options? This gets a bit more complicated - we have to construct a list of type ObjectListPickerInfo and populate it with our options, then use that as an argument to ObjectListPickerDialog.Show(). Below is a very simple example of an outfit-changing dialog that gives the user a choice of which outfit category to change into:

First, declare the list of type ObjectListPickerInfo, then add elements to it. Each ObjectListPickerInfo element consists of a label and an object which can be of any type you need to use - in this case the Sims3.SimIFace.CAS.OutfitCategories enum. This list gets passed to the ObjectListPickerDialog.Show method which displays the list, lets the user pick one, and returns the object for that list element. Then we cast the returned object back into Sims3.SimIFace.CAS.OutfitCategories and use it to tell the sim which outfit category to change into.

Or you can use ComboSelectionDialog, which works almost the same way but takes a string for the dialog box title, a Dictionary instead of a List, and a default object; and appears in the game as a dropdown list:

There are more methods for user interaction than I can get into in this tutorial. Next we'll look at how to find and examine these and other game structures and methods in the game libraries.

Examining Game Code

Where do I get all these wonderful toys? :D

Scripting mods can call on the EA game libraries of classes, methods, properties, etc. to do all kinds of things inside the game. In order to use them, obviously you have to find them and hopefully have some understanding of what they do.

First, some background. Game code comes in two flavors: managed and unmanaged. We can use only the managed code; unmanaged code does a lot of nuts and bolts stuff that's not directly accessible to modders. Managed code is installed on your computer in the form of .dll libraries inside .package files. Presumably when you set up Visual C# Express you extracted the .dll resources and added them to your project as references. (http://simswiki.info/wiki.php?title..._Studio_project) Now we'll look at how to examine the actual code in them.

There are two popular tools for this: .NET Reflector ($95, http://www.reflector.net/), and ILSpy (free, http://ilspy.net/). If you didn't get Reflector back when the price was more reasonable, the choice should be obvious. I'll use ILSpy for my examples, but they work pretty much the same way although Reflector has a slicker interface. (To install ILSpy, download the binaries using the "Download Binaries" button at the top of the main page, and unzip into a folder anyplace convenient. Then run ILSpy.exe.)

To set up the first time, first remove any assemblies listed on the left side of the window. Then open the game assemblies from the same location where you extracted them for use with your scripting projects. You should include mscorlib (the EA mscorlib - make sure it's the one you extracted from the game packages), ScriptCore, SimIFace, Sims3GameplayObjects, Sims3GameplaySystems, Sims3Metadata, System (again the EA version), System.Xml, and UI. When you're done, ILSpy should look like this:

What ILSpy and Reflector do is to decompile the code in the dll libraries back into a readable programming language - in our case, C#. Now it's just a matter of poking around in the code to see what's useful and what we can call in a script. For example, if you expand UI and under that expand Sims3.UI, you'll find the interaction classes used in the examples above, along with a lot of others. By clicking on a class you get a list of the fields, properties, methods, etc. in that class on the right side, which can also be expanded to show actual code.

Remember the game events discussed back in lesson one? The full list is an enum in Sims3GameplaySystems: Sims3.Gameplay.EventSystem.EventTypeID:

One more example - in Sims3GameplaySystems you'll find the Sims3.Gameplay.Actors.Sim class with a long list of useful properties and methods for manipulating sims. One of the properties is the SimDescription class which has its own long list of components. There's also the Genealogy class with information about the sim's family.

It can take a lot of time and patience to find what you're looking for.

One last tip - you'll notice that a lot of the methods and so on are private or protected and MS Visual C# Express won't let you use them. If you need one of these resources, you can create a custom, unprotected dll to use as a reference for your project. There's a discussion here: http://www.modthesims.info/showthread.php?p=3766584

Otherwise, you'll probably have to disassemble the dll using ildasm, open it in a text editor, replace all instances of ' private ', ' family ', and ' sealed ' with ' public ', save, and reassemble with ilasm. Instructions on finding ildasm and ilasm are here in Section E: http://www.modthesims.info/showthread.php?t=354419

I've attached the complete script with the interaction examples above. I hope this is useful, and happy scripting!

I wanted A Social Interaction Like ( Amorous Hug ) Or something like it , Where you can add your custom animation & stuff .

Do you have any idea how we can do that ?

I really appreciate it , thanks :D

This tutorial covers the basics of how to add a generic pie menu interaction. The action performed by the interaction could be anything you can code, I imagine including animations. But apparently a true social interaction is more complicated - here's a thread with a summary: http://www.modthesims.info/showthread.php?t=492221

Programming is one of those things that requires a very specific mindset. I'll be immodest for a second and say that I'm at least a decent programmer, but I will say that I am not a programmer by existing trade or career aspiration and I flatly hate it. Game design is so much more fun and interesting than actually going in and digging around with the nuts and bolts, but the sad truth is that they're institutionally linked and you can't have one without the other. All I can say is keep at it. If you get discouraged, back away, play some games, write down some ideas, and come back fresh a day later, a week later, or a month later -- whatever works for you -- and suddenly what looked like Greek will look like fenugreek for cooking with.

I will say it's pretty important to learn at least one programming language (not necessarily C#) before you attempt to do anything that actually involves programming, however. Attempting to self-teach programming without a step-by-step tutorial, by simply going in and playing around with "pure base virtual deconstructors" and whatevertheheckelse, will not teach you anything useful and will teach you all the wrong things. =)

Twallan's framework also has a social action injection system, which you can also look at if you use ILSpy. Twallan even offers to provide NRaas source code to anyone who asks for it. Unfortunately Twallan's framework is purpose-built for his suite of mods and is thus very robust (and by extension extremely hard for a beginner to understand).

Ahmad, coding is not easy and not something you can pick up in a few hours. If you don't have any programming experience it can take weeks or months to learn the basic principles of how to construct program logic, understanding data types and structures, how function calls work, etc. etc. Just the terminology can be a challenge. Beyond that, it takes experience and a basic talent or detail-oriented mind and lots of patience to become a GOOD programmer. I think too many people come in thinking they can quickly put together something that does what they want.

I'll add that IMO C# is not an easy language to learn, especially for a beginner, since you have to learn the basics of Object Oriented Programming (OOP) in order to have any clue what you're doing. In my working life I was a career applications programmer, and a good one: learned Cobol in school, and used mostly Fortran, Assembly, and Cold Fusion on the job (which tells you how old I am). It still took me weeks to wrap my brain around C# enough to do the most basic useful scripting mods and months to get to the point of being what I'd call really productive.

I'm not saying this to discourage anyone - just so you have realistic expectations. Coding is a skill that takes a lot of work, but it can be tremendously rewarding. Personally, I love every frustrating, aggravating, sometimes tedious, sometimes confusing moment. When that program or script takes shape and starts doing exactly what you want it to do, it feels like creating a beautiful work of art.

Creating custom animations is easy compared to this. I couldn't figure it out how to add "FirefighterEmergencySituation.CarryOutChild " to Sims pie menu. Gosh, I also really need that interaction for my movie.
If there is another way to add that interaction please let me know.

Have you tried adding it to adult sims the same way you'd add a custom interaction? Although I suspect the firefighter carry interaction will only work in an actual fire. It might be possible to copy the animation calls from the carry interaction definition, though.

Great tutorial! You wrote it in a very clear, straightforward way that made it easy to follow. I had your example up and running soon after figuring out a minor glitch I made when setting up a VS-compatible project.

Now I just have to learn more about C#. I've been programming for a while, but never got around to learning that language. Well, this is a good excuse to start!

i have a question to your tutorial "Modding - General - Tutorial: Adding pie menu options to sims". I tried it out, but it didnt worked for me... I took your code and created a dll file (before i did the correct setup for VS, i use VS 2010 Express). No errors or something else, so far so good. Then i wrote the XML file, exactly as you wrote it. Finally i created the S3SA file in S3PE with your settings (means correct namespace and classname) and added the XML file to it. Then i saved it as a package-file and put it into the Mods/Packages folder, where all the other packages are... Start the game, chose my family, but after loading and selecting a sim there is no new interaction icon . its all like it was before... where is the mistake?

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ecdcc8d1-b218-413d-9297-098a2bb6ce5b")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Did you add "using Sims3.SimIFace;" and "[assembly: Tunable]" ? Not having "[assembly: Tunable]" may be causing your problem. It says to do this in the "Pure Scripting" Visual Studio setup instructions but not in the "Creating a game compatible Visual Studio project" - my mistake for not pointing that out. I'm revising the tutorial to say only to use the Pure Scripting instructions to avoid confusion.

Please do not PM me with mod, tutorial, or general modding questions or problems; post them in the thread for the mod or tutorial or post them in the appropriate forum.

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ecdcc8d1-b218-413d-9297-098a2bb6ce5b")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Did you add "using Sims3.SimIFace;" and "[assembly: Tunable]" ? Not having "[assembly: Tunable]" may be causing your problem. It says to do this in the "Pure Scripting" Visual Studio setup instructions but not in the "Creating a game compatible Visual Studio project" - my mistake for not pointing that out. I'm revising the tutorial to say only to use the Pure Scripting instructions to avoid confusion.

Have you tried adding it to adult sims the same way you'd add a custom interaction? Although I suspect the firefighter carry interaction will only work in an actual fire. It might be possible to copy the animation calls from the carry interaction definition, though.

You couldn't possibly test this out? Please? All I can do are custom animations, I'm not understanding at all how to add interactions to pie menus.

I don't have it in VS. I get the error "The type or namespace name 'Definition' could not be found (are you missing a using directive or an assembly reference?)". I think I need to prefix it with Sims3.SimIFace or something, but I don't know which. Can you help me?

Let's Play Sims.Seabody's Mods - all thoroughly tested to ensure that they work correctly.

I don't have it in VS. I get the error "The type or namespace name 'Definition' could not be found (are you missing a using directive or an assembly reference?)". I think I need to prefix it with Sims3.SimIFace or something, but I don't know which. Can you help me?

Can you upload or post your complete code so I can take a look?

Please do not PM me with mod, tutorial, or general modding questions or problems; post them in the thread for the mod or tutorial or post them in the appropriate forum.