Replies: 7 (Who?), Viewed: 270 times.
Lab Assistant
Original Poster
#1 Old 17th Nov 2022 at 6:28 AM
Default How do I go about making a moodlet appear to other nearby sims whenever the actor sim has a specific trait?
I would like to create a moodlet similar to the hunted moodlet that can be caused by vampires. I will specify how I would want it to work in my project. So, If the actor has the custom trait that I made, then nearby sims would gain a moodlet when that actor is in the same room as the sims who get that moodlet. And, when the actor leaves, then the moodlet is removed from the sims that were near the actor with the custom trait.

I took a look at the Hunted Buff in ILSpy, but I am unsure on how to approach this task. I would appreciate it if someone pointed me in the right direction. Thank you.
Advertisement
Forum Resident
#2 Old 18th Nov 2022 at 9:16 PM
Following this thread.

I would like to create actual cat/dog allergy traits, and that would involves adding a moodlet based on proximity to a sim of a given species. That seems pretty similar.

It might be as straightforward as adding broadcasters to vampire sims. One place I'm familiar with that gives a code example of a broadcaster is the Germy moodlet. In that case, the broadcaster is added/removed with the moodlet, but I see no reason you can't add a permanent broadcaster to all your vampires at load-up.

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
Forum Resident
#3 Old 20th Nov 2022 at 1:08 AM
So. Hmm. There are some approximations to the solution I would suggest to consider first.

Subscribe an EventListener to EventTypeId.kSawSim or EventTypeId.kSocialInteraction

These events fire whenever one Sim sees another Sim or respecitvely when one Sim talks to another sim. That's a lot of times!

But yea, just check if one of them has the "triggering trait" and apply the "triggered buff" on the other sim. For like 10 minutes or so.


A precise solution would subscribe to the EventTypeId.kRoomChanged event and every time you check what other <Sim> objects are in the room and run a check if they are in the same room with a sim with the "triggertrait" and set their buff or remove it. Since the roomchanged event triggers like crazy when sims are busy, it might be an even better solution to go all brute-force and check ALL sims if they cohabit rooms every 2 sim-minutes or so.

Find my Mods: Here at MTS, over at Simlogical
Lab Assistant
Original Poster
#4 Old 20th Nov 2022 at 5:29 AM
Quote:
Originally Posted by Consort
So. Hmm. There are some approximations to the solution I would suggest to consider first.

Subscribe an EventListener to EventTypeId.kSawSim or EventTypeId.kSocialInteraction

These events fire whenever one Sim sees another Sim or respecitvely when one Sim talks to another sim. That's a lot of times!

But yea, just check if one of them has the "triggering trait" and apply the "triggered buff" on the other sim. For like 10 minutes or so.


A precise solution would subscribe to the EventTypeId.kRoomChanged event and every time you check what other <Sim> objects are in the room and run a check if they are in the same room with a sim with the "triggertrait" and set their buff or remove it. Since the roomchanged event triggers like crazy when sims are busy, it might be an even better solution to go all brute-force and check ALL sims if they cohabit rooms every 2 sim-minutes or so.


Thanks for your suggestion consort, I ended up using the kSawSim event and it worked as I wanted it too. Especially after I inputted all the conditions I needed for the buff to be added to the other sim. However, like you said I am concerned about performance since the event will trigger each time sims see each other. What is the method you mentioned last? About making the game check every 2 minutes if sims were in a room? I'll be honest I don't know how to implement a method like that, but I would definetly love to know.
Lab Assistant
Original Poster
#5 Old 20th Nov 2022 at 5:34 AM
Quote:
Originally Posted by echoweaver
Following this thread.

I would like to create actual cat/dog allergy traits, and that would involves adding a moodlet based on proximity to a sim of a given species. That seems pretty similar.

It might be as straightforward as adding broadcasters to vampire sims. One place I'm familiar with that gives a code example of a broadcaster is the Germy moodlet. In that case, the broadcaster is added/removed with the moodlet, but I see no reason you can't add a permanent broadcaster to all your vampires at load-up.


I would love to see cat/dog allergies. This is a great idea. Also, what is a Broadcaster? I took a look at the GermyBuff in ILSpy, but I don't know how they are utilized at the moment.
Forum Resident
DELETED POST
20th Nov 2022 at 6:26 PM
This message has been deleted by Consort. Reason: mistake in my code
Forum Resident
#6 Old 22nd Nov 2022 at 11:51 PM
Re:My brute force approach

Sorry, I had a headache and botched the solution first time.

I want to say in advance that I have not done anything with buffs, so I might be doing something wrong or there is some super elegant solution that I'm not aware of. Do I even apply them correctly?

I'm using the Childish trait causing the BadNightSleep buff as a proof of concept for this demo.

Anyway, the quick and dirty solution I come up with is this:

Code:
public static void ApplyBuffs()
{
    try
    {

        // get an array of all the sims in the game
        var allsims = Sims3.Gameplay.Queries.GetObjects<Sim>();

        // let's look at each one
        foreach (var sim in allsims)
        {
            // check if the sim has the triggering trait. Do nothing if sim is on world lot (streets)
            if (sim.HasTrait(TraitNames.Childish) && !sim.LotCurrent.IsWorldLot)
            {
                //get all sims that are on the same lot, same room id and are not the trait sim
                var simsinroom = sim.LotCurrent.GetObjects<Sim>(x => x.RoomId == sim.RoomId && x != sim);

                foreach (var roomsim in simsinroom)
                {
                    // (re)apply buff all those sims, it will timeout after 5 mins.                        
                    roomsim.BuffManager.AddBuff(BuffNames.BadNightSleep, 0, 5f, false, MoodAxis.None, Origin.FromBeingAroundNonFriends, false);
                }
            }
        }


    }
    catch (Exception e)
    {
        // show error
        string text = "applybuff" + e.ToString();
        StyledNotification.Show(new StyledNotification.Format(text, ObjectGuid.InvalidObjectGuid, ObjectGuid.InvalidObjectGuid, StyledNotification.NotificationStyle.kGameMessagePositive));

    }

    // this was fun, let's do it again in 2 minutes
    AlarmManager.Global.AddAlarm(2f, TimeUnit.Minutes, new AlarmTimerCallback(ApplyBuffs), "applybuffs", AlarmType.NeverPersisted, null);
}


The code above should run every 2 sim-minutes and just applies a buff with a 5 min timeout. I believe it works but looks a bit silly in the game because the timeout is visible under the buff and you see how it gets refreshed.

Just call ApplyBuffs() in your WorldLoadFinished routine and it should go.

Now, if we want to switch on and off buffs to mimic how the game would typically work, we need a more cluttered approach:

Code:
public static void ApplyBuffs2()
{
    try
    {

        // get an array of all the sims in the game
        var allsims = Sims3.Gameplay.Queries.GetObjects<Sim>();
        // we use this dictionary to map which sim requires their buff to be set (true) or unset (false)
        Dictionary<Sim, bool> applydict = new Dictionary<Sim, bool>();

        // copy the array of all sims to our applydict and set value to false for now;
        foreach (var sim in allsims)
        {
            applydict[sim] = false;
        }

        // let's paint all sims that should have the buff with "true"
        foreach (var sim in allsims)
        {
            // check if the sim has the triggering trait. Do nothing if sim is on world lot (streets)
            if (sim.HasTrait(TraitNames.Childish) && !sim.LotCurrent.IsWorldLot)
            {
                //get all sims that are on the same lot, same room id and are not the trait sim
                var simsinroom = sim.LotCurrent.GetObjects<Sim>(x => x.RoomId == sim.RoomId && x != sim);

                foreach (var roomsim in simsinroom)
                {
                    // set flag to true in our dictionary
                    applydict[roomsim] = true;


                }
            }
        }

        // mapping is done, we iterate a third time to actually apply or remove buffs.
        foreach (var entry in applydict)
        {
            if (entry.Value) // value is true, so (re)apply the buff
            {
                entry.Key.BuffManager.AddBuff(BuffNames.BadNightSleep, 0, 0f, true, MoodAxis.None, Origin.FromBeingAroundNonFriends, false);
            }
            else // preemptively timeout/remove the buff on everyone else
            {
                entry.Key.BuffManager.UnpauseBuff(BuffNames.BadNightSleep);
            }
        }


    }
    catch (Exception e)
    {
        // show error
        string text = "applybuff2 " + e.ToString();
        StyledNotification.Show(new StyledNotification.Format(text, ObjectGuid.InvalidObjectGuid, ObjectGuid.InvalidObjectGuid, StyledNotification.NotificationStyle.kGameMessagePositive));

    }
    // don't forget to resubscribe the alarm.
    AlarmManager.Global.AddAlarm(2f, TimeUnit.Minutes, new AlarmTimerCallback(ApplyBuffs2), "applybuffs2", AlarmType.NeverPersisted, null);
}


Nope, that's not very elegant, but it shouldn't be too slow either.

The difference is that ApplyBuffs2 actively switches on and off the buff while ApplyBuffs only swithces them on and relys for them to timeout on their own. ApplyBuffs2 would be more suitable if the buff is defined as a permanent buff to get as close to expected game behaviour (Buff shows a dash, not a 0m timeout).

Find my Mods: Here at MTS, over at Simlogical
Lab Assistant
Original Poster
#7 Old 23rd Nov 2022 at 5:21 AM
Hello Consort, I used both of your methods. As you suggested the ApplyBuffs2 works much better and it works as the method I wanted to implement. Thank you so much and thanks for leaving notes in your code. That made it much more easier to understand. I modified the conditions to work alongside my custom traits/buffs. You're method is awesome. Again thank you!
Forum Resident
#8 Old 23rd Nov 2022 at 11:30 PM
Excellent.

Find my Mods: Here at MTS, over at Simlogical
Back to top