NPC Helper 2/Docs

Reference

Release Notes

Changes in every NPC Helper 2 release, including the 2.0.0 breaking changes.

2.4.0#

  • Adds heart events. An NPC folder can have an Events.toml with one table per event, written in plain words (Location, Hearts, optional Weather, Time, Days and After, where the Farmer and the Npc stand, and Steps such as Rei: Hello., Rei walks down 2, Rei emotes heart). NPC Helper compiles it to the game's event script and key (event ID <Npc>_<EventName>, the f <Npc> <hearts x 250> condition, music, camera, actors, skippable, end) and adds it to Data/Events/<Location>. An event with a problem is skipped with a message that names the step. A whole game script can still be given as Script.
  • Adds festival lines. A Festivals.toml with one table per festival ID (spring13, summer11 ...) gives the NPC her Dialogue and SpouseDialogue at that festival, added to Data/Festivals/<id> the way the game's own NPCs have theirs. Placing the NPC on the festival map is not supported yet. See events.
  • A marriageable NPC whose sprite sheet has nothing drawn in the spouse-kiss frame (28) or the wedding frames (36-38), or whose sheet ends before them, now gets a warning that names the frame (the game shows an invisible NPC there). Generated placeholder sprite sheets are now 64x320 so they include the wedding frames.
  • A heart event that gives both Script and Steps now says that only Script is used.
  • Heart events and festival lines can be translated. A locale/<code>/Events.toml has a [EventName] table with Texts, the translated lines in the order they are said (the scene stays the base pack's), and a locale/<code>/Festivals.toml replaces the festival Dialogue and SpouseDialogue. A wrong number of lines, an unknown event or an unknown festival is reported. Translation templates (TranslationPack.BuildTemplate), TranslationPackBuilder.FromNpc and the SDK's LocaleBuilder.EventLines / Festival include them, and TranslationPack.Validate compares them with the base pack.
  • The pack-structure check ignores files a mod manager leaves in a pack (Vortex's *.vortex_backup, __folder_managed_by_vortex, vortex.deployment.json, Mod Organizer's meta.ini, desktop.ini, Thumbs.db, .DS_Store), so installing through Vortex no longer logs warnings, and a language folder holding only such files is not reported as empty.
  • The pack-structure check no longer reports ordinary folders such as docs as a misspelled NPCs folder.

2.3.0#

  • The TOML parser now supports all of TOML 1.0: dotted keys and nested tables, inline tables, hex/octal/binary integers, inf/nan, and date-time values, with a strict mode (TomlParseOptions.Strict). NPC files still load leniently. An unquoted key with a dot (a.b = 1) is now a dotted key; quote it to keep the dot.
  • Locale folders are now layered: a regional folder such as locale/pt-BR only needs the texts that differ from locale/pt, which in turn override the base text. Previously only the most specific folder was read, so a partial pt-BR folder hid the rest of pt. Switching between en, en-US and an empty locale no longer reloads every NPC.
  • Packs laid out by hand are checked for misspelled or misplaced folders and files (NPCs, locale, sprites, portraits, language codes such as th_TH, Dialog.toml, non-.toml files, top-level .toml files, a misnamed manifest.json or mod.toml), for NPC files missing from the NPCs list, and for a pack that loads nothing. At startup NPC Helper also warns when a pack has translations for an NPC that is not loaded and suggests the NPC it probably meant.
  • mod.toml takes more optional settings: Exclude (skip drafts), Locales and Translates (declare a translation pack's languages and NPCs, so a translation whose NPC mod is missing is reported at startup), and StrictToml (read the pack as strict TOML 1.0). Every setting is optional, none repeats manifest.json (a copy there is reported and ignored), and unknown settings are now reported.
  • Translations in other mods are now found through SMAPI's list of content packs for NPC Helper instead of walking the whole Mods folder. Only NPCs/<Npc>/locale/<code> inside those packs is checked. A translation mod that is not a content pack for NPC Helper, or sits in a folder without a manifest, is no longer detected; use the Manual install into the NPC's own mod folder or the Manager (content pack) archive.
  • A content pack that only holds translations no longer warns "No NPCs found"; it logs which NPCs it translates.
  • The startup log is now one grouped entry (NPCs per pack, language, errors and warnings) without file-system paths.
  • Fixes external locale packs not being found when the Mods folder is a symbolic link or junction.

2.2.1#

2.2.0#

  • Adds combined location-and-season sprite and portrait variants, named <Location>_<Season>.png (for example, Hospital_Summer.png), with selection priority: location + season, location, season, then the default image.
  • Supports 2× portrait source sheets with PortraitScale = 2 in the content pack's root mod.toml; NPC Helper downsamples every selected portrait, including seasonal/location variants and marriage portraits, to the game's native 64×64 face tiles.
  • Bumps NPC Helper, the SDK and CLI packages to 2.2.0.

2.1.1#

  • Avoids the no-NPC warning for translation-only content packs that declare NPCs = [] in mod.toml.
  • Packages a translation pack's mod.toml beside its manifest when the manifest is placed in a separate folder.

2.1.0#

  • Changes the runtime SMAPI UniqueID to Framework.Mod.NpcHelper; content pack host references and SDK-generated manifests/API lookups use the new ID. The SDK and CLI package IDs remain unchanged.
  • Groups the NPC Helper startup summary and diagnostics into one SMAPI log entry.
  • Fixes startup in Thai by supplying the English Data/NPCGiftTastes asset using the game's explicit English language code when the Thai translation mod requests its missing localized asset; translation-mod edits still apply afterward.
  • Supplies custom NPC sprites and portraits for localized asset requests, avoiding fallback attempts to load nonexistent game .xnb files.
  • Detects Thai from the localized asset suffix or locale code without treating the nested English fallback load as Thai.
  • Finds separate NPC locale packs across supported renamed/wrapped mod-manager layouts, while stopping at each mod manifest and reading only NPCs/<NpcName>/locale.

2.0.0#

Renamed: NPC Helper 2#

At the 2.0.0 release, the mod was renamed NPC Helper 2 (with a new logo in assets/branding/); only its display name changed then, while identifiers remained unchanged. The runtime ID was subsequently changed to Framework.Mod.NpcHelper.

A hardening and refactor release, plus an SDK and a cleaner file format. The NPC files are not compatible with 1.x: the format change is listed first, then the other breaking changes.

New file format (breaking)#

The NPC files were reorganised so they are shorter to write and easier to read. Nothing about what an NPC can do was removed except the path keys, which were not needed.

  • <Name>.toml is grouped into tables. The flat keys moved:

    1.x key now
    Gender, Age, Manner, SocialAnxiety, Optimism [Personality] with the same names
    BirthdaySeason, BirthdayDay [Birthday] Season, Day
    HomeRegion, DefaultMap, DefaultX, DefaultY, DefaultFacing [Home] Region, Map, X, Y, Facing
    Datable, Marriageable [Romance] with the same names
    Language, SocialTab, Calendar, EndSlideShow, IsDarkSkinned, CanReceiveGifts, CanGreetNearbyCharacters, PerfectionScore, CanCommentOnPurchasedShopItems, IntroductionsQuest, FlowerDanceCanDance [Options] with the same names
    Name, DisplayName, [Dialogue], [GiftTastes] unchanged
  • Schedules are lists of stops. [[Schedule]] blocks (seven lines per stop) became one [Schedule] table: the key is the schedule key and each stop is one string in the game's own syntax, Weekday = ["600 Town 10 12 2", "2200 bed"]. Days/Season/Day/Hearts moved into the key (fall_Mon_4, summer_12), Arrival is the a prefix, Action and EndMessage follow the facing, Goto and Raw are plain string values and NotFriendship is a first list item. The scheduler itself is unchanged; the same game strings come out.

  • No path keys, and the images are in folders. CustomSpritePath, CustomPortraitPath, DialoguePath, SchedulePath, [Sprites] and [Portraits] are gone. The files are found by name: Dialogue.toml, Schedule.toml, Marriage.toml, and all images in sprites/ and portraits/: Default.png is the main sprite sheet / portrait (was sprite.png / portrait.png), portraits/Marriage.png the wedding portrait (was portrait_marriage.png), any other name a variant by location or season. A sprite.png, portrait.png or portrait_marriage.png left in the NPC folder is reported.

  • A second, easier way to write a schedule stop. Besides the game's "600 Town 10 12 2", a stop can be spelled out: "6:00 Town x=10 y=12 face=down", with clock times (6:00, 1:30pm, 12:30am), x=/y=, up/right/down/left (or face=), anim=, and by 12:00 for "must have arrived by". Both forms can be mixed and give the same game schedule.

  • One marriage file. The marriage/ folder (engagement.toml, spouse_dialogue.toml, spouse_schedule.toml) is now Marriage.toml next to the NPC file, with [Engagement] and [Dialogue] tables; the spouse schedule is the [Marriage] table of Schedule.toml (next to [Schedule], with the same stop syntax); portrait_marriage.png sits in the NPC folder. locale/<lang>/Marriage.toml works the same way. The unsupported wedding_event.toml, spouse_room.toml and patio.toml are no longer even looked for.

  • mod.toml is no longer written by the SDK and the CLI (every NPC in NPCs/ loads); it is still read when a pack has one.

  • Every key of the old format is reported when the NPC loads, with where it lives now, so a half-converted file tells you what is left.

  • NpcDefinition.CustomSpritePath, CustomPortraitPath, DialoguePath, SchedulePath, SpriteVariants and PortraitVariants and the SDK's SpriteVariant(...) / PortraitVariant(...) (the ones that took a path) were removed; SpriteVariantFile and PortraitVariantFile remain.

New: every fixed game option is available (checked against the real game)#

Values the game itself defines now offer the game's complete real set, with the game's own names (game-options). Friendlier spellings are aliases on top of the real values.

  • New NPC options: Language (Default/Dwarvish), SocialTab (all four values; it was fixed at AlwaysShown, which is still the default), Calendar, EndSlideShow, IsDarkSkinned, CanReceiveGifts, CanGreetNearbyCharacters, PerfectionScore, CanCommentOnPurchasedShopItems, IntroductionsQuest, FlowerDanceCanDance. All reach the game's CharacterData.
  • Item categories: all 39 the game defines, by name (category:Gem, or ItemCategory.Gem in the SDK) or number. A negative number that is not a real category is reported.
  • Schedules now cover the game's whole vocabulary, read from the game's own parser: <day> keys (every season), heart-gated keys, rain2, GreenRain, passive-festival keys, bed, location omitted, time 0 (start of day), arrival (a), end message, and the GOTO, NOT friendship and raw/MAIL commands. Spouse keys include festivals.
  • The SDK enums mirror the catalog exactly (a test enforces it), and the schedule DSL has a scope for every key kind.

Changed behaviour from this (breaking)#

  • Day without Season is the game's plain <day> key (every season). 1.x wrote spring_<day>.
  • Stop times must be 0 or 600-2600 in 10-minute steps. A time such as 605 is rejected; the game matches times exactly against its 10-minute clock, so it could never fire.
  • Two stops at the same time: the later one is skipped with a warning (the game rejects the whole key, leaving the NPC with no schedule that day). Before, both were written.
  • Action must be a single animation name (the game splits on spaces); a numeric Map is rejected (the game would read it as "location omitted").
  • Map is now optional on a stop, and X/Y are not needed for bed.
  • marriageJob and bus are tied to specific vanilla NPCs; using them on a custom NPC is flagged.

New: SDK, CLI and a standard pack structure#

  • NpcHelper.StardewValley.Sdk (NuGet, no SMAPI/game dependency): define NPCs in C# with NpcBuilder and produce either a TOML content pack (NpcPackBuilder) or a DLL mod (api.Register(npc, folder)). Both run on the normal NPC Helper 2 runtime mod from Nexus.
  • npchelper CLI (NpcHelper.StardewValley.Cli, dotnet tool): new pack, new npc, new dll-mod, validate, inspect, pack.
  • Schedule problems (invalid time, map, facing, unusable spouse keys) are now reported when the NPC loads (at launch, in npchelper validate) instead of the first time the game asks for the schedule.
  • The runtime's API class is now public, and the SDK's INpcHelperApi is a strict subset of it using framework types only (checked by a test).

Breaking changes#

  • Strict validation. An NPC with an invalid Name, Gender, Age, Manner, SocialAnxiety, Optimism, BirthdaySeason, BirthdayDay, DefaultMap or DefaultFacing is rejected with a clear error. Before, Enum.Parse threw inside the Data/Characters edit, which broke every NPC.
  • NPC names may only contain letters (any language), digits, _ and -.
  • Paths are sandboxed. mod.toml entries must be relative and stay inside the content pack. Absolute paths and .. escapes are ignored with a warning. (The NPC files have no path keys any more.)
  • A stop needs a time and a tile (X Y; not for bed). Stops missing them (previously silently sent to Town 10,10), or with invalid times/maps/facings, are skipped with a warning.
  • HomeRegion must be one of the game's three regions, Town, Desert or Other (NPC.region_*). Anything else becomes Other with a warning, because no game code would ever match it.
  • Marriageable = true implies Datable = true (1.6 has one flag, CanBeRomanced).
  • Spouse schedule is written under the game's marriage_ keys. In 1.x it replaced the NPC's whole schedule with plain keys that the game ignores for spouses. Seasonal weekday overrides (Days + Season) are expanded into the date keys the game reads, because it has no marriage_<season>_<weekday> key; spouse Rain and no-Days entries are skipped with a warning. Details in the Marriage reference.
  • No longer injected (the game does not read them in 1.6): Data/NPCDispositions, Data/SpouseRooms, Data/SpousePatios, and the per-NPC wedding_<Name> event in Data/Events/Farm. The files wedding_event.toml, spouse_room.toml and patio.toml are no longer read. (The old wedding injection used a key without conditions and a shifted event script, so it could fire a malformed event on the farm.)
  • TOML escapes are now standard: \n, \t, \uXXXX are interpreted (1.x only handled \" and \\). Locale files that define [Schedule] now replace the base schedule instead of appending to it.
  • API: INpcHelperApi gained RegisterNpcFromToml, IsNpcRegistered, GetRegisteredNpcNames. RegisterNpc still exists, but it now validates and deep-copies its argument.
  • NpcDefinition.AbsoluteSpritePath / AbsolutePortraitPath were replaced by Resolved*Path properties.

Bug fixes#

  • Own NPCs/ folder: marriage files (spouse_dialogue.toml, Engagement.toml…) were registered as NPCs.

  • mod.toml with several entries on one line (NPCs = ["a", "b"]) was read as a single bad path; multi-line arrays were dropped.

  • Multi-line arrays and multi-line (""") strings in NPC files were silently dropped; table headers with a trailing # comment attached their keys to the wrong table; quoted keys kept their quotes.

  • Manner, SocialAnxiety and Optimism were never written to Data/Characters.

  • Gift tastes: item names ("Joja Cola") are now resolved to IDs (previously they were passed through and split on the space); Universal_* placeholders in empty lists were removed; a / in a gift message no longer corrupts the entry.

  • Characters/Dialogue/MarriageDialogue<Name> used Edit on an asset that does not exist for custom NPCs; it is now loaded.

  • Engagement dialogue keys that belong to other NPCs (e.g. Abigail0 in Rei's file) are no longer injected.

  • Images are loaded through each pack's SMAPI ModContent helper (correct decoding and alpha premultiplication for SMAPI 4.4) instead of raw Texture2D.FromStream, which gave dark fringes on soft edges.

  • Sprites/portraits were reloaded every time an NPC changed location and dialogue/schedule caches were flushed with them. Now only the affected image is reloaded, and only when the chosen file actually changes.

  • NPCs are spawned with the game's own Game1.AddCharacterIfNecessary instead of a hand-built NPC (the game already spawns SpawnIfMissing NPCs on load and every morning). Farmhands no longer try to spawn/warp NPCs in multiplayer.

  • OnAssetRequested no longer builds ~10 strings per NPC per asset; an exception in one NPC no longer affects the others.

  • Locale overlay files are read in a stable order.

  • Spouses were warped out of the farmhouse on every load. The 1.x "early morning" warp moved any NPC that was not at its DefaultMap whenever timeOfDay < 630, and a loaded save always starts at 6:00. The warp was redundant (the game already places NPCs) and has been removed; the schedule bootstrap now only runs for an NPC NPC Helper 2 itself just added.

  • A deeply nested array ([[[[…) overflowed the stack and killed the game. Nesting is limited to 16 levels and TOML files to 4 MB.

  • An unexpected exception while loading one NPC is now logged for that NPC instead of aborting Entry (which makes SMAPI disable the whole mod).

  • Gift tastes accept item context tags (egg_item, category_fruit) without a misleading warning; the game matches them against the gifted item.

  • After a language change, live NPCs drop their cached schedule data.

  • Data/Characters, Data/NPCGiftTastes and Data/EngagementDialogue are edited at Early priority so Content Patcher patches apply to NPC Helper 2's NPCs.

  • A marriage/ folder on an NPC that is not Marriageable now logs a warning instead of being silently ignored.

Known limitations (verified against the 1.6.15 game code)#

  • Portraits/<Name>_Marriage is shown only while the NPC speaks their wedding vows; the game never selects it anywhere else by itself.
  • MarriageDialogue<Name>Roommate, spouse rooms and patios are not provided (see the Marriage reference).
  • Gift reaction text comes from AcceptGift_* keys in the NPC's dialogue, not from the gift-taste string.

[HP] ReiMod#

  • Version 2.0.0, requires NPC Helper 2 2.0.0.
  • Gift taste Algae → Green Algae (the real item name).

1.2.0#

NpcHelper#

  • Bumped mod version to 1.2.0.
  • Added automatic deployment for [HP] ReiMod during build when EnableModDeploy=true.
  • Improved marriage systems:
    • Correct engagement data target (Data/EngagementDialogue).
    • Added spouse schedule asset injection and runtime cache invalidation.
    • Added case-insensitive marriage file resolution.
    • Added locale-aware marriage file loading (locale/<lang>/marriage).
    • Reloads marriage data on locale change.
  • Improved schedule key generation for seasonal day patterns.

[HP] ReiMod#

  • Bumped content pack version to 1.2.0.
  • Updated required NpcHelper minimum version to 1.2.0.
  • Cleaned and standardized marriage data files:
    • marriage/engagement.toml
    • marriage/spouse_dialogue.toml
    • marriage/spouse_schedule.toml
    • marriage/wedding_event.toml
  • Added file-by-file locale coverage for marriage content:
    • locale/th/marriage/*
    • locale/es-ES/marriage/*
  • Normalized dialogue key parity in locale files to match base dialogue keys.