Hi there! You are currently browsing as a guest. Why not create an account? Then you get less ads, can thank creators, post feedback, keep a list of your favourites, and more!
Quick Reply
Search this Thread
Field Researcher
Original Poster
#1 Old 7th Jun 2020 at 11:28 PM
Default Apply buff when sim performs an idle
Hello! I'm new to script modding (or any modding really, but I do have coding experience - not in C# though), and as my first fully from scratch mod (after reading tutorials and opening up others' mods for a while), I'm trying to insert a script that has a chance to apply some custom buffs every time a sim does the pregnancy idle animation. The way EA made the pregnancy buff work has always annoyed me, every sim shouldn't just be ecstatic about it the whole time, so I figured I'd give fixing it a try. Might be a little much for a first project but I figure disliking EA's handling of pregnancy as much as I do will give me more determination than picking something I have a smaller chip on my shoulder about.

From what I understand, I think a strategy for doing this could be to add an event listener initialized on world load that listens for the event of a sim doing the idle, and applies my buffs when that happens. It doesn't look like any of the events in the enum Sims3.Gameplay.EventSystem.EventTypeId have anything to do with idles, so instead I'm wondering if I could get the name of the last idle a sim has performed by doing something like this:
IdleManager i = new IdleManager();
string lastIdleName = i.LastIdle;
...and then add the buffs to a sim whenever lastIdleName for that sim is the one I want ("a_pregnancy_idle_rubBelly_x", if you're wondering).

So my questions are:
1) Does the above sound like an at least feasible approach to the goal I have? I really don't know the code for this game well enough to tell
2) Does anyone know of any mods that have a similar feature, where a script (for any purpose at all!) is triggered by a sim performing an idle, that I could look inside to see how that was implemented?
Advertisement
Space Pony
#2 Old 8th Jun 2020 at 4:37 AM Last edited by gamefreak130 : 8th Jun 2020 at 4:51 AM.
Quote: Originally posted by lizcandor
Hello! I'm new to script modding (or any modding really, but I do have coding experience - not in C# though), and as my first fully from scratch mod (after reading tutorials and opening up others' mods for a while), I'm trying to insert a script that has a chance to apply some custom buffs every time a sim does the pregnancy idle animation. The way EA made the pregnancy buff work has always annoyed me, every sim shouldn't just be ecstatic about it the whole time, so I figured I'd give fixing it a try. Might be a little much for a first project but I figure disliking EA's handling of pregnancy as much as I do will give me more determination than picking something I have a smaller chip on my shoulder about.

From what I understand, I think a strategy for doing this could be to add an event listener initialized on world load that listens for the event of a sim doing the idle, and applies my buffs when that happens. It doesn't look like any of the events in the enum Sims3.Gameplay.EventSystem.EventTypeId have anything to do with idles, so instead I'm wondering if I could get the name of the last idle a sim has performed by doing something like this:
IdleManager i = new IdleManager();
string lastIdleName = i.LastIdle;
...and then add the buffs to a sim whenever lastIdleName for that sim is the one I want ("a_pregnancy_idle_rubBelly_x", if you're wondering).

So my questions are:
1) Does the above sound like an at least feasible approach to the goal I have? I really don't know the code for this game well enough to tell
2) Does anyone know of any mods that have a similar feature, where a script (for any purpose at all!) is triggered by a sim performing an idle, that I could look inside to see how that was implemented?


Full disclosure: I've never worked with idles before, nor do I know of any mods that do off the top of my head.

You seem to be on the right track. However, you do not want to simply instantiate a new IdleManager. IdleManagers are meant to be tied to specific sims, and the game already constructs them as needed for this purpose. Instead, what I think you would want to do is something like this:

Code:
using Sims3.Gameplay.Actors;
using Sims3.Gameplay.ActorSystems;

internal static void IdleTest()
{
    foreach (Sim sim in Sims3.Gameplay.Queries.GetObjects<Sim>())
    {
        if (sim.SimDescription.IdleManager is IdleManager idleManager && idleManager.LastIdle == "a_pregnancy_idle_rubBelly_x")
        {
            sim.BuffManager.AddElement(0xFFFFFFFFFFFFFFFF, Origin.None); // This is the method that adds custom moodlets to a sim, in case you didn't already know
        }
    }
}


Set this function as the callback of a repeating alarm (created on WorldLoadFinished, as you said), and you should be set.

"The Internet is the first thing that humanity has built that humanity doesn't understand, the largest experiment in anarchy that we have ever had." - Eric Schmidt

If you enjoy the mods I put out, consider supporting me on patreon: www.patreon.com/Gamefreak130
Field Researcher
Original Poster
#3 Old 8th Jun 2020 at 5:37 AM
Quote: Originally posted by gamefreak130
IdleManagers are meant to be tied to specific sims, and the game already constructs them as needed for this purpose.

I was wondering if that was the case! Making the buff be assigned by the callback function of a repeating alarm and writing the callback function so it uses specific sims' IdleManagers was the solution I came to also, I'm glad that was actually the right idea - right now I have this alarm repeating every 5 minutes, which may be too much but I'm just going to try it out and see if my computer hates it.

On my first in-game test it turned out my custom buffs aren't getting loaded, though, I can't even assign them with MasterController; so I've got to go back and figure out what's up with that before I can see if the idles thing worked. Thanks for the advice!
Virtual gardener
staff: administrator
#4 Old 9th Jun 2020 at 2:15 PM
Quote: Originally posted by lizcandor
On my first in-game test it turned out my custom buffs aren't getting loaded, though, I can't even assign them with MasterController; so I've got to go back and figure out what's up with that before I can see if the idles thing worked. Thanks for the advice!
That's because you still need to 'instantiate' that too  Here are a few helpful links:

http://www.simlogical.com/ContentUploadsRemote/uploads/1063/How_Create_Load_Custom_Moodlets_with_Pure_Script_Mod.pdf
http://modthesims.info/showthread.p...5#startcomments

So you basically need to set up some sort of "XML reader" for your buff as well. Which, I can say out of experience, is an annoying one to set up. :p So feel free to ask any questions as well on that if that's not exactly working out!  
Field Researcher
Original Poster
#5 Old 13th Jun 2020 at 4:30 AM
I've followed NonaMena's tutorial but am having no luck, maybe I've made a mistake in my XML files. By an XML reader, you mean something like the AddBuffs method of the BuffBooter class in the tutorial, right?
Field Researcher
Original Poster
#6 Old 13th Jun 2020 at 4:01 PM Last edited by lizcandor : 13th Jun 2020 at 4:20 PM.
EDIT: My initial forum search wasn't thorough enough, I just noticed this thread http://modthesims.info/showthread.p...hlight=mscorlib sounds like maybe the same problem I'm having; I'll check that out too. Would be funny if it turned out the problem is just that Visual Studio 2019 is too new for this.

Okay, I tried some more debugging! I noticed my mod couldn't even apply EA moodlets, so while my buffs XML or the reader for it may also be broken that's probably not the only issue. I also notice when I look in my package that the S3SA file I made has this error message:
Code:
Error reading resource 0x073FAA07-0x00000000-0x9E02A2151845A3C3 
Front-end Distribution: 14-0222-1852 
Library Distribution: 14-0222-1852  
Source: mscorlib 
Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
Exception has been thrown by the target of an invocation. 
---- 
Stack trace:    
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)    
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)    
at s3pi.WrapperDealer.WrapperDealer.WrapperForType(String type, Int32 APIversion, Stream s)    
at S3PIDemoFE.MainForm.browserWidget1_SelectedResourceChanged(Object sender, ResourceChangedEventArgs e) 
----  
Source: mscorlib 
Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 
Unable to read beyond the end of the stream. 
---- 
Stack trace:    
at System.IO.__Error.EndOfFile()    
at System.IO.BinaryReader.FillBuffer(Int32 numBytes)    
at System.IO.BinaryReader.ReadUInt32()    
at ScriptResource.ScriptResource.Parse(Stream s) ----


And I don't know what to make of most of that yet but it sounds like my mscorlib.dll isn't being read? The mscorlib.dll I'm using is the NRaas unprotected one; I remember it being mentioned somewhere that not all the core libraries need to be unprotected, so I'm going to try swapping that for the protected version I extracted myself and see what happens.
Virtual gardener
staff: administrator
#7 Old 13th Jun 2020 at 7:03 PM
Usually S3PE does indeed show a few "error from these and that dll files" but you might be right given that bit where it says "unable to read beyond the end of the stream". Usually, when that happens there's probably 2 things happening here:

1. Your framework was written in NET3.0 or higher, rather than 2.0 (which the sims is developed in) and therefore the mscorlib not working/compiling correctly with that version. 
2. Make sure to double-check step 6 in this tutorial: https://modthesims.info/wiki.php?ti..._Studio_project

Once that's fixed, it should do the trick! Then it's merely a question whether the code actually works . I do want to say though, that having worked on TS3 code actively for a year now, when the notification isn't working, the code above it is probably not working. TS3 doesn't really have much of a debug method except for writing out the exception error in a notification or modal. :/

Do let us know how it goes though!
Field Researcher
Original Poster
#8 Old 21st Jun 2020 at 1:38 AM
Default Buffs work!
A week later, I have an update! The short version is the mod basically works now.

I read through that tutorial (thanks Lyralei!) and a couple others again, did those 2 checks, and then discovered I was making an embarrassingly dumb mistake. But for the record, for the sake of future modding newbies who may be the same kind of fool as me and need it pointed out: dragging and dropping DLLs into S3PE is not the same as going through the whole series of steps in the Building The Package section of the Pure Scripting Modding tutorial, and things will not work if you do that

After being reminded of the instructions, the S3SA file in my package looked normal in s3pe, and the package actually showed up in the list of mods on starting the game, which it didn't before. My custom buffs still weren't loading at first, which is what I was trying to understand for the last while and finally solved today: it seems like there must have been a localization issue, although I don't know what it was. For testing the package, I'd only made an English STBL, because I'd assumed my game wouldn't need the others; but eventually there was nothing else left I could check, so I used the STBL duplicator to make strings for all the other languages it supports just to see if that would change anything. It did, the buffs work just fine now.

The other part of my initial plan, assigning the buffs based on the occurrence of a specific idle, hasn't worked yet. I'm not giving up on that idea yet, but as a workaround for now I'm just having the callback function to a repeating alarm on each pregnant sim check if the pregnancy is visible and then roll to see if either or both buffs should be applied based on traits. Slightly less fun, but it works and the effect is basically the same.

Thanks!
Field Researcher
Original Poster
#9 Old 23rd Jun 2020 at 9:20 AM Last edited by lizcandor : 23rd Jun 2020 at 10:48 AM.
[EDIT: Turns out the problem really was just that my brain is slow when I'm tired; I tested for another hour and then realized one of my problems was because I was using a public instead of a local variable for my alarm handle, and the other was because the target of the "got pregnant" event is the other parent in the pregnancy, not the sim who is pregnant. I didn't catch that second one until I started doing test pregnancies with MC's partner pollinate instead of just making random sims do parthenogenesis.]

I thought I was done but actually have one more question, sorry! It seems like my alarms aren't being removed properly and I'm having a hard time figuring out why(possibly because it's 4AM). I wrote the callback function for the alarm (pasted below) to check if the sim is pregnant before trying to apply any buffs, and if not, to remove the alarm and display a message telling me that happened. If it weren't for the messages I'd think everything was working, but the alarm-removed message for sims that aren't pregnant anymore just keeps repeating on every cycle of the alarm unless I do ResetSim on whoever the message is about.

So my question is, is trying to make an alarm's callback function tell it to remove itself a fundamentally mistaken idea? And just out of curiosity, how badly would unwrangled alarms that don't do anything but ask if a sim is pregnant and get the answer "no" slow down a game?

Code:
        public static ListenerAction OnPregnancy(Event e)
        {
            Sim sim = e.TargetObject as Sim;

            lizcandorPregnancyAlarm = sim.AddAlarmRepeating(1f, TimeUnit.Hours, MixedPregnancyFeelingsCallback, 1f, TimeUnit.Hours, "MixedPregnancyFeelings Check", AlarmType.NeverPersisted);

            void MixedPregnancyFeelingsCallback()
            {
                StyledNotification.Show(new StyledNotification.Format(String.Concat("MPF callback on ", sim.Name), StyledNotification.NotificationStyle.kGameMessageNegative));

                if (sim.SimDescription.IsPregnant)
                {
                    if (sim.SimDescription.IsVisuallyPregnant)
                    {
                        if (RollPositive(sim))
                        {
                            sim.BuffManager.AddElement(0x11F86A084D18A79A, Origin.FromPregnancy); // Add Eagerly Expecting
                        }

                        if (RollNegative(sim))
                        {
                            sim.BuffManager.AddElement(0x50D6924CDE9821F5, Origin.FromPregnancy); // Add Anxiously Expecting
                        }
                    }
                }
                else
                {
                    sim.RemoveAlarm(lizcandorPregnancyAlarm);
                    StyledNotification.Show(new StyledNotification.Format(String.Concat("Pregnancy alarm removed from ", sim.Name), StyledNotification.NotificationStyle.kGameMessageNegative));
                }
            }
            
            return ListenerAction.Keep;
        }
Back to top