- Site Map >
- Modding and Creation >
- Sims 3 Creation >
- Modding Discussion >
- The Code Snippet Jar!
- Site Map >
- Modding and Creation >
- Sims 3 Creation >
- Modding Discussion >
- The Code Snippet Jar!
Posts: 3,865
Thanks: 8689 in 68 Posts
Well, this thread will have covered with simple snippets as to what and when to use something, so both advanced, as well as beginners, can enjoy from it! Or even if you have any questions if EA's code simply allows something or you need an extra push into that coding error!
I've got some good ones to include!
Make sure to list yours in such a way as shown below. Just so that everything is more organised and easier to find. If you've got an alternative way or even an easier way of doing a particular function, then it's totally fine to share this too, but preferably label these as "Alternative:" or "My way:" Or something like that
Make sure however, not to copy paste your entire script or class. A simple function is fine though!
What this thread isn't for:
This is not a thread about how to fix your code or errors. If there's any errors you encounter and you need help, make sure to create a thread to ask that particular question. Your reply will get deleted/moved as a new thread. Of course, exceptions are for if any snippets happen to have a spelling mistake and it needs to be pointed out
This thread is also not about asking questions and your reply will get deleted if so.
C# can be a complex language, and it's of course totally fine to ask questions about it! But, having 20 errors in your code is actually quite easily fixable by just googling or checking your brackets So make sure that you at least have a basic understanding of C#.
But... how do I learn C#? It's super complicated!
First off, C# is indeed the scripting language that the sims has been written, and we totally recommend checking out the scripting tutorials first:
Script modding Wiki page
It also really depends whether you've done coding before! Like, javascript or even python. if you did and knew the basics in those languages you'll get it in no time!
Now, beginners do struggle a lot usually to get somewhere and it can get quite frustrating! Now, to really get a grasp of a leaning language is obviously patience But here's a list of tips:
- Don't give up! First thing you probably feel after getting 10000 errors is throwing your PC through the room, but really, google them all. Usually, it's either a bracket that isn't quite in the right place or the whole confusion of a class being static/non-static, void. etc.
- Practise! This can be a game or non-game projects but do go with something easy and if you like, expand it from there!
- Understand what you're writing! This means, you can copy/paste someone else's code (or even EA's), but take it from me, you need to understand it too! if you don't, then you'll loose track of the logistics behind your code which is... not good.
- Try typing it out with pseudocode! This means literally, with words, typing it out. Like what I'm doing right now It sounds pointless but as a beginner, it's so amazing to use!
Table Of Contents
To have a clear idea of what's been posted:
- Zoe22: Set game speed
- Zoe22: Add Alarm To Object
- Zoe22: Remove Alarm From Object
- Zoe22: Check If Sim Is In Active Household
- Zoe22: Modify Household Funds
- Zoe22: Add Money To Household Bills
- Zoe22: Destroy object In Game
- Battery: Get Translation Key directly
- Battery: Run a Task/Action without blocking the Main Thread
- Battery: Enable Extension Methods In SharpDevelop
- Lyralei: Standard Statemachine Setup.
- Lyralei: Make Inventory Item Stackable
- Lyralei: Give Game Object It's Own Inventory
- Lyralei: Enable Live Mode Dragging in Code
- Lyralei: Stopwatch Alternative - Part 1
- GameFreak130: Stopwatch Alternative - Part 2
- Zoe22: Add Greyed Out Message On Interaction
- GameFreak130: Workaround For Overriding Priority of Interaction
- Lyralei/GameFreak130: Fire as singular Task (OneShotFunctionTask)
- GameFreak130: Ferry Method For Saving Data across Travelling
- Zoe22: Replace EA Interaction
- Zoe22: Count Number of Object On lot
- Zoe22: Get All (stacked) items of a specific type In Sim's Inventory
- Zoe22: Route Sim To Object's General Area
- Zoe22: Create An Object Through Code (Custom and EA object)
- Lyralei: Giving Your Object a Way to (re)name it in-game
- Lyralei: Troubleshoot your Jazz Script
- Lyralei: Firing an Animation Without a Jazz statemachine (Solo Animation)
- Lyralei: How To Fire a Notification + Types to use
- SimStateDude: Query Objects Of a Certain Type
- SimStateDude: Get Interaction Type
- SimStateDude: Get Object By Unique ID
- SimStateDude: Find An 'Actors'/Sims Traits
- SimStateDude: Get Household Id of a sim
- SimStateDude: Playing A Default EA Sound Effect
- SimStateDude: Removing An Interaction (By Type)
- SimStateDude: Persistable Data - Saving Your Stuff With EAs Code
- SimStateDude: Nested Pie Menu Options
- SimStateDude: Changing An 'InWorld' Objects Price
- SimStateDude: Changing An Objects Color (not To be Confused with the CASt)
- SimStateDude: Adding Moodlets to A Sim/Actor
- SimStateDude: Find A Household By ID
- SimStateDude: Visual Effects!
- SimStateDude: Move A Sim To An Object Radius and Check If In Use
- SimStateDude: Numbers In A String Dialogue
- echoweaver: Add an Inventory Interaction
- echoweaver: Check whether an inventory interaction has already been added to an object
- echoweaver: Showing and setting up the Item selecting dialogue (ObjectListPickerDialog)
- GameFreak130: LoadFromMainMenuOnly (alternative from the Ferry approach)
- Lyralei: Parse Error into an XML file (Like Nraas's script Error XML files)
- Lyralei: Changing the amount of an individual need
- Lyralei: Checking the sim's mood
- Lyralei: Change and set the maximum value of a mood
- Lyralei: Create your own notification (with a button!)
- Gamefreak130: Alarm Types Explained
- KittyTheSnowcat: Change Quality on Ingredient
- KittyTheSnowcat: Setting Preset of Object In code
- FloTheory: Sim Talking With sims around them, while Preforming Interaction
- echoweaver: Change VFX colours through code
- echoweaver/Lyralei/Gamefreak130: Order world events are triggered
- MonocoDoll: Freeze/unfreeze sims motive
- Lyralei: Get GameObject once placed down
- Lyralei: How to set up managers/singleton classes the TS3 way.
Posts: 562
Thanks: 3651 in 11 Posts
Gameflow.SetGameSpeed(SimIFace.Gameflow.GameSpeed.Pause, Gameflow.SetGameSpeedContext.GameStates);
All speeds are: Pause, Normal, Double, Triple, Skip
Adding an alarm to an object:
AlarmHandle handle = object.AddAlarmRepeating(1f, TimeUnit.Hours, new AlarmTimerCallback(WhenAlarmEnds()), "AlarmName", AlarmType.AlwaysPersisted);
Types of alarms: AddAlarm, AddAlarmDay, AddAlarmRepeating
Remove an alarm on an object:
object.RemoveAlarm(handle);
Check if sim is in active household:
if (sim.IsInActiveHousehold) { }
Modify sim's household funds:
sim.ModifyFunds( amount to add to funds, negative value for taking away money));
Add to sim's household bills:
sim.Household.UnpaidBills += value
Destroy an object in the game:
object.Destroy()
Posts: 433
Thanks: 800 in 6 Posts
InteractionInstance interactionInstance = GameInteraction.Singleton.CreateInstance(Target, Actor, new InteractionPriority(InteractionPriorityLevel.Autonomous), true, false); StyledNotification.Show( new StyledNotification.Format(InteractionDefinitionUtilities.GetInteractionLocalizationKey(typeof(TargetClass),interactionInstance.InteractionObjectPair),StyledNotification.NotificationStyle.kGameMessagePositive));
With:
Target = The target of the Interaction
Actor = The Actor of the Interaction
GameInteraction = The Interaction whichs Key you need to retrieve
TargetClass = The Class of the interaction target e.g. Sim
This will show an Notification with the TranslationKey
If you need to Run an Action so that it doesnt block the main thread you can use this
public class Task_GenericAction : Task { Action mAction = null; Action[] mActions = null; public static void Start(Action PerformAction) { Simulator.AddObject (new Task_GenericAction (PerformAction)); } public static void StartArray(Action[] PerformActions) { Simulator.AddObject (new Task_GenericAction (PerformActions)); } public Task_GenericAction (Action PerformAction) { mAction = PerformAction; } public Task_GenericAction (Action[] PerformActions) { mActions = PerformActions; } public override void Simulate() { try { if (mAction != null) { mAction(); } if (mActions != null && mActions.Length > 0) { foreach(Action current in this.mActions) { current(); } } } catch(Exception e) { } finally { Sims3.SimIFace.Simulator.DestroyObject(base.ObjectId); } } }
and call it like that
Task_GenericAction.Start(YourActionHere)
thats all im willing to share for now (thats actually more than i originally wanted to share), since i still need to sell my Script Utility Mod where these snippets are from, to some unsuspecting Modders.. and i did post a whole class. lets see if Lyralei notices
Posts: 433
Thanks: 800 in 6 Posts
namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class ExtensionAttribute : Attribute { } }
Posts: 3,865
Thanks: 8689 in 68 Posts
base.StandardEntry(); base.EnterStateMachine("JAZZ_MACHINE_NAME_HERE", "Enter", "x"); // Enter could be anything, but it's common practise to start with enter base.SetActor("OBJECT OR ACTOR NAME HERE", base.Target); // This can be another actor, "y" or "Oven" or "glass_prop". base.EnterState("x", "Enter"); base.AnimateSim("Exit"); base.StandardExit();
Posts: 3,865
Thanks: 8689 in 68 Posts
public override bool StacksWith(IGameObject other) { GameObject gameObject = other as GameObject ; if(gameObject != null) { return true; } return false; }
Making the object an inventory-enabled (aka, being able to be stored in inventories)
public override void OnStartup() { base.AddComponent(new object[1] { new List(new Type[3] { typeof(Sim), typeof(SharedFamilyInventory), typeof(SewingTable) }) }); base.AddInteraction(PutInInventory.Singleton); base.OnCreation(); }
Available types you can use for this:
- Sim
- SharedFamilyInventory
- Your own Custom object that has an inventory (Make sure this is the first class of your script, so not the interaction classes)
- Tomb chests, EA's inventory objects (Even the InventionBench if you like! )
public bool IsDraggable = true; public override bool HandToolAllowUserPickup() { if (!IsDraggable) { return false; } return base.HandToolAllowUserPickup(); } // To apply it to your object: GameObject.IsDraggable = true;
Posts: 3,865
Thanks: 8689 in 68 Posts
DateTime start = DateTime.Now; // ADD YOUR CODE BETWEEN THESE LINES, THIS CAN BE A TYPE OF LOOP, METHOD, SOMETHING BEING CALLED, ETC. DateTime end = DateTime.Now; // Here we just print it for debugging purposes. This can be done in a dialogue or notification SimpleMessageDialogue.show("Title of the dialogue " + (end - start).ToString());
Usually, you'd use the StopWatch class for it. Unfortunately, EA took that out of their own System.Diagnostics version :/. So this is just a simple workaround! If you want to check multiple, then just do exactly the same repeatedly.
Posts: 438
Thanks: 5404 in 22 Posts
A snippet that makes it easier to figure out how long it took to load a function, loop, method, or anything alike. (Credits to Tashiketh as well).
Code:
DateTime start = DateTime.Now; // ADD YOUR CODE BETWEEN THESE LINES, THIS CAN BE A TYPE OF LOOP, METHOD, SOMETHING BEING CALLED, ETC. DateTime end = DateTime.Now; // Here we just print it for debugging purposes. This can be done in a dialogue or notification SimpleMessageDialogue.show("Title of the dialogue " + (end - start).ToString()); Usually, you'd use the StopWatch class for it. Unfortunately, EA took that out of their own System.Diagnostics version :/. So this is just a simple workaround! If you want to check multiple, then just do exactly the same repeatedly. |
StopWatch was taken out of System.Diagnostics because EA implemented their own StopWatch class in SimIFace.
Basic functionality is pretty much the same as the System StopWatch. Here's an example:
using Sims3.SimIFace; using Sims3.UI; internal void TimedProcedure() { StopWatch timer = StopWatch.Create(StopWatch.TickStyles.Microseconds).Start(); // Things // TODO More things // Optional: Maybe some more things here? timer.Stop(); SimpleMessageDialogue.Show("TimedProcedure() took " + timer.GetElapsedTimeFloat().ToString() + " microseconds to execute."); timer.Dispose(); }
If you enjoy the mods I put out, consider supporting me on patreon: www.patreon.com/Gamefreak130
Posts: 562
Thanks: 3651 in 11 Posts
public override bool Test(Sim a, SomeGameObject target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { if(canDoThisNow == true) { return true; } else { string message= "i am too tired"; greyedOutTooltipCallback = CreateTooltipCallback(message); } return false; }
Posts: 438
Thanks: 5404 in 22 Posts
All interactions in the game have a priority level assigned to them. When the game adds an interaction to a Sim's queue, all lower-priority interactions already in the queue are automatically canceled. Most interactions share the same default priority, but certain interactions (mainly reactions to burglars, mummies, simbots, etc.) are labeled by the game as high priority, meaning they will rather annoyingly cancel all user-directed interactions in the queue when they are assigned. If you want to work around this for a custom interaction (or make an interaction with the same functionality), you'll need to make it high priority by adding the following to your interaction's class:
using Sims3.Gameplay.Interactions; public override void Init(ref InteractionInstanceParameters parameters) { parameters.Priority = new InteractionPriority(InteractionPriorityLevel.High); base.Init(ref parameters); }
There are priority levels higher than high, but they shouldn't be used unless you know what you're doing.
As an aside, if at any point in an interaction's Run() method you want it to become uncancellable (i.e. the user can't click to remove it from the queue), you can use the following property of InteractionInstance:
CancellableByPlayer = false;
If you enjoy the mods I put out, consider supporting me on patreon: www.patreon.com/Gamefreak130
Posts: 3,865
Thanks: 8689 in 68 Posts
public override bool Run() { // when adding the function, never add the () to the end. This is because it expects a delegate Simulator.AddObject(new OneShotFunctionTask(new Function(yourFunctionhere))); } public void yourFunctionhere() { // code you want to fire here. }
What it does, is it fires the function on a different thread whenever it can, meaning that there's less pressure onto the game for running said function. This function is an asynchronous function, as it waits till the game is ready to fire it on a different thread. This is defined with using OneShotFunctionTask. Function, of course, just defines which function it should look at.
Simulator.AddObject(), just adds this function for the simulator's 'todo list' so to speak. (The simulator is the system that also has sims do stuff automatically, etc)
There is a way to parse any needed parameters for the function, but that I've never gotten to work beside a whole workaround. So I'd recommend keeping your function within the interaction bit you're using this in. So under the Run() function if you will
Posts: 438
Thanks: 5404 in 22 Posts
PersistableStatic fields are very useful for pure script mods, since they can effectively serve as global variables whose values can be tied to a save game and automatically saved/loaded by the game. However, multiple worlds in a single save will maintain separate copies of these fields, and their current value will automatically become the default starting values in newly-exposed worlds. When you travel to China, attend university, start a new game after quitting to main menu, etc., the value of PersistableStatics at the time of world loading will be carried over, but any further changes in one world will not affect the values in another. This is useful in some situations (e.g. keeping track of the number of Sims in a world), but not in others (e.g. keeping track of how many sim-days have been simulated save-wide).
To work around this, I created a generic static class (an obscure feature of C#, but a helpful one in this case) that can "ferry" any PersistableStatic data declared in a class or struct across worlds when traveling, effectively allowing an entire save to share a single copy.
using Sims3.SimIFace; using System; using System.Collections.Generic; using System.Reflection; /// <summary>Transfers (or "Ferries") values of PersistableStatic type members ("Cargo") across worlds when traveling.</summary> /// <remarks><para>Using the Ferry, one copy of a type's PersistableStatic data can be shared across multiple worlds in a save, /// as opposed to each world creating and maintaining its own separate copy.</para> /// <para>Client code is responsible for setting any default values for Cargo after it has been loaded, /// should such values be necessary for new games or newly-exposed saves.</para> /// <para>Types derived from <typeparamref name="T">T</typeparamref> and types from which <typeparamref name="T">T</typeparamref> is derived /// will not have their declared Cargo saved unless a separate Ferry is called for them as well.</para></remarks> /// <typeparam name="T">The type containing PersistableStatic data to be ferried</typeparam> /// <exception cref="NotSupportedException"><typeparamref name="T">T</typeparamref> does not contain PersistableStatic members</exception> public static class Ferry<T> { private static readonly Dictionary<FieldInfo, object> mCargo; static Ferry() { FieldInfo[] fields = FindPersistableStatics(); if (fields.Length == 0) { throw new NotSupportedException($"There are no PersistableStatic fields declared in {typeof(T)}."); } mCargo = new Dictionary<FieldInfo, object>(fields.Length); foreach (FieldInfo current in fields) { mCargo[current] = null; } } private static FieldInfo[] FindPersistableStatics() { MemberInfo[] fieldMembers = typeof(T).FindMembers(MemberTypes.Field, BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic, (info, criteria) => info.GetCustomAttributes(typeof(PersistableStaticAttribute), false).Length > 0, null); return Array.ConvertAll(fieldMembers, (x) => (FieldInfo)x); } // Transfer loaded Cargo to respective members of T public static void UnloadCargo() { if (GameStates.IsTravelling) { foreach (FieldInfo current in new List<FieldInfo>(mCargo.Keys)) { current.SetValue(null, mCargo[current]); mCargo[current] = null; } } } // Load all Cargo onto T's Ferry for transfer public static void LoadCargo() { if (GameStates.IsTravelling) { foreach (FieldInfo current in new List<FieldInfo>(mCargo.Keys)) { mCargo[current] = current.GetValue(null); } } } }
using Sims3.SimIFace; using System; // In this example, UselessSettings's Cargo is loaded/unloaded to maintain current settings across an entire save // However, no default values for the Cargo are ever set after app startup // So any new games or newly-exposed saves after quitting to main menu will copy the settings from the previously-loaded world public static class Main { [Tunable] private static bool kInstantiator; static Main() { World.OnWorldLoadFinishedEventHandler += OnWorldLoadFinished; World.OnWorldQuitEventHandler += OnWorldQuit; } private static void OnWorldLoadFinished(object sender, EventArgs e) => Ferry<UselessSettings>.UnloadCargo(); private static void OnWorldQuit(object sender, EventArgs e) => Ferry<UselessSettings>.LoadCargo(); } public struct UselessSettings { [PersistableStatic] public static int sInt = 5; [PersistableStatic] public static float sFloat = 7.2f; }
using Sims3.Gameplay.Utilities; using Sims3.SimIFace; using Sims3.UI; using System; public static class Main { [Tunable] private static bool kInstantiator; static Main() { World.OnWorldLoadFinishedEventHandler += OnWorldLoadFinished; World.OnWorldQuitEventHandler += OnWorldQuit; } private static void OnWorldLoadFinished(object sender, EventArgs e) { UselessData.Unload(); UselessData.sTimesTraveledInSave++; UselessData.seekretString += 'A'; // Display the current value of sTimesTraveledInSave and seekretString upon entering live mode after loading/traveling AlarmManager.Global.AddAlarm(1f, TimeUnit.Minutes, delegate () { StyledNotification.Show(new StyledNotification.Format($"{UselessData.sTimesTraveledInSave}\n{UselessData.seekretString}", StyledNotification.NotificationStyle.kSystemMessage)); }, "TEST", AlarmType.NeverPersisted, null); } private static void OnWorldQuit(object sender, EventArgs e) { UselessData.Load(); // UselessData is cleared every time a world is unloaded, // So any new games or newly-exposed saves after quitting to main menu will have default values (rather than copying the values from the previously-loaded world) // But if we're traveling, our data is safe and sound in the Ferry! UselessData.sTimesTraveledInSave = 0; UselessData.seekretString = ""; } } // Static classes cannot be generic type parameters // So this is just a sealed class instead public sealed class UselessData { [PersistableStatic] public static int sTimesTraveledInSave = 0; [PersistableStatic] public static string seekretString = ""; public static void Unload() => Ferry<UselessData>.UnloadCargo(); public static void Load() => Ferry<UselessData>.LoadCargo(); }
using Sims3.SimIFace using System public static class Main { [Tunable] private static bool kInstantiator; static Main() { World.OnWorldLoadFinishedEventHandler += OnWorldLoadFinished; World.OnWorldQuitEventHandler += OnWorldQuit; } private static void OnWorldLoadFinished(object sender, EventArgs e) { Ferry<Animal>.UnloadCargo(); Ferry<Dog>.UnloadCargo(); } private static void OnWorldQuit(object sender, EventArgs e) { Ferry<Animal>.LoadCargo(); Ferry<Dog>.LoadCargo(); } } public class Animal { // This field is ONLY captured by Ferry<Animal> // It is NOT considered part of Dog's declared Cargo [PersistableStatic] private static int sAnimalCount; } public class Dog : Animal { // This field is ONLY captured by Ferry<Dog> // It is NOT considered part of Animal's declared Cargo [PersistableStatic] private static int sNumMailmenChased; }
If you enjoy the mods I put out, consider supporting me on patreon: www.patreon.com/Gamefreak130
Posts: 562
Thanks: 3651 in 11 Posts
private static void OnPreload() { WashHands.Singleton = new CustomWashHands.Definition(); }
Count number of objects on a lot:
uint numberOfObject = someLot.CountObjects<Sink>();
Get List of certain type of object in an Inventory:
List<IGameObject> objects = sim.Inventory.FindAllOfType(typeof(SomeObject));
Route to an object's general area:
Route route = Actor.CreateRoute(); route.SetOption(Route.RouteOption.DoLineOfSightCheckUserOverride, value: true); float num = 1f; float num2 = 2f; IHasRouteRadius hasRouteRadius = Target as IHasRouteRadius; if (hasRouteRadius != null) { float num3 = 3f; num = hasRouteRadius.CarryRouteToObjectRadius; num2 = num * num3; if (num2 - num > 2f) { num2 = num + 2f; } } route.PlanToPointRadialRange(Target.Position, num, num2, RouteDistancePreference.PreferNearestToRouteDestination, RouteOrientationPreference.TowardsObject, Target.LotCurrent.LotId, new int[1] { Target.RoomId }); Vector3 position = Target.Position; if (!Actor.DoRoute(route)) { return false; } if (position != Target.Position) { return false; }
Create an object:
For regular objects:
Cup cup = GlobalFunctions.CreateObject("CoffeeCup", Target.Parent.Position, Target.Level, Vector3.UnitZ) as Cup;
string resourceString= "Type:Group:Instance"; object= (CustomObject)GlobalFunctions.CreateObject(ResourceKey.FromString(resourceString), Target.Position, Target.Level, Target.Position);
Posts: 3,865
Thanks: 8689 in 68 Posts
This code snippet shows how to change the name of an object to rename the object's name. The name component is basically the functionality how we can name a sim's car whenever they're best friends with their car
Posts: 3,865
Thanks: 8689 in 68 Posts
If your jazz script is not working as expected, you can use EA's debugging exceptions to catch it
try { mCurrentStateMachine.RequestState("x", "JournalReadLoop"); } catch (ResetException ex) { print("Lyralei's Journal: " + ex.Message + " -=- " + ex.Source); } catch (ArgumentException ex) { print("Lyralei's Journal: " + ex.Message + " -=- " + ex.Source); } catch (SacsTimeoutException ex) { print("Lyralei's Journal: " + ex.Message + " -=- " + ex.Source); } catch (SacsAbortException ex) { print("Lyralei's Journal: " + ex.Message + " -=- " + ex.Source); } catch (ApplicationException ex) { print("Lyralei's Journal: " + ex.Message + " -=- " + ex.Source); } catch (Exception ex) { print("Lyralei's Journal: " + ex.Message + " -=- " + ex.Source); }
Solo animations for testing
If you want to play just an animation without wanting to make a jazz script, or you want to check if your CLIP animation works before making a jazz script, you can also use:
// The clip added here is for grabbing metals from the ground base.Actor.PlaySoloAnimation("a2o_object_genericSwipe_x", true); // another example but with your own CLIP name: base.Actor.PlaySoloAnimation("a_Lyralei_IWantToAnimate", true);
NOTIFICATIONS:
Sims3.UI.StyledNotification.Show(new Sims3.UI.StyledNotification.Format("ADD TEXT/OR FUNCTION HERE", StyledNotification.NotificationStyle.kGameMessageNegative));
An example on how to have the sim interacting with something to trigger the notification
actor.ShowTNSIfSelectable("In use!", StyledNotification.NotificationStyle.kSimTalking)
All the notification Styles:
kSimTalking
kSystemMessage
kGameMessagePositive
kGameMessageNegative
kDebugAlert
kCustom
kCelebrityUpdate
Posts: 51
Thanks: 1059 in 2 Posts
Query Objects Of a Certain Type
-Finds objects of that type either in general or a specific lot. - Can be GameObject, Sim, or a specific object within the world. Add a 'LOT' inbetween the () to narrow the search to particular lot.
Computer[] computer = Queries.GetObjects<Computer>();
Get Interaction Type
-Find whether an object has a specific interaction type, so for example if you created an interaction class called 'StartBusiness' (off the top of my head :P) you would do the following:
foreach (InteractionObjectPair interaction in computer.Interactions) { if (interaction.InteractionDefinition.GetType() == StartBusiness.Singleton.GetType()) { //DO CODE HERE... LIKE REMOVE INTERACTION ETC. } }
Get Object By Unique ID
-All objects in a world are unique so if you want to find out information about a set object you can do the following:
GameObject.GetObject(objectID).theMethodYouWantToCall;
Find An 'Actors'/Sims Traits
-Check the basic pure script tutorial to find out the difference between Actors & Targets (I.E Sims & their Interaction Objects (another sim, object etc)).
-The trait names will list if you just press the . and then you can choose from a list of all the available traits in the game!
//Within an interaction. actor.TraitManager.HasElement(TraitNames.Good) //Actively selected sim: Sim.ActiveActor.TraitManager.HasElement(TraitNames.Good)
Household IDs
-You can check for the unique household ID of an active sim, or actor which you can query if storing data about that 'household':
Sim.ActiveActor.Household.HouseholdId;
Playing A Default EA Sound Effect
-You can find the strings by searching through ILSPY (and perhaps another way but I'm not sure), but for example below this will play the career promotion sound effect, but is used to play any sound. Keep in mind however most sound playback does checks to see if another sound is playing etc.
Audio.StartSound("sting_career_positive");
Removing An Interaction (By Type)
-Similar to the get type method above, you can also remove an interaction from an object that you have queried within a for/foreach: (Will remove SetForSale Interaction or whatever one you want!).
obj.RemoveInteractionByType(SetForSale.Singleton);
Persistable Data - Saving Your Stuff With EAs Code
-So if you're making anything more than a one shot kind of mod you're going to want to save data. Logically while the game is open anything you have stored in variables through the code will be saved but you need to explicitly save it along with The Sims 3 code base. Not 100% of exactly how this works but in short you can do the following above a class you wish to preserve:
[Persistable] //Or if its static data: [PersistableStatic] //Add the following to your assemblyinfo.cs file at the end of the other [] options: [PersistableStatic] //Thats it... you don't need to open a file or do any of that, basically what persisting does it literally 'freezes' the state of the variables stored when the game is saved by the user via the save button. You can then add anything you wish to save in some kind of 'save' class. If you are using a class however and you have a constructor with parameters, you need to make sure you have one empty constructor above the used one. Not sure why.. ask GameFreak lol but it won't work properly without this. Example: public class Save_Test { Save_Test() { } Save_Test(ulong lotID, int simName) { } }
Nested Pie Menu Options (The Real Estate... kind of ones)
-If you have a lot of interactions then you wont want to clutter up the object you're adding to so you can nest them, see the real estate option on the phone or computer for this example. In short it will add any interaction you add the 'path' too, under that path. Put the code in the interaction class, WITHIN the definition class, which contains the GetInteractionName & Test functions/methods.
public override string[] GetPath(bool isFemale) { return new string[1] {"Real Estate..."}; }
Changing An 'InWorld' Objects Price
-At times you may want to adjust the price of a placed ingame item, for example I wanted 'bought' items from my business mod to be set to $0 until restocked, so they were basically worth nothing. Its VERY easy. This example uses a referenced object under an interaction but would work the same with any object queried too as you get access to the same list of methods :
base.Target.mIntPrice = 0;
Changing An Objects Color
-A little tempremental but in short the following code will 'tint' your objects a color, I haven't tested but in short it seems to work on a 0-100 basis. 100 being full color. The parameters are (r,g,b,transitiontime). Example:
//Will tint the object in question to red!
base.Target.SetColorTint(100f,0f,0f,0f);
Adding Moodlets to A Sim/Actor
-Simple really, you can add any moodlet in the game to a Sim with the following, and set its origin and length of time to show!
//BuffNames (press . to see a list of ALL moodlets (buffs) in the game!). MoodAxis affects the mood of the Sim but I don't remember exaxctly what it does... has options similar to The Sims 4 emotions! The origin gives another drop down with a list of potential options as to where the Sim got the moodlet from as they hover over it. The 60f bit is in 'sim seconds' so 60f would be 1 real life minute. The f bit refers to 'float' or basically decimal numbers, but you don't need to add a decimal it works fine with whole / integers.
base.Actor.BuffManager.AddBuff(BuffNames.NewStuff, 0, 60f, false, MoodAxis.Fulfilled, Origin.FromNewObjects, false);
Find A Household By ID
-At times if you are storing the household ID to reference you may wish to find that household to manipulate various options you can do that with the following code:
//The modify family funds bit will adjust the amount of money + or - depending on the value entered. You can just press the . after the find() method though to see a list of all options to perform on households anyhow .
Household.Find(householdID).ModifyFamilyFunds();
Visual Effects!
-Okay so this is early days I don't know EXACTLY how this works but I feel confident that if you just change the name of the visual effect it would play automatically on any target (sim/object etc).
//Change the name of the effect in the " " to show different effects when an interaction is run on your object. The one shown here will show the 'simoleon fly out' effect from the store savvy seller set! Just copy/paste into your code to do the same. Let me know if you understand more than me on this one .
VisualEffect visualEffect = VisualEffect.Create("store_rugPurchase");
Vector3 trans = Vector3.Zero;
Vector3 axis = Vector3.Zero;
if (Slots.AttachToBone(visualEffect.ObjectId, Target.ObjectId, ResourceUtils.HashString32("transformBone"),false,ref trans, ref axis, 0f) == TransformParentingReturnCode.Success)
{
visualEffect.SetAutoDestroy(destroy: true);
visualEffect.Start();
}
else
{
visualEffect.Dispose();
}
Move A Sim To An Object Radius and Check If In Use
-This one is easy as it says it in the method name lol:
//Use within an interaction or on a 'Sim' directly. base.Target is the object/sim to route too, and the 0.5f, 2f is the radius, i'm not sure what this is measured in but this seems to get the sim 'close' to an object as I found it in Ani's code so it works! It will also check if another Sim is using the object, for example it will 'return' false if a sim is sat in a chair its referencing.
base.Actor.RouteToObjectRadialRangeAndCheckInUse(base.Target, 0.5f, 2f)
Numbers In A String Dialogue
-At times you want user input but not always just a sting (or text), so you can do the following to ask for numbers ONLY and then convert the users text into an 'int' for using elsewhere:
//The 'true' bit at the end is whether you want to allow ONLY numbers, if false you can take letters like usual. The result after the user presses the 'tick' button is stored in the variable name after 'string'.
string newCost = StringInputDialog.Show("Change Cost","Choose how much this object will cost:","",true);
int result;
//Here it just says 'try turn the string newCost into a number' and if successful return it in the previously declared 'result' variable!
int.TryParse(newCost, out result);
That's all for now, there are a few other things I could post about but need a break, hope this helps someone! And turns down the volume on requests for me to do it finally haha.
Thanks!
SSD.
Creating Sim State Expansion for The Sims 3. :)
Posts: 990
Thanks: 1965 in 13 Posts
This is when you want an interaction to show up when you click an item in inventory. Obvious to look at, but I had to dig to find an example .
item.AddInventoryInteraction(InteractionClass.Singleton);
Inventory interactions use RunFromInventory() instead of Run()
To check whether an inventory interaction has already been added to an object, use:
foreach (InteractionObjectPair pair in object.GetAllInventoryInteractionsForActor(sim)) { if (pair.InteractionDefinition.GetType() == InteractionYouWant.Singleton.GetType()) { return; } }
Echo Weaver's Simblr: http://echoweaver.tumblr.com/
A portrait in stubbornness - Playing the same legacy since 2009
Sample a Brave Legacy: http://sims3sample.illation.net
Posts: 990
Thanks: 1965 in 13 Posts
Pickers are kind of weird -- you don't have to instantiate them. Just call the static Show() method, and they'll instantiate themselves and pop up to the user. This is the simplest picker subclass I've found, and it's the only one I've needed to use so far. Its Show method takes a parameter of type List<ObjectListPickerInfo>. ObjectListPickerInfo is just a class of two items: a string name and an object.
Here's an example that will pop up a picker asking the user to select a pet breed by its name (e.g. "Dalmation"). The picker returns the BreedOutfit object containing all the info about the breed.
List<BreedOutfit> mBreeds = CASLogic.GetBreedOutfitList(speciesFlag); List<ObjectListPickerInfo> breedInfo = new List<ObjectListPickerInfo>(); foreach (BreedOutfit b in mBreeds) { ObjectListPickerInfo o = new ObjectListPickerInfo(StringTable.GetLocalizedString(b.BreedLocKey), b); breedInfo.Add(o); } return ObjectListPickerDialog.Show(breedInfo) as BreedOutfit;
Echo Weaver's Simblr: http://echoweaver.tumblr.com/
A portrait in stubbornness - Playing the same legacy since 2009
Sample a Brave Legacy: http://sims3sample.illation.net
Posts: 438
Thanks: 5404 in 22 Posts
using Sims3.Gameplay.Utilities; using Sims3.SimIFace; using Sims3.UI; using System; public static class Main { [Tunable] private static bool kInstantiator; static Main() { World.OnWorldLoadFinishedEventHandler += OnWorldLoadFinished; World.OnWorldQuitEventHandler += OnWorldQuit; } private static void OnWorldLoadFinished(object sender, EventArgs e) { UselessData.sTimesTraveledInSave++; UselessData.seekretString += 'A'; // Display the current value of sTimesTraveledInSave and seekretString upon entering live mode after loading/traveling AlarmManager.Global.AddAlarm(1f, TimeUnit.Minutes, delegate () { StyledNotification.Show(new StyledNotification.Format($"{UselessData.sTimesTraveledInSave}\n{UselessData.seekretString}", StyledNotification.NotificationStyle.kSystemMessage)); }, "TEST", AlarmType.NeverPersisted, null); } private static void OnWorldQuit(object sender, EventArgs e) { // UselessData is cleared when a world is unloaded, // So any new games or newly-exposed saves after quitting to main menu will have default values (rather than copying the values from the previously-loaded world) // But if we're traveling, our data is carried over by the game and will replace any old data in the destination the next time we save! // This could also be put into an ObjectGroupsPreLoad callback and have the same effect if (!GameUtils.IsTravelling) { UselessData.sTimesTraveledInSave = 0; UselessData.seekretString = ""; } } } public static class UselessData { // The "true" here enables LoadFromMainMenuOnly [PersistableStatic(true)] public static int sTimesTraveledInSave = 0; [PersistableStatic(true)] public static string seekretString = ""; }
Given the extra memory required by the Ferry to store the data and information about where it goes, I see no reason to use it over this method...which is a shame, since I was rather proud of that code
If you enjoy the mods I put out, consider supporting me on patreon: www.patreon.com/Gamefreak130
Posts: 3,865
Thanks: 8689 in 68 Posts
public static void WriteErrorXMLFile(string fileName, Exception errorToPrint) { uint num = 0u; string s = Simulator.CreateExportFile(ref num, fileName); if (num != 0) { CustomXmlWriter customXmlWriter = new CustomXmlWriter(num); customXmlWriter.WriteToBuffer(errorToPrint.ToString()); customXmlWriter.WriteEndDocument(); } }
All you have to do in your Run() function or any try/catch is the following:
try { // Insert programmer magic here } catch(Exception ex) { // Filename will obviously be the main name of the XML file. The XML file can be found in your documents folder, just like you're used to with Nraas Error trap WriteErrorXMLFile("File Name Here!!!", ex) }
Posts: 3,865
Thanks: 8689 in 68 Posts
Changing the level of a certain mood (Here, we're making the sim sleepier):
base.Actor.Motives.ChangeValue(CommodityKind.Energy, -75f); //(mood goes -100 to 100)
Checking the sim's mood:
// Remember, min is -100 and max is 100 of all moods. if (base.Actor.Motives.GetMotiveValue(CommodityKind.Energy) <= -85f) { /// Do something... }
Literally set the maximum value of a mood. (Will also freeze the mood!, not recommended to use this but if you got a VERY good usecase for it, here you go)
// Remember, min is -100 and max is 100 of all moods. base.Actor.Motives.SetValue(CommodityKind.Energy, 60f);
Posts: 3,865
Thanks: 8689 in 68 Posts
public class SimpleSingleBtnNotification { public Sim mSim; public Sim mTarget; public StyledNotification mNotification; public StyledNotification.Format mNotificationFormat ; public SimpleSingleBtnNotification(StyledNotification.Format notificationFormat, Sim sim, Sim target) { mSim = sim; mTarget = target; mNotificationFormat = notificationFormat; } // Param: Callback expects a method. See example on how this is parsed through. public static void Show(StyledNotification.Format notificationFormat, Sim sim, Sim target, StyledNotification.ButtonPressed callback) { SimpleSingleBtnNotification simpleSingleBtnNotification = new SimpleSingleBtnNotification(notificationFormat, sim, target); simpleSingleBtnNotification .mNotificationFormat .mButtonPressed = callback; simpleSingleBtnNotification .mNotification = StyledNotification.Show(simpleSingleBtnNotification .mNotificationFormat ); } } // EXAMPLE USAGE: public static void TriggerCustomNotification() { StyledNotification.Format notificationFormat = new StyledNotification.Format("Body text" , StyledNotification.NotificationStyle.kGameMessageNegative); SimpleSingleBtnNotification.Show(notificationFormat, ExampleCallback); // See how we parsed in ExampleCallback but without the ()? } public void ExampleCallback() { StyledNotification.Show(new StyledNotification.Format("Helloww I am an example callback! If I got triggered after the button press, then I worked!", StyledNotification.NotificationStyle.kGameMessageNegative)); }
Posts: 3,865
Thanks: 8689 in 68 Posts
ORIGINAL POST: https://modthesims.info/showthread....763#post5660763
Here's a comparison table for reference:
Owner objects are the GameObjects passed as the last argument to the alarm add methods. Typically they are null for global alarms, in which case DeleteOnReset and AlwaysPersisted are functionally equivalent. Global alarms almost never need to be persisted, though -- just readded on WorldLoadFinished. That way, there's a little bit less to save and load in an already-bloated game. |
Posts: 224
Thanks: 1005 in 7 Posts
Ingredients can either have a Plantable component or not.
If they don't then you set the quality with
ingredient.SetQuality(qualityEnum)
qualityEnum in this case is of kind Sims3.Gameplay.Objects.Quality and you can pick one from this list:
Any = -1, Horrifying = 1, Putrid = 2, Foul = 3, Bad = 4, Neutral = 5, Nice = 6, VeryNice = 7, Great = 8, Excellent = 9, Outstanding = 10, Perfect = 11
If they do have a plantable component however the above method will not do anything. You need to set
ingredient.Plantable.QualityLevel = qualityFloat
BUT in this case qualityFloat is a float.
i have tried several method in the game to set the quality this way and it was always off so I ended up writing myself a little array:
public static float[] kQualityLevels = new float[11] { 0.05f, 0.1f, 0.15f, 0.25f, 0.3f, 0.35f, 0.4f, 0.5f, 0.6f, 0.8f, 1f };
If you copy this somewhere in your code, you can just use
ingredient.Plantable.QualityLevel = kQualityLevels[((int)qualityEnum-1)];
So the array translate the enum types into the float value to set the ingredient to the correct value.
Posts: 224
Thanks: 1005 in 7 Posts
You can just copy and paste this
public void SetPreset(uint presetIndex) { uint index; index = (presetIndex > (this.mProduct.NumPresets -1)) ? 0 : presetIndex; SortedList<string, bool> sortedList = new SortedList<string, bool>(); SortedList<string, Complate> originalPatterns = Complate.ExtractPatterns(this.ObjectId, sortedList); ObjectDesigner.SetObject(this.ObjectId); ObjectDesigner.SetPresetInfo(this.ObjectId, ObjectDesigner.GetDesignPreset(index)); DesignModeSwap designModeSwap = Complate.SetupDesignSwap(this.ObjectId, originalPatterns, false, sortedList); if (designModeSwap != null) { designModeSwap.ApplyToObject(); } }
On your GameObject instance:
YOUrOBJECT.SetPreset(PRESEtNUMBER);
Example from my own code:
Sims.Gameplay.Objects.Snow.RecipeBag recipeBag = GlobalFunctions.CreateObjectOutOfWorld("SnowRecipeBag") as Sims.Gameplay.Objects.Snow.RecipeBag; recipeBag.SetPreset(20);
Who Posted
|