Mod The Sims

Mod The Sims (https://modthesims.info/index.php)
-   Tutorials (https://modthesims.info/forumdisplay.php?f=619)
-   -   Tutorial: Adding pie menu options to sims (https://modthesims.info/showthread.php?t=491875)

CmarNYC 24th Nov 2012 7:37 PM

Tutorial: Adding pie menu options to sims
 
What this tutorial will do:
  • Show you how to add a social interaction to a sim
  • 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;

namespace cmarXmods
{
    public class DemoClass
    {
        [Tunable]
        protected static bool kInstantiator = false;

        static DemoClass()
        {
            World.OnWorldLoadFinishedEventHandler += new EventHandler(OnWorldLoadFinishedHandler);
        }

        public static void OnWorldLoadFinishedHandler(object sender, System.EventArgs e)
        {
            foreach (Sim sim in Sims3.Gameplay.Queries.GetObjects<Sim>())
            {
                if (sim != null)
                {
                    AddInteractions(sim);
                }
            }
        }

        public static void AddInteractions(Sim sim)
        {
            sim.AddInteraction(ShowNotification.Singleton);
        }

        private sealed class ShowNotification : ImmediateInteraction<Sim, Sim>
        {
            public static readonly InteractionDefinition Singleton = new Definition();
            protected override bool Run()
            {
                StyledNotification.Show(new StyledNotification.Format(base.Actor.Name + " has clicked on " + base.Target.Name,
                            StyledNotification.NotificationStyle.kGameMessagePositive));
                return true;
            }
            [DoesntRequireTuning]
            private sealed class Definition : ImmediateInteractionDefinition<Sim, Sim, ShowNotification>
            {
                protected override string GetInteractionName(Sim a, Sim target, InteractionObjectPair interaction)
                {
                    return "Show sim names";
                }
                protected override bool Test(Sim a, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback)
                {
                    return true;
                }
            }
        }
    }
}


Let's look at the various parts of this.

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.

Code:
        static DemoClass()
        {
            World.OnWorldLoadFinishedEventHandler += new EventHandler(OnWorldLoadFinishedHandler);
        }


Here, the script adds a new event handler to the OnWorldLoadFinished event. This event is fired when your game finishes loading, and in turn your event handler executes.

Code:
        public static void OnWorldLoadFinishedHandler(object sender, System.EventArgs e)
        {
            foreach (Sim sim in Sims3.Gameplay.Queries.GetObjects<Sim>())
            {
                if (sim != null)
                {
                    AddInteractions(sim);
                }
            }
        }


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.

Code:
        public static void AddInteractions(Sim sim)
        {
            sim.AddInteraction(ShowNotification.Singleton);
        }


And here we add the interaction ShowNotification, which is defined below, to the sim.

Code:
        private sealed class ShowNotification : ImmediateInteraction<Sim, Sim>
        {
            public static readonly InteractionDefinition Singleton = new Definition();
            protected override bool Run()
            {
                StyledNotification.Show(new StyledNotification.Format(base.Actor.Name + " has clicked on " + base.Target.Name,
                            StyledNotification.NotificationStyle.kGameMessagePositive));
                return true;
            }
            [DoesntRequireTuning]
            private sealed class Definition : ImmediateInteractionDefinition<Sim, Sim, ShowNotification>
            {
                protected override string GetInteractionName(Sim actor, Sim target, InteractionObjectPair interaction)
                {
                    return "Show sim names";
                }
                protected override bool Test(Sim actor, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback)
                {
                    return true;
                }
            }
        }


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:

<?xml version="1.0" encoding="utf-8"?>
<base>
<Current_Tuning>
<kInstantiator value="True" />
</Current_Tuning>
</base>

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.

CmarNYC 24th Nov 2012 7:38 PM

Making it better - tweaks and enhancements
 
1 Attachment(s)
Now let's get beyond making a script that's functional, and into making one that's a bit more useful.

Error Checking

Anyone who's done any programming knows errors happen - whether they're bugs in your program (very likely) or errors in data (also very likely) or user input (inevitable). Here's a useful set of error code I stole, er, got from Rick via Twallan (to the best of my memory).

Code:
        public static bool Exception(Exception exception)
        {
            try
            {
                return ((IScriptErrorWindow)AppDomain.CurrentDomain.GetData("ScriptErrorWindow")).DisplayScriptError(null, exception);
            }
            catch
            {
                WriteLog(exception);
                return true;
            }
        }
        public static bool WriteLog(Exception exception)
        {
            try
            {
                new ScriptError(null, exception, 0).WriteMiniScriptError();
                return true;
            }
            catch
            {
                return false;
            }
        }


This consists of two methods:
  • 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.
  • public static bool WriteLog(Exception exception) - Writes error information to a file in your Documents/Sims 3 folder.

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:

Code:
        public static void OnWorldLoadFinishedHandler(object sender, System.EventArgs e)
        {
            try
            {
                foreach (Sim sim in Sims3.Gameplay.Queries.GetObjects<Sim>())
                {
                    if (sim != null)
                    {
                        AddInteractions(sim);
                    }
                }
            }
            catch (Exception exception)
            {
                Exception(exception);
            }
        }


Making interactions conditional

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:

Code:
        public static void AddInteractions(Sim sim)
        {
            if (sim.SimDescription.TeenOrAbove)
            {
                sim.AddInteraction(ShowNotification.Singleton);
            }
        }


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:

Code:
                protected override bool Test(Sim actor, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback)
                {
                    return (actor.SimDescription.Age == target.SimDescription.Age);
                }


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:

Code:
private static EventListener sSimInstantiatedListener = null;


Define the event handler method:

Code:
        protected static ListenerAction OnSimInstantiated(Event e)
        {
            try
            {
                Sim sim = e.TargetObject as Sim;
                if (sim != null)
                {
                    AddInteractions(sim);
                }
            }
            catch (Exception exception)
            {
                Exception(exception);
            }
            return ListenerAction.Keep;
        }


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:

Code:
sSimInstantiatedListener = EventTracker.AddListener(EventTypeId.kSimInstantiated, new ProcessEventDelegate(OnSimInstantiated));


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:

Code:
        public static void AddInteractions(Sim sim)
        {
            if (sim.SimDescription.TeenOrAbove)
            {
                foreach (InteractionObjectPair pair in sim.Interactions)
                {
                    if (pair.InteractionDefinition.GetType() == ShowNotification.Singleton.GetType())
                    {
                        return;
                    }
                }
                sim.AddInteraction(ShowNotification.Singleton);
            }
        }


What this does is iterate through all the interactions defined for the sim, and if it finds ShowNotification already there it returns without adding it.

Handling other events

But what about sims that age up from children to teens during gameplay? I want them to have the interaction added too. So let's add a handler for the AgeTransition event:

Code:
private static EventListener sSimAgedUpListener = null;


in the main class, and

Code:
sSimAgedUpListener = EventTracker.AddListener(EventTypeId.kSimAgeTransition, new ProcessEventDelegate(OnSimInstantiated));


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:

Code:
                public override string[] GetPath(bool bPath)
{
return new string[] { "MyStuff Options..." };
}


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.

Where to go from here

Languages:

If you choose to add multiple language support to your script, you'll have to make some changes in your code along with constructing STBL files for each language. Fortunately there's an excellent tutorial here: http://simswiki.info/wiki.php?title...ocalized_Coding

References:

Here's another very good tutorial on the basics of scripting, this time with objects: http://simswiki.info/wiki.php?title...Depth_Scripting

And the SimsWiki link for General Modding which covers core and script modding: http://simswiki.info/wiki.php?title..._GeneralModding

Download:
Last, I've attached the complete script used in this tutorial, cleaned up a bit to show some of the refinements in comments and to remove my namespace. This should be useful as a template.

Next: Using game libraries and interacting with the user.

CmarNYC 24th Nov 2012 7:38 PM

5 Attachment(s)
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:

Code:
                bool whatToShow = TwoButtonDialog.Show("Choose which to show", "Gender", "Gender Preference");
                if (whatToShow)
                {
                    StyledNotification.Show(new StyledNotification.Format(base.Target.Name + " is: " + base.Target.SimDescription.Gender.ToString(),
                                StyledNotification.NotificationStyle.kGameMessagePositive));
                }
                else
                {
                    string genderPref = base.Target.SimDescription.GenderPreferenceIsFemale() ? "Female" : "Male";
                    StyledNotification.Show(new StyledNotification.Format(base.Target.Name + " prefers: " + genderPref,
                                StyledNotification.NotificationStyle.kGameMessagePositive));
                }


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.

In case you have three options, there's also a ThreeButtonDialog:

Code:
                ThreeButtonDialog.ButtonPressed b = ThreeButtonDialog.Show("Choose which to show", "Married?", "Number of children", "Number of siblings");
                if (b == ThreeButtonDialog.ButtonPressed.FirstButton)
                {
                    StyledNotification.Show(new StyledNotification.Format(base.Target.Name + " married: " + base.Target.SimDescription.IsMarried.ToString(),
                                StyledNotification.NotificationStyle.kGameMessagePositive));
                }
                if (b == ThreeButtonDialog.ButtonPressed.SecondButton)
                {
                    StyledNotification.Show(new StyledNotification.Format(base.Target.Name + " children: " + base.Target.Genealogy.Children.Count.ToString(),
                                StyledNotification.NotificationStyle.kGameMessagePositive));
                }
                if (b == ThreeButtonDialog.ButtonPressed.ThirdButton)
                {
                    StyledNotification.Show(new StyledNotification.Format(base.Target.Name + " siblings: " + base.Target.Genealogy.GetSiblings().Count.ToString(),
                                StyledNotification.NotificationStyle.kGameMessagePositive));
                }


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:

Code:
                string s = StringInputDialog.Show("Text Entry Dialog", "Type something:", "");          //prompt for a string
                string n = StringInputDialog.Show("Text Entry Dialog", "Enter a number:", "", true);    //allow only numbers
                StyledNotification.Show(new StyledNotification.Format("You entered " + s + ", " + n,
                                StyledNotification.NotificationStyle.kGameMessagePositive));


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:

Code:
                List<ObjectListPickerInfo> pick = new List<ObjectListPickerInfo>();
                pick.Add(new ObjectListPickerInfo("Everyday", Sims3.SimIFace.CAS.OutfitCategories.Everyday));
                pick.Add(new ObjectListPickerInfo("Career", Sims3.SimIFace.CAS.OutfitCategories.Career));
                pick.Add(new ObjectListPickerInfo("Swimwear", Sims3.SimIFace.CAS.OutfitCategories.Swimwear));
                pick.Add(new ObjectListPickerInfo("Formal", Sims3.SimIFace.CAS.OutfitCategories.Formalwear));
                object obj = ObjectListPickerDialog.Show(pick);
                Sims3.SimIFace.CAS.OutfitCategories cat = (Sims3.SimIFace.CAS.OutfitCategories) obj;
                base.Target.SwitchToOutfitWithoutSpin(cat);


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:

Code:
                Dictionary<string, object> dict = new Dictionary<string,object>();
                dict.Add("Everyday", Sims3.SimIFace.CAS.OutfitCategories.Everyday);
                dict.Add("Career", Sims3.SimIFace.CAS.OutfitCategories.Career);
                dict.Add("Swimwear", Sims3.SimIFace.CAS.OutfitCategories.Swimwear);
                dict.Add("Formal", Sims3.SimIFace.CAS.OutfitCategories.Formalwear);
                object obj2 = ComboSelectionDialog.Show("Pick an outfit category", dict, null);
                Sims3.SimIFace.CAS.OutfitCategories cat2 = (Sims3.SimIFace.CAS.OutfitCategories)obj2;
                base.Target.SwitchToOutfitWithoutSpin(cat2);


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

If you have Visual C# Express 2010 or later, you can use Peter Jones' utility here: http://www.den.simlogical.com/denfo...hp?topic=1689.0

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!

JT` 25th Nov 2012 9:14 AM

You nailed the reference in the walkthrough and changed it to ShowNotification, but missed the same in the main block of code:

private sealed class Definition : ImmediateInteractionDefinition<Sim, Sim, GoToXCAS>

=)

CmarNYC 25th Nov 2012 2:28 PM

Corrected - thanks!

Dramatic-Gamer 4th Jan 2013 9:53 AM

Thank you for this tutorial .

But this is not the kind of interaction that i wanted

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

CmarNYC 4th Jan 2013 3:16 PM

Quote: Originally posted by bella3lek4
Thank you for this tutorial .

But this is not the kind of interaction that i wanted

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

I've never done that and am not planning on doing a tutorial for it.

Dramatic-Gamer 6th Jan 2013 6:18 PM

Thank you ,

I will start learning C# after i finish my exams .

i hope i will finally come up with something

Dramatic-Gamer 7th Jan 2013 6:31 PM

This Tutorial gave me Headache !

The whole coding thing gave me headache !!!

I am so full of it .
its not working ,

i quit !!!


Some creator should make a tool to simply add an interaction , What it does , what it effects , what animations to play or to import , & so on .

i can't handle this

lenglel 7th Jan 2013 7:12 PM

I had that headache when I first started. It was my brain trying to comprehend it's own stupidity. Modding only looks easy because the modders are good at it.

JT` 8th Jan 2013 5:37 PM

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).

Don't be discouraged! Everyone has to start somewhere.

CmarNYC 14th Jan 2013 2:14 PM

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.

Sof_m9 22nd Jan 2013 4:22 PM

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.

CmarNYC 27th Jan 2013 9:41 PM

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.

Klinn2 15th Feb 2013 9:43 PM

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!

CmarNYC 16th Feb 2013 1:05 AM

Thank you! I had fun learning C# - I hope you do too.

seb.klein.89 26th Feb 2013 2:26 PM

Problem
 
1 Attachment(s)
hi,

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?

cheers

CmarNYC 26th Feb 2013 4:03 PM

In VS Express, open your project and expand the project Properties, then open AssemblyInfo.cs. The contents should look something like this: (The AssemblyProduct and AssemblyTitle may be different.)

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Sims3.SimIFace;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DemoClass")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("DemoClass")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: Tunable]

// 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.

seb.klein.89 26th Feb 2013 4:39 PM

Problem solved
 
Quote: Originally posted by CmarNYC
In VS Express, open your project and expand the project Properties, then open AssemblyInfo.cs. The contents should look something like this: (The AssemblyProduct and AssemblyTitle may be different.)

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Sims3.SimIFace;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DemoClass")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("DemoClass")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: Tunable]

// 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.


Yeah thats it. Adding "[assembly: Tunable]" and everything is fine thx

Sof_m9 3rd Mar 2013 8:35 PM

Quote: Originally posted by CmarNYC
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.

CmarNYC 4th Mar 2013 2:46 AM

Quote: Originally posted by Sof_m9
You couldn't possibly test this out? Please? All I can do is custom animations, I'm not understanding at all how to add interactions to pie menus.


Thing is, this is likely to be a considerable project, and one I have no interest in myself.
When I get some spare time and if it turns out to be easy, I'll let you know.

Sof_m9 4th Mar 2013 5:31 PM

Quote: Originally posted by CmarNYC
Thing is, this is likely to be a considerable project, and one I have no interest in myself.
When I get some spare time and if it turns out to be easy, I'll let you know.


I understand. Thank you.

forgottenmistake 12th Apr 2013 4:04 AM

Durp
 
Argg! Messed up somwhere... Back to square one...

Seabody 9th Jun 2013 7:07 AM

Hi Cmar. The method Definition() in this part of the code:

Code:
public static readonly InteractionDefinition Singleton = new Definition();


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?

CmarNYC 12th Jun 2013 1:11 AM

Quote: Originally posted by Seabody
Hi Cmar. The method Definition() in this part of the code:

Code:
public static readonly InteractionDefinition Singleton = new Definition();


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?

Sof_m9 14th Jun 2013 6:07 PM

Quote: Originally posted by CmarNYC
Can you upload or post your complete code so I can take a look?


Hi CmarNYC, just wondering if you have spare time anytime soon to test out carrying kids interaction?
Thanks.

CmarNYC 16th Jun 2013 4:51 AM

Quote: Originally posted by Sof_m9
Hi CmarNYC, just wondering if you have spare time anytime soon to test out carrying kids interaction?
Thanks.


Yes - truthfully I've been distracted by personal problems the last few months and doing very little modding work, but this could be a good project to get back into things. Thanks for reminding me!

Sof_m9 16th Jun 2013 5:17 PM

Quote: Originally posted by CmarNYC
Yes - truthfully I've been distracted by personal problems the last few months and doing very little modding work, but this could be a good project to get back into things. Thanks for reminding me!


Really?? Thank you!! If you need any help please let me know and I'll try to help in any way I can.
Sorry about your personal problems.
xx

Kimsie 17th Jun 2013 3:04 PM

Thank you so much for this!

CmarNYC 18th Jun 2013 11:08 PM

Working on it now. Question: There's already an interaction for a parent to pick up and carry a toddler. What is it that's different about the firefighter carry that you want?

Sof_m9 19th Jun 2013 12:46 AM

Quote: Originally posted by CmarNYC
Working on it now. Question: There's already an interaction for a parent to pick up and carry a toddler. What is it that's different about the firefighter carry that you want?


Yay, great!
Toddlers can be carried, of course, but not kids. I've always wanted kids to be carried, too. I also need that interaction for a Sims movie.
I really hope you are able to add that interaction to the Sims pie menu. Thanks again for working on this!

CmarNYC 19th Jun 2013 3:40 PM

Quote: Originally posted by Sof_m9
Yay, great!
Toddlers can be carried, of course, but not kids. I've always wanted kids to be carried, too. I also need that interaction for a Sims movie.
I really hope you are able to add that interaction to the Sims pie menu. Thanks again for working on this!


The interaction seems to apply to toddlers, but I'll see what happens with children.

Sof_m9 20th Jun 2013 1:06 AM

Quote: Originally posted by CmarNYC
The interaction seems to apply to toddlers, but I'll see what happens with children.


I saw a video of a firefighter carrying a kid, that's why I asked if someone could add that interaction to every Sims pie menu.

egnite987 6th Jul 2013 8:39 AM

Hi I would like to create a mod but not sure where to make a thread for it. I want it to be a bank loan type of mod where I click on the city hall and an option comes up to loan money and then you type the amount of money you would like to borrow. The max would be 10,000 and the min would be about 300. The amount should be paid in full with no interest in around 1 sim week. You can also be able to pay off the loan separately like 100 simoleans everyday or something as you will be able to type the amount of money you would like to pay. But you cannot exceed 1 week, if you do or decide to ignore the loan a repo man will come and take the amount worth of stuff (like when you don't pay the bills). You can only be able to loan one time unless you pay off the full amount you will then be able to loan again. If the repo man does come then you will not be able to ask for a loan in around another sim week. When you pay it all off you can get like a moodlet called "Fulfilled" with +25 or something to the mood.

CmarNYC 6th Jul 2013 9:08 AM

Quote: Originally posted by egnite987
Hi I would like to create a mod but not sure where to make a thread for it. I want it to be a bank loan type of mod where I click on the city hall and an option comes up to loan money and then you type the amount of money you would like to borrow. The max would be 10,000 and the min would be about 300. The amount should be paid in full with no interest in around 1 sim week. You can also be able to pay off the loan separately like 100 simoleans everyday or something as you will be able to type the amount of money you would like to pay. But you cannot exceed 1 week, if you do or decide to ignore the loan a repo man will come and take the amount worth of stuff (like when you don't pay the bills). You can only be able to loan one time unless you pay off the full amount you will then be able to loan again. If the repo man does come then you will not be able to ask for a loan in around another sim week. When you pay it all off you can get like a moodlet called "Fulfilled" with +25 or something to the mood.


You should post questions on how to make this in the Create / Sims 3 / Modding Discussion forum.

sydsyrious 10th Dec 2013 6:50 AM

Hello CMar. I know this tutorial hasn't seen much action but wanted to let you know I really enjoyed this one and keep going back to it as a reference. I'm not sure if this is the proper place to ask about this but I wanted to ask if you had an example of a nested pie. Mine is very simple that I'm attempting, but unfortunately I keep getting stuck as to how to structure. I have 3 simple types, with small lists attached. I want to be able to have a Sim pick a type and then show the list the type is attached to for them to select an action. I hope that was clear and if you happen to see this and can help, would really appreciate it. Thanks again for the great tutorial. : )

CmarNYC 10th Dec 2013 5:05 PM

1 Attachment(s)
If what you're talking about is a pie menu that has the user make one choice and then presents a second (third, etc.) list of choices based on that - I've attached the class for my outfit changing script as an example. I'm afraid it's not simple, though. Twallan's Master Controller code would be another example. It's just a matter of writing code in the pie menu option Run to present options and go from there with if statements.

Or if you mean when you click a pie menu option and get a second (or third, etc.) level of pie menu options, that is very simple and uses the Path method which is explained in the tutorial under "Defining paths and submenus".

The differences are that you have to use code to use things like pick lists. My opinion is that pie menu levels/submenues are better for a small number of choices, but pick lists are necessary for a large number of choices.

Did I answer your question?

sydsyrious 10th Dec 2013 5:23 PM

Quote: Originally posted by CmarNYC
If what you're talking about is a pie menu that has the user make one choice and then presents a second (third, etc.) list of choices based on that - I've attached the class for my outfit changing script as an example. I'm afraid it's not simple, though. Twallan's Master Controller code would be another example. It's just a matter of writing code in the pie menu option Run to present options and go from there with if statements.

Or if you mean when you click a pie menu option and get a second (or third, etc.) level of pie menu options, that is very simple and uses the Path method which is explained in the tutorial under "Defining paths and submenus".

The differences are that you have to use code to use things like pick lists. My opinion is that pie menu levels/submenues are better for a small number of choices, but pick lists are necessary for a large number of choices.

Did I answer your question?


Oh wow...you already replied! This is perfect and gave me that little "push" to get back on the direction I need to go. Sometimes I seem to get lost in it all.....and hung up on the tiniest little details. It's been so much fun learning and the comment you made in the tutorial about how it took you several months to get comfortable even after having experience in programming made me feel so much better as it will probably take me years not coming from that background and that I shouldn't expect to grasp it all at once. Thank you so very, very much Cmar!

CmarNYC 10th Dec 2013 11:08 PM

Always happy to help, and thanks very much for the feedback! Yes, programming is neither easy nor fast, unless you're a genius. I'm still learning new stuff about C#.

LadySmoks 14th Mar 2014 7:48 PM

Well Cmar, your tutorial makes it look sooooooooooooo easy. And after hours (HOURS) of flubbing my way thru all the step by step instructions you provided, I finally came to the realization that it was time for a vodka Martini with 3 olives, kick my husband, take a relaxing bubble bath, finish off the bottle of vodka without vermouth or olives and forget the whole thing and leave this stuff to people like you!

CmarNYC 14th Mar 2014 8:25 PM

LOL! It's a pretty steep learning curve, yes, at least if you don't have much programming experience. The more complex scripts I see some people do still leave me going "Bwuh??" and wanting to join you in those martinis.

seronis 17th May 2014 10:53 AM

Just finally thought id try modding Sims3 (I mod other games I play but none in C#) and this helped me immeasurably. Got it working on 2nd try, and the first failure I -think- was related to me messing up how I had vstudio link in mscorelib and nothing to do with this tutorial.

Emilie217 21st Dec 2014 6:21 AM

Thanks a lot Cmar! That's exactly the kind of tutorial I was looking for! Sometimes going through someone else's code to pinpoint the one thing you want is a pain XD You saved me a lot of time If I had known TS3 used C#, I would have created mods years ago. I feel late to the party XD

djbmd 9th Jul 2015 1:48 AM

Questions
 
First of all, you have done a lot of great mods. Thanks for all your work.

I am trying to break into modding, so thanks also for sharing your knowledge in tutorials. One problem I am having with this one is that, in VS2010, I get the error on the "foreach" statement: "Gameplay" (in Sims3.Gameplay.Quaries) does not exist. I have all the "using" statements you list.

On a more global scale, one thing the tutorials don't get into is where to find data such as data types or object information. The type "Sim" is obvious, but what if I want to modify a plant or create a new object? Where would I find a list of names and associated numbers of, say, a type of object or all produce, or all the drink mixes? Is there list of which files to look in for which data?

Yes, I am still stuck in Sims3. TS4 is interesting but still a little sparse. Will wait for more expansion packs to switch over. I'm still enjoying 3;

Thanks for your help.

HKnowles 23rd Feb 2023 11:43 PM

I'm sorry for my stupidity, but could you please explain "Defining paths and submenus" in more detail? Because I really don't know where to add the code you showed me.

Vensey 2nd May 2024 10:52 AM

Update: So I'm not sure how or why, but copying and pasting my code into a brand new dll and completely remaking the s3pe package seems to have let me load it into the game. Now my issue is that the mod shows in the mod scripts on the main page, but doesn't show up in the pie menu in game XP Guess I still have more work to do.

Hello everyone,

I am new to script modding and, aside from giving me massive gratitude for modders, I seem to be struggling with it.

I'm following all of the tutorials I can possibly find about script modding, including following Pudding Face's video tutorial step-by-step.

The goal: to create a mod where sims can talk to themselves without having the insane trait.

I'm using SharpDeveloper, and when I build my code, it doesn't throw any errors when I build/compile it. I've created my XML file and made sure both the XML and DLL are in s3pe. Nothing was throwing errors at me, so I have reason to believe that the code might be able to work. (Please let me know how to do the little code box markdown in my comments and I can post the code as needed for review).

Essentially, what's happening is that even after clearing my caches from my Sims 3 folder and ONLY having my test mod installed (no cc or other mods), my game simply gets stuck on the title screen and my computer fans start whirring like crazy. I know that my computer can handle the mods and I know that other mods and cc work because they were working literally before I started my script modding.

I'm not sure why it's behaving this way, so any help would be greatly appreciated. I don't know anything about coding or script modding, but I am definitely open to learning!

Thank you!

LadySmoks 2nd May 2024 10:18 PM

Quote: Originally posted by Vensey
Update: So I'm not sure how or why, but copying and pasting my code into a brand new dll and completely remaking the s3pe package seems to have let me load it into the game. Now my issue is that the mod shows in the mod scripts on the main page, but doesn't show up in the pie menu in game XP Guess I still have more work to do.


Since Cmar's passing, it may be best to open a new help thread in Modding Discussions, or Miscellaneous sections.

Vensey 3rd May 2024 1:44 PM

Quote: Originally posted by LadySmoks
Since Cmar's passing, it may be best to open a new help thread in Modding Discussions, or Miscellaneous sections.


Oh my gosh, I'm so sorry to hear that. My apologies, and condolences. I wasn't aware, but I really love a lot of Cmar's mods. I'm sorry to hear the news. I will look at opening a new help thread elsewhere. Thank you for letting me know.


All times are GMT +1. The time now is 3:37 PM.

Powered by: vBulletin Version 3.0.14 · Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.