Discussion in 'Mods' started by Platonymous, Nov 5, 2017.

  1. Platonymous

    Platonymous Big Damn Hero

    Add Custom NPCs using json csv/tsv and png files.


    How to create an NPC:

    Create a folder with the name of the NPC inside the Npcs folder.
    Add a json file with the name of the NPC inside it, that links to the tsv/csv files inside the folder.
    CSV files must use semicolon as a seperator, TSV files need to use (Tab)


    "name": "Name", *
    "displayName": "DisplayName",
    "sprite": "sprite.png", *
    "version": "1.0.0", (default is "1.0.0")
    "author": "unknown", (your name)
    "firstDay": <days played>, (default is 0)
    "condition": <Precondition>, (default is none, exp. "y 2/z summer"
    "portrait": "portrait.png", *
    "schedule": "schedule.tsv", *
    "dialogue": "dialogue.tsv", *

    "marriageDialogue": "marriageDialogue.tsv", (default is none)
    "animations": "animations.tsv", (default is none)
    "specialPositions": "positions.tsv", (default is none)
    "events": "events.tsv", (default is none)
    "mail": "mail.tsv", (default is none)
    "spouseRoom": "spouseRoom.tbin", (default is none)
    "spoudeRoomPos": [<x1>,<y1>,<x2>,<y2>], (x1y1 = upgrade 1, x2y2 = upgrade 2, default is [29, 1, 35, 10]
    "shopLocation": "<Map Name>", (default is none)
    "shopPosition": [<x>,<y>], (default is [0,0])
    "shopkeeperPosition": [<x>,<y>], (default is [0,0]
    "shopCondition": "<Precondition>", (default is none, exp. "f Abigail 100")

    "index": <objectindex>, (default is -1)
    "name": "<Objectname only used when index = -1>", (default none)
    "condition": "<Precondition>", (default is none)
    "price": <saleprice>, (default is 100)
    "type": "<Object, Ring, Hat, Weapon, Slingshot, Boots, Furniture, Cooking/Crafting Recipe, Wallpaper, Floor>" (default is Object)
    (Custom Crops can be added via name, Custom Furniture with "type": "CustomFurniture" and "name":"<folder>.<file>.<id>" exp. "Example.example.json.0")

    "map": "building1.tbin",
    "location": "<Map Name>",
    "position": [<x>,<y>]
    (default is empty)

    "name": "name_room1",
    "map": "room1.tbin",
    "isOutdoor": <true or false>, (default is false),
    "conditions": <Precondition>, (default is none, exp. "NOT f Abigail 2000"),
    "mapLocation": [0,0,0,0] (Position on NPCMapLocation Map, default is null)
    (default is empty)

    "mapEntry": "<Map Name>",
    "mapExit": "<Map Name>",
    "entry": [<x>,<y>],
    "exit": [<x>,<y>],
    "flip": <true or false> (default is false)
    (default is empty)

    "translations": [<langudage code>,<language code>,..], (default is empty)
    "translateMarriage": <true or false>, (default is true)
    "translateAnimations": <true or false>, (default is false)
    "translateSchedule": <true or false>, (default is false)
    "translateEvents": <true or false>, (default is false)
    "translateMail": <true or false>, (default is true)

    "map": "<Staring Map Name>", *
    "position": [<x>, <y>], * (Starting Position)

    "age": "<adult, teen or child>", (default is adult)
    "facing": <0, 1, 2 or 3>, (0 = up, 1 = right, 2 = down, 3 = left, default is 3)
    "gender": "<male or female>", (default is male)

    "manners": "<polite, rude or neutral>", (default is neutral)
    "homeRegion": "<Town, Desert or Other>", (default is Town)
    "relations": "<for ex. Kent 'husband'>", (default is empty)
    "socialAnxiety": "<outgoing, shy or neutral>", (default is neutral)
    "optimism": "<positive, negative or neutral>", (default in neutral)

    "datable": "<datable or not-datable>", (default is not-datable)
    "crush": "<NPCName or null>", (default is null)

    "customLocations": ["CustomLocation","AnotherCustomLocation"], (Required when using events for custom locations, default is empty)

    "birthdaySeason": "summer", *
    "birthday": 9, *

    "loves": [<objectid>, <objectid>, ... ], *
    "likes": [<objectid>, <objectid>, ... ], *
    "dislikes": [<objectid>, <objectid>, ... ], *
    "hates": [<objectid>, <objectid>, ... ] *



    TSV/CSV Structure:

    Tsv/csv files follow a simple key->value structure:
    (I use ; as a stand in for the seperator, in tsv files that would be a (Tab), don't use " " around the value)



    <Preconditon or default>;mailid;Mail Text



    Special Positions: (holds the positions for the festivals)
    <festivalname>;<x> <y> <face>
    <festivalname>;<x> <y> <face>

    key;<startFrameNr>/<framenr for repeat> <framenr for repeat> <framenr for repeat> ... /<endFrameNr>

    Special Dialogues:
    These keys are unique to the mod:

    engagement1;Dialogues for engagement
    engagement2;Dialogues for engagement
    (The Engagement Dialogues are required for datable NPCs)

    <festivalname>;Festival Dialogue
    (To give the NPC something to say during Festivals)

    loveItemDialogue;Gift Response Dialogue
    likeItemDialogue;Gift Response Dialogue
    dislikeItemDialogue;Gift Response Dialogue
    hateItemDialogue;Gift Response Dialogue
    neutralItemDialogue;Gift Response Dialogue
    (The Item Dialogues are REQUIRED for all NPCs)

    shopClosed;Shop Closed Text
    shopText;Shop Text
    (shopText is requiredfor all NPCs with shops)

    Adding Map Content:

    While rooms are full maps, Buildings and the SpouseRoom replace parts of a map.
    As such their tbin files must only inlcude the area and layers they change.
    Standart Tilesheets can be used in maps but their files should not be included in the release,
    custom tilesheets Tilesheetindex need to start with a "z".

    Variables can be used in all tsv/csv but only declared in Dialogues, Animations and Schedules:

    <Name>, <NAME>, <name> will be replaced with the NPCs name with respective capitalization
    <birthday> will be replaced with season_day according to birthday
    ::YourKey:: => will be replaced by the value in Dialouges/Animations/Schedules under YourKey.
    referenced animations won't have the / 's

    Exp. Schedule:
    Tue;1100 ::OpenShop::;1300 ::AlecEating::;1400 ::OpenShop::;1730 ::FishTankFeeding::;1800 ::InTheForest::
    OpenShop;PetShop 21 14 3
    AlecEating;AlecsRoom 19 5 0 alec_eating
    FishTankFeeding;PetShop 3 6 0 alec_fish "::FishTankFav::"
    InTheForest;Forest 91 40 2 "::LuckyRiver::"

    To create or edit TSV files, I would recommend using Google Sheets.

    Special Thanks to HopeWasHere for working with me on this.
    (The "Alec" NPC in the screenshots belongs to her and is available here:
      Last edited: Dec 11, 2017
    • DJ_Zapple

      DJ_Zapple Big Damn Hero

      Aw yiss! Now THIS should help make Zintha a reality! <3 Thanks for this mod!
      • SkyeTheNoob

        SkyeTheNoob Void-Bound Voyager

        Woah, this is super cool! I've been waiting for something like this, thank you very much for making this mod!!
        • anothersarah

          anothersarah Void-Bound Voyager

          It's exciting to see this released! I was looking at your json structure and wondering what some of the fields meant -- things like manners, socialanxiety, or relations. Is this for modder-organizational purposes, something SDV wants, or do these affect the NPC somehow ?
          • Platonymous

            Platonymous Big Damn Hero

            'manners' influence which of the standart dialogues are used. 'socialanxiety' if and how they greet other NPCs they know ('relations') when passing them. 'relations' also determin the dialogues in which NPCs tell the player about what other characters like and how they adress them. 'crush' (loveInterest in the code) was likely ment to setup the dance partners during the flower dance, but that ended up being hardcoded, so it now isn't used at all, same with optimism.

            The differences in Greeting for socialanxiety are for. ex.:
            NPC.cs.4058: "Hi..." #!String
            NPC.cs.4059: "Hi!" #!String

            And manners for ex.:
            NPC.cs.4274: "You remembered my birthday? I'm impressed. Thanks.$h" #!String
            NPC.cs.4275: "A birthday gift? That's very kind of you! I love it.$h" #!String

            The 'neutral' option in both are fake, neutral is the same as 'polite' or 'outgoing' respectively.

            I haven't counted all the dialogue differences, but from a quick search there aren't a lot. So it only adds some very small variants to the characters.
              anothersarah likes this.
            • anothersarah

              anothersarah Void-Bound Voyager

              Oh, interesting, I didn't realize those dialogue snippets were assigned from personality vs just being explicitly written. I suppose I might have wondered if I'd noticed they weren't in a dialogue file :) Thanks for the helpful response !
              • DJ_Zapple

                DJ_Zapple Big Damn Hero

                Out of curiosity, are all of the [ ] and < > required in the json?
                • anothersarah

                  anothersarah Void-Bound Voyager

                  Yes and no :) You'll need the [] in the [1,2,3] style because they are arrays of information. The <> looks like it was just trying to be informative, so you would actually write "map": "Saloon", or "facing":2,
                  • Platonymous

                    Platonymous Big Damn Hero

                    That's correct. The mod will include a template in the near future.
                    • lambee

                      lambee Subatomic Cosmonaut

                      Hello. I love this mod. Thanks for ur work!
                      I got somes question here:
                      1. What are these two used for?
                      "map": "<Staring Map Name>" *
                      "position": [<x>, <y>] * (Starting Position)
                      2. How can I add spouse room for new NPCs?
                      • lambee

                        lambee Subatomic Cosmonaut

                        Met some erros:
                        [SMAPI] Custom NPC failed on entry and might not work correctly. Technical details:
                        Newtonsoft.Json.JsonReaderException: The file at F:\Program Files (x86)\Steam\steamapps\common\Stardew Valley\Mods\CustomNPC\Npcs\Sixteen\Sixteen.json doesn't seem to be valid JSON.
                        Technical details: After parsing a value an unexpected character was encountered: ". Path 'name', line 3, position 0.
                        ? StardewModdingAPI.Framework.Serialisation.JsonHelper.ReadJsonFile[TModel](String fullPath) ?? C:\source\_Stardew\SMAPI\src\SMAPI\Framework\Serialisation\JsonHelper.cs:?? 69
                        ? StardewModdingAPI.Framework.ModHelpers.ModHelper.ReadJsonFile[TModel](String path) ?? C:\source\_Stardew\SMAPI\src\SMAPI\Framework\ModHelpers\ModHelper.cs:?? 105
                        ? CustomNPC.CustomNPCMod.loadNPCs() ?? C:\Users\David\Documents\GitHub\Stardew-Valley-Mods\CustomNPC\CustomNPCMod.cs:?? 90
                        ? CustomNPC.CustomNPCMod.Entry(IModHelper helper) ?? C:\Users\David\Documents\GitHub\Stardew-Valley-Mods\CustomNPC\CustomNPCMod.cs:?? 37
                        ? StardewModdingAPI.Program.LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, SContentManager contentManager) ? ? C:\source\_Stardew\SMAPI\src\SMAPI\Program.cs:?? 808

                        "name": "Sixteen"
                        "displayName": "Sixteen"
                        "sprite": "sprite.png"
                        "portrait": "portrait.png"
                        • anothersarah

                          anothersarah Void-Bound Voyager

                          I see you followed the json structure, but I also see now that the example doesn't show commas :)


                          "name": "Sixteen",
                          "displayName": "Sixteen",
                          "sprite": "sprite.png",
                          "portrait": "portrait.png",

                          etc. Until the last one, of course.

                          (Edit: To one of your earlier questions, I don't believe spouse-room support is in yet, but is supposed to follow.)
                            lambee likes this.
                          • .Lavender.

                            .Lavender. Big Damn Hero

                            Wanted to let you know I got my NPC working fine, but then after marriage, everything went downhill. The game doesn't seem to recognise my marriagedialouge.tsv despite picking up on the others just fine so they have no dialogue outside of the generic lines. Also, my NPC acts like we have a low relationship despite just getting married. The getting engaged and wedding were perfect, it was just post-marriage. UI shows them at 10 hearts too, yet placed them at the bottom and stuff.
                            • DJ_Zapple

                              DJ_Zapple Big Damn Hero

                              So... Is there another way to make .tsv files besides Google Sheets? I've had to use my phone for internet, and can't tether.
                              • Platonymous

                                Platonymous Big Damn Hero

                                Fixed that json example. Spouseroom is working in my dev build, so it will be in the next version the json for that is going to be:
                                "spouseRoom": "SpouseRoom.tbin"
                                with an optional "spouseRoomPos": [ 29, 1, 35, 10 ] (<x1>,<y1>,<x2>,<y2>) for the spouseroom positions in upgrade 1 and 2 Farmhouses.
                                The spouse room tbin has to only contain the spouseroom, so in most cases a 6 by 9 and custom tilesheets need to have a "z" as there first letter(only as the id).
                                Though not tested yet, in theory you could add a new kitchen or whole new rooms to the house if you want.

                                It's one of of few experimental features that are coming in the next version, that most people can just leave out, but if someone want's to combine his NPC with a mod that changes the farmhouse layout, there you go.

                                You could just use something like notepad+ and make a simple textfile that looks like this:

                                Introduction;This is my Introduction Dialogue
                                Mon;This is my Monday Dialogue
                                spring_1;You get the idea..

                                save it as a .csv and reference that in the json.

                                The marriage dialogue should work, it does at my end at least, and I don't think I made any changes in my dev version regarding marriage dialogues. Are you using the right keys for the Marriage Dialogues, they have special ones, for ex: Rainy_Day_0 or Indoor_Day_2.

                                The other error I have no idea yet, it's not happening for me, but I look into it. Any Errors in the console, any mods your using that could have an influence?
                                  Last edited: Nov 12, 2017
                                  anothersarah likes this.
                                • DJ_Zapple

                                  DJ_Zapple Big Damn Hero

                                  Ah. Well, that certainly helps. So I take it they pretty much use the same file structure as the base game? Means I can pull this off ten times more easily.
                                  • Diotheawesome

                                    Diotheawesome Poptop Tamer

                                    So that's how its done, Thanks for making it clear
                                    • .Lavender.

                                      .Lavender. Big Damn Hero

                                      Yes. I also tested with a vanilla NPC's marriage dialogue and still nothing.

                                      Also, I'm a bit lost on the right formatting for events in the tsv files.

                                      Say | represents a cell, I've been trying:
                                        911526 | f Alex 2500/t 1900 2200/n joshMessage: "gusviolin | -1000 -1000/farmer 5 5 1 Gus 10 6 2 Alex 9 5 3 Emily 9 17 2/skippable/showFrame 117/showFrame Alex 39....
                                      But that didn't work. I then tried putting every command in its own cell, but also nothing. I'm a little lost.
                                      • Platonymous

                                        Platonymous Big Damn Hero

                                        Here's an example of a working event:

                                        Farm | ID89/t 600 900/w sunny | continue | 64 15 | farmer 64 16 2 Florence 64 18 0 | pause 500 | skippable | emote farmer 8 | pause 500 | speak Florence "::intro_Event1::" | faceDirection Florence 3 | pause 500 | speak Florence "::intro_Event2::" | faceDirection Florence 0 | speak Florence "::intro_Event3::" | emote farmer 40 | emote farmer 8 | speak Florence "::intro_Event4::" | emote farmer 16 | speak Florence "::intro_Event5::" | emote farmer 16 | speak Florence "::intro_Event6::" | question fork1 "::intro_Event7::" | fork gotGuts | speak Florence "::intro_Event8::" | move Florence 0 2 2 | pause 250 | animate Florence false true 100 ::flo_smoke_event:: | pause 1000 | speak Florence "::intro_Event9::" | end
                                        Farm | gotGuts | emote Florence 16 | speak Florence "::gotGuts_Event1::" | emote Florence 56 | emote farmer 8 | speak Florence "::gotGuts_Event2::" | emote farmer 40 | speak Florence "::gotGuts_Event3::" | end
                                        ID## and ::abc:: are variables, introduced in the next version, in the current version ID## would be your eventid and ::abc:: would be whatever text or (in the case of ::flo_smoke_event:: ) animation you want to display.
                                          HopeWasHere likes this.
                                        • Platonymous

                                          Platonymous Big Damn Hero

                                          I added the new features in 0.9.0 (spouseroom, mail, buildings, rooms, warps, shop, translations, variables) to the description, all are optional.

                                          Share This Page