Stardew Valley

This is an update to this article where I wrote about the animals at the fall fair festival.

TLDR of previous article: Fall fair animals were incorrectly coded as Villager NPCs and therefore received a chat indicator; my attempt to remove them was to exclude them from the list of NPCs I gather when drawing indicators.

TLDR of this article: I incorrectly fixed the previous issue and (in theory, temporarily) removed children and animals from the player's world. Needless to say, this has been fixed in version 1.2.3

This article will be more technical than the last one and includes some code, in order to fully explain the issue.


As per the last article, I attempted to solve the issue of the animals at the fair having indicators above their heads. I discovered using mod's debug output and information from the Lookup Anything mod that the animals were classified as villagers, and even were marked as sociable. A sociable NPC means they have a friendship bar and can be talked to for friendship, given gifts, etc. Examples of non-sociable NPCs are Gunther and Marlon (unless you have mods to make them sociable). The animals couldn't be talked to, even when using noclip mode, which made this a pretty strange issue to have. A byproduct of them being classified as villagers was that they had actual names (even though you'd never see them in game). Below, I've copied in my code for the array of fall fair animal names.

private readonly string[] illegalVillagers = {
"BabyPig",
"Pig",
"White Chicken",
"Brown Chicken",
"White Cow",
"BabyWhite Cow",
"PonyRide"
};

My attempt to solve this problem was to filter out these specific animals. Each draw cycle, I grab the list of NPCs in the current location/festival and apply an indicator above their heads. By filtering out the animals from this list before drawing, they would not receive an indicator. Below is my code for grabbing the NPCs and filtering out the unneeded ones, as of version 1.2.2.

private NetCollection<NPC> GetNPCsInCurrentLocation() {
NetCollection<NPC> npcs;

bool eventIsOcurring = _config.showIndicatorsDuringCutscenes ? Game1.CurrentEvent != null : Game1.isFestival(); if (eventIsOcurring) {
npcs = new NetCollection<NPC>(Game1.CurrentEvent.actors);
} else {
npcs = Game1.currentLocation.characters;
}

npcs.Filter(c => {
// At the grange festival (fall 16), the animals are classified as villagers for some reason
// They cannot be talked to, so they are removed from the list
if (illegalVillagers.Contains(c.Name))
return false;

return c.isVillager();
});

return npcs;
}

This code has a bad bug, can you find it?

It turns out, I forgot all about the concept of passing by reference vs passing by value. In the if statement, I correctly set the npcs collection to a new collection object, since the objects needed to be converted to a different data structure (List to Collection). In the else statement, however, I left the collection as a direct reference to the game's characters collection. This meant that in the filtering function, I wasn't just filtering out the fair animals; I was also removing all NPCs that weren't a villager, such as pets, children, and barn animals, from the actual list of characters the game was using.

At the very least, this caused the NPCs to disappear. I suspect they may have actually been deleted, given that in some cases the player got the new pet cutscene from Marnie, despite supposedly still having their existing pet. I can't be completely certain of this, however. I am reasonably confident that as long as you didn't save the game with your characters missing, there should be no lasting damage to the save file. If you have any issues after using version 1.2.2, please let me know and we can work to resolve them.

In 1.2.3, here is the updated code to ensure this issue doesn't happen any more. Note the new keyword to ensure creating a copy, and not a reference, of the original character collection.

private NetCollection<NPC> GetNPCsInCurrentLocation() {
NetCollection<NPC> npcs;

bool eventIsOcurring = _config.showIndicatorsDuringCutscenes ? Game1.CurrentEvent != null : Game1.isFestival(); if (eventIsOcurring) {
npcs = new NetCollection<NPC>(Game1.CurrentEvent.actors);
} else {
npcs = new NetCollection<NPC>(Game1.currentLocation.characters);
}

npcs.Filter(c => {
// At the grange festival (fall 16), the animals are classified as villagers for some reason
// They cannot be talked to, so they are removed from the list
if (illegalVillagers.Contains(c.Name))
return false;

return c.isVillager();
});

return npcs;
}

If you'd like to view the entire indicator drawing file, you can find it at my github.

So if I've learned anything, it's that I can definitely mess with the game's data without necessarily touching the save file. I'm going to be extra careful when grabbing data from now on, and will always make sure I'm making a copy and not pulling a reference.

If you have any issues, please let me know.

- Jboss

Article information

Added on

Written by

jbossjaslow

0 comments