REQUEST SMAPI 2.0 Replacement for Happy Animals Mod? | Fix for 6pm animal happiness drain

Discussion in 'Mods' started by Verne, Oct 30, 2017.

  1. Verne

    Verne Astral Cartographer

    This one by StarPeanut.

    What this mod did (to my knowledge) was set animal happiness to 255 every night, which sounds cheaty, but...the happiness drain after 6pm is still an issue, to my knowledge, and that's the most broken part of the happiness system.

    This is the only mod I used that isn't SMAPI 2.0 compatible, and I actually haven't played since before that update, mostly because of real world issues. I'd love to have it back, though!

    Thank you!


    Github Modding Ideas post about the issue

     
      Last edited: Oct 30, 2017
    • Tinybillow

      Tinybillow Scruffy Nerf-Herder

      This 6pm happiness issue is undesirable. Agreed. Especially when you pristinely care for your animals. +1.
       
      • Pathoschild

        Pathoschild Tiy's Beard

        If nobody responds here, I suggest adding it to the mod idea list so modders looking for ideas will see it. :)
         
        • Verne

          Verne Astral Cartographer

          @Pathoschild I made an account and added it, thanks! :D

          @Tinybillow Aye, it feels like a big bummer when you take perfect care of them every day and then it's undone by a bug :(
           
          • Jurk0wski

            Jurk0wski Orbital Explorer

            I'm working on a fix myself right now, since I got tired of waiting for an official fix. It's my first mod though, so I'm still figuring out how things work. That's not to say I don't have coding experience, just nothing with SV.

            While I'm unsure exactly what I can do with modding right now, and assuming this thread's code is accurate, then the updated code I posted a couple days ago in the thread should work as well, all I have to do is figure out how to actually mod it in.

            Right now, I'm examining the game's source code trying to figure out exactly where that section of code is. I'll post a reply here with any updates.

            Edit: found the code I'm looking for:

            Code:
                public virtual void updatePerTenMinutes(int timeOfDay, GameLocation environment)
                {
                  if (timeOfDay >= 1800)
                  {
                    if (environment.IsOutdoors && timeOfDay > 1900 || !environment.IsOutdoors && (int) this.happiness > 150 || (environment.isOutdoors && Game1.isRaining || environment.isOutdoors && Game1.currentSeason.Equals("winter")))
                      this.happiness = (byte) Math.Min((int) byte.MaxValue, Math.Max(0, (int) this.happiness - (environment.numberOfObjectsWithName("Heater") <= 0 || !Game1.currentSeason.Equals("winter") ? (int) this.happinessDrain : (int) -this.happinessDrain)));
                    else if (environment.IsOutdoors)
                      this.happiness = (byte) Math.Min((int) byte.MaxValue, (int) this.happiness + (int) this.happinessDrain);
                  }
                  if (environment.isTileOccupiedByFarmer(this.getTileLocation()) == null)
                    return;
                  environment.isTileOccupiedByFarmer(this.getTileLocation()).temporaryImpassableTile = this.GetBoundingBox();
                }
            Now that I've gotten a better look at this code rather than just the snippet the thread gave me, it looks like they attempted a fix, but they didn't understand what was wrong, and simply reversed how the heater+winter check worked without changing what it actually does. Additionally, now I can see that it is currently set to only be activate after 6PM instead of just being all the time with some checks that hit you anyways. It's been a while since I've coded, so I remember there might be something I have to worry about with it being a virtual function, but I'll worry about that later.

            So, fixes I have planned for this in particular:
            1. The happiness drain will only happen if the animal is indoors before 6PM in any season other than winter. To prevent issues, I'll still restrict it to times after 10 AM, to give animals time to move outdoors if they aren't already.
            2. Happiness will continue to drain from animals indoors without a heater in winter regardless of the time.
            3. Heaters will have no effect outdoors (currently heaters can be placed outdoors, and this does not currently check against that for winter).
            4. Animals with less than 150 happiness who would not have their happiness drained for any reason, will have their happiness increase to at least 150.
            5. During winter with a heater, all animals, not just those with 150 or more mood, will have their mood increased.
            If you want any other changes to this, let me know.
             
              Last edited: Oct 31, 2017
            • MouseyPounds

              MouseyPounds Cosmic Narwhal

              The code related to losing happiness after 6pm is from StardewValley.FarmAnimal.updatePerTenMinutes(). Please also look into the happiness overflow issue (#1 in the other post). Although it was supposedly fixed, it seems like it still happens with Coopmaster (and probably Shepherd) professions; this is from StardewValley.FarmAnimal.pet()
               
              • Jurk0wski

                Jurk0wski Orbital Explorer

                yeah, found it already, and I'll look into the overflow issue as well, just in case.

                Edit:
                Looking at the overflow issue, I think I see where the issue might be. Let me get you a snippet of the important part:

                Code:
                if (!this.wasPet)
                        {
                          this.wasPet = true;
                          this.friendshipTowardFarmer = Math.Min(1000, this.friendshipTowardFarmer + 15);
                          if (who.professions.Contains(3) && !this.isCoopDweller())
                          {
                            this.friendshipTowardFarmer = Math.Min(1000, this.friendshipTowardFarmer + 15);
                            this.happiness = Math.Min(byte.MaxValue, (byte) ((uint) this.happiness + (uint) Math.Max(5, 40 - (int) this.happinessDrain)));
                          }
                          else if (who.professions.Contains(2) && this.isCoopDweller())
                          {
                            this.friendshipTowardFarmer = Math.Min(1000, this.friendshipTowardFarmer + 15);
                            this.happiness = Math.Min(byte.MaxValue, (byte) ((uint) this.happiness + (uint) Math.Max(5, 40 - (int) this.happinessDrain)));
                          }
                          this.doEmote((int) this.moodMessage == 4 ? 12 : 20, true);
                          this.happiness = (byte) Math.Min((int) byte.MaxValue, (int) this.happiness + Math.Max(5, 40 - (int) this.happinessDrain));
                          if (this.sound != null && Game1.soundBank != null)
                          {
                            Cue cue = Game1.soundBank.GetCue(this.sound);
                            string name = "Pitch";
                            double num = (double) (1200 + Game1.random.Next(-200, 201));
                            cue.SetVariable(name, (float) num);
                            cue.Play();
                          }
                          who.gainExperience(0, 5);
                        }
                
                So, if the animal was not yet pet, first, flag it as being pet, then increase it'd friendship (not mood) by 15. There's then 2 near identical if statements, but they both do the same thing just dependent on the animal type and profession. It's intended to increase friendship again if you have the right profession, and then increase the animal's mood as well. It then does another mood increase after the if statements.

                Now, let me snip the most important parts that might be causing the issue.

                first, the mood code for when you have the profession:

                Code:
                this.happiness = Math.Min(byte.MaxValue, (byte) ((uint) this.happiness + (uint) Math.Max(5, 40 - (int) this.happinessDrain)));
                and the mood code that always happens:

                Code:
                this.happiness = (byte) Math.Min((int) byte.MaxValue, (int) this.happiness + Math.Max(5, 40 - (int) this.happinessDrain));
                Let me start with the always-happens code to see what happens, and let's start at max mood too. the creature's mood drain (a positive number, so when you subtract it, you are "draining" the mood) is cast to a signed integer, which, depending on how it's handled by the program can vary, should be a range of -32768 to 32767. The drain should be nowhere near that, so it's not an issue. the mood drain as a sign int is subtracted from 40. It then picks the larger of either that number or 5, so an animal will always gain at least 5 mood, so for out purposes, let's use 5. We then take the animal's current mood, cast it to a signed int, which should make it 255 if it was previous max, and add 5 to it, so now we have 260. Finally, it figures out the max value of a byte, which should be 255, and casts it to a signed int, which is still 255, and it takes the smaller of those 2 values, casts it back to a byte, and assigns that to the animal's current happiness, which should result in 255. Casting stuff into bytes can get... weird... but seeing as people say it work's fine, I'll assume it does.

                Not let's look at the profession one. same mood drain stuff, so let's once again assume 5. This 5 is then cast into an unsigned integer, which ranges from 0 to 65535. It's still a 5. It then takes the animal's current mood, casts it to an unsigned int, so still 255, and adds them, so 260. It then... casts that to a byte... WAT... I don't know how it handles that. My guess is it turns into 4, since 260 looks like this is binary: 0000 0001 0000 0100, a byte is only 8 bits, so it would chop off the extra bits, giving you 0000 0100, which is 4. So, then it takes that 4, compares it against the largest a byte can hold at takes the smallest, which is 4, then assigns that to the animal's mood.

                So yes, professions do cause the wrap around, i'll see about fixing that too.

                Edit:
                btw, don't worry about me going on explanations like this. I use it as a programmer's rubber duckie, it helps me figure out how to fix stuff.


                Edit: well, after wrestling with all the info provided, and even asking the discord some questions. I've come to the conclusion that these bugs would be far, far easier to fix by just compiling a short but detailed list of instructions about exactly what's wrong, why, and how to fix it, and emailing CA or whoever is now keeping the game updated, and hoping they put out a hotfix. While I was told it's possible to replace some of the game's class's methods with your own, it's not easy in any way, not really viable, and thus not suggested at all unless there's no other choice. After spending 2 hours pretty much scouring the game's code and reading documentation and guides, I'm out. I know what the problems are, I just see no easy fix aside from getting them to fix their own game's code.
                 
                  Last edited: Oct 31, 2017
                • kumarei

                  kumarei Void-Bound Voyager

                  I started working on this last night, and currently have a working alpha to fix the happiness problem. Still needs a tiny bit of tweaking, since it's overbroad right now. I've got an idea for how to fix the profession overflow.

                  https://github.com/YonKuma/MoodGuard

                  EDIT: If you want to download it now, you can at:

                  https://github.com/YonKuma/MoodGuard/releases/download/v1.0-alpha.3/MoodGuard.1.0-alpha.3.zip

                  With the warning that I haven't tested it completely, and I've only tested it on Windows.

                  EDIT2: Renamed to Mood Guard and added a safeguard
                   
                    Last edited: Oct 31, 2017
                    HopeWasHere likes this.
                  • kumarei

                    kumarei Void-Bound Voyager

                    Tinybillow, Verne and HopeWasHere like this.
                  • Verne

                    Verne Astral Cartographer

                  • Tinybillow

                    Tinybillow Scruffy Nerf-Herder

                    I've been using this on mac, zero issues, nice mod. I really appreciate the new config. Keep going. :)
                     

                    Share This Page