Tips for Making Events from a Novice by LenneDalben

From Stardew Modding Wiki
Jump to navigation Jump to search

I recently overcame my fear of events and wrote several in a short span of time. I wanted to share some of the things I learned that helped me.

As the page title suggests, I'm not an expert. If you're looking for information from that level of expertise, check out Siv's guide and tips by Arknir.

Things I Needed

First, some things I needed before getting started.

Skills

I'm familiar with Content Patcher (CP) formatting.

  • If you're completely new to it, you're likely to have a steeper learning curve, because events have extra quirky formatting that can take time to get used to. If you're new to CP, take a look at the wiki page on CP, especially the introduction to JSON.

I have patience and determination, prior mod writing experience and prior mod troubleshooting experience.

  • Making mods already requires a certain amount of patience and willingness to troubleshoot, but events are especially trying. SMAPI tries to give you more detailed errors about where issues are in the in-game chat, but sometimes even those aren't too descriptive, so there is a lot of "review the entire event, line by line, trying to figure out what went wrong." However, if you're committed to seeing your vision become reality, you may find the results are truly worth it.

Link References

These are all the links I used at one point or another while writing events:

  • The Siv tutorial. I was initially nervous to check it because of the XNB stuff, but essentially any time XNB / yaml files are referenced, ignore that. There is a detailed breakdown and explanation of an event, piece by piece.
  • The event modding wiki page. This is the "textbook" for event modding, with a list of just about everything you can do in an event. Ctrl+F is your friend on this page. I was frequently referring to commands and the directions back and forth.
  • The great ID spreadsheet, useful for searching for music, sound effects, and other stuff.
  • The wiki page containing information on object data, if you are adding objects to your event.
    • Alternatively, check the big craftables and object (spring objects) files by unpacking your game files. You'll also need to unpack your game files to check for a base game (vanilla) event example.
  • The dialog modding wiki page, specifically the format sections. We'll use a variety of portrait commands, and depending on how fancy you're getting, also special tokens and dialog commands.
  • The mail modding wiki page, specifically the mail flags list. This helps if you want to have a condition so your event only plays if certain milestones are completed.
  • The debug commands wiki page. This lists the available debug commands, but of special interest are patch reload ModUniqueID (a command from Content Patcher, CP) and debug ebi #. These will help speed up minor edits+testing cycles, and troubleshooting+testing cycles.
  • The Debug Mode mod. It's very helpful when writing and troubleshooting events, because you can check (X, Y) coordinates and map names. You can also toggle it while an event is playing to see where the event stops, should you have an issue.
  • The json validator site. It can check for formatting and syntax issues, so it's highly recommended to run your content.json and manifest.json through that before loading up the game. Alternatively, you can check out how to set up the schema checker so that your mod is validated while you're writing it.
  • The SMAPI log parser site. It provides a lot of helpful information for troubleshooting, including getting a patch summary. If you're new to reading logs, we have a tutorial here.
  • If you're looking for an example of something in an event in a mod (dynamic tokens for code, adding temporary actors, question forks, anything else you can think of), check out Lucikiel and/or Lavril. Chances are, Arknir the eventsmith has implemented it, and you can look at that code for an example.
  • Lemurkat made a 2 part Tutorial: Creating an Event, and both are linked on that page!
  • Courtesy of Elhrvy, I learned Pathoschild made a script for i18n'ing events (formatting for translations). It is powerful! No longer will you have to deal with cutting and pasting dialog back and forth. Note that you need the latest version of LINQPad to run it successfully.
    • Note: Airyn mentioned if you're using quickQuestion in your event, double-check that the script translated strings after the quickQuestion. Sometimes it doesn't.

Getting Started

With all our relevant tabs open, CP basics in hand, unpacked game files, and after reading through the Siv tutorial, we can get started!

An Idea

First you need an idea. It can be general, like NPC X talks to NPC Y about Z topic. Then you can pick a location for this conversation to take place. Depending on how you work best, you may already know the dialog lines you want to use. If not, don't fret! I personally varied on this event by event. Sometimes I already had specific dialog, other times I came up with it while writing out the movement and placement of NPCs.

An Example Base Game (Vanilla) Event

At this point, I highly recommend trying to find a base game / vanilla example event that is similar to what you want. For instance, do you want it to be in the same location, or to start or end similarly, in terms of movement, NPC placement, center of the camera, etc. You can unpack your game files to search for those. Then, you can copy-paste applicable parts from that event to yours and edit the in-between parts according to your idea.

Scope Out Location In-Game

After you have a general idea of who is in the event, what map they should be in, and have checked if there is a vanilla example event, now is a good time to get Debug Mode, load up a save and check out the map. Toggle Debug Mode to pick (X, Y) positions for NPCs and any BigProps or objects as applicable. Debug Mode will also tell you the map name. If you want to move an NPC during the event, this is also a great time to check what the start and end positions are. You'll use those while doing math later.

Write and Test Event

Draft Event Script

Now that we know who is in the event, where we want them (both map name and positions), and have our vanilla example event, then we can get started writing the event script. I personally copied the starting bits and ending bits from a vanilla event, and edited it from there. Specify the 3 essential fields to start your event, then go from there. Are characters moving right away, or talking? Would emotes help communicate emotion?

Movement can get tricky because you have to remember that (0, 0) begins in the top left corner, and that movement is relative to the character's starting position. Also keep in mind the different numbers for the directions the characters can face. This is where math comes in and I highly recommend checking through Siv's tutorial again, specifically the section on move farmer 0 2 1/move farmer 2 0 0. I often goofed on the direction the characters are facing and had to refer to the event modding wiki page a lot.

With dialog, be careful about getting the "\Text\" format correct.

Especially if this is your first attempt with event modding, start with small steps. Have the beginning establishing shot / fade in, maybe 1 middle thing (dialog, movement, etc.), and then the ending shot / fade out. Test that. If that works ok, then add the next dialog / movement / etc., and test that. Slowly building up the event complexity helps with troubleshooting the components.

Test Event

After writing out your draft event, you can run the content.json through the json validator site and set the Format to Content Patcher. This will check for syntax issues, but won't catch everything. If you set up the json schema checker, you can skip this step because your formatting was checked while you wrote your event.

Finally, it's time to load up the game and test your event. You can trigger it based on the criteria you set (for instance, does it need to be a specific day of the week, specific weather, reach certain friendship levels, etc.), or use the command debug ebi #.

  • Note that you can't use debug ebi # on the same map the event is on. If you're on the map the event is on and try to use that command, the event won't trigger. For example, if the event is in the Forest, you can use the command debug ebi # while the farmer is anywhere but the forest.
  • Also note that if you have CP When conditions, debug ebi # can't blow past them. The reason for this is because the event doesn't actually exist if the When condition hasn't been met (thanks Airyn for the clarification!). If you're trying to quickly test your event, temporarily remove the CP When conditions so that debug ebi # will work.

It's unlikely the event will work on the first try, but if it does, congratulations, you've written your first event!

If it doesn't work on the first try, check the in-game chat for errors from SMAPI as well as the SMAPI log. Remember that you will spend quite a bit of time re-reading the event script looking for misplaced/extra quotation marks or slashes, and double checking that your formatting is like the vanilla example event and/or aligns with the event modding wiki page and Siv's tutorial. Below are some common mishaps and how to fix them:

Common Event Script Issues

Symptom / Issue Cause Fix
Event stops or gets stuck Extra or misplaced slashes or quotation marks Remove extra slashes or quotation marks, or put them in the correct location
Alternatively event gets stuck, or the farmer / player does something unexpected

(noted by Airyn)

Did not specify an actor for a command, i.e. you have faceDirection 1 or jump 5 or emote 32.

Depending on the command, the game may default to the farmer when no actor is specified (hence the farmer doing something unexpected), or just get stuck.

Make sure you specify an actor for the command:

faceDirection Jas 1 or jump Penny 5 or emote Shane 32

A command doesn't happen but event continues past it (for example, a character doesn't say their dialog line) Missing a slash or quotation marks around the command that was skipped Confirm the appropriate slash or quotation marks are in the correct location
The event unexpectedly restarts from the beginning Missed a space in between a speak command and the slash, like so: speak Sebastian\"This is dialog.\" Add the missing space between the speak command and the slash, like so: speak Sebastian \"This is dialog.\"
Character is stuck walking up against a wall or other object, and event hangs forever.

ALTERNATIVELY: characters starts walking, stops moving, and event hangs forever

Miscalculated the number of tiles a character needed to move Redo the math for the number of tiles the character needed to move
Character turns in an unexpected direction, walks off screen, and event hangs forever Combined above tile miscalculation with getting the direction wrong

ALTERNATIVELY: multiple move commands with true at the end, i.e. move Abigail 0 1 true/move Demetrius 2 0 1 true but the last move command doesn't say false.

Above math redo and double check the direction the character needs to move in

ALTERNATIVELY: if you have multiple move commands with true, make sure the last one says false.

No music / sound effect plays, and event stops Incorrect music / sound effect cue Confirm you have the correct format to set the music / sound effect, and that you're referring to the text ID (spelled and capitalized correctly), not the number ID
Dialog shows strange formatting Misplaced quotation marks or portrait commands Confirm your quotation marks and portrait commands are in the correct location
Related to above, dialog shows spaces where apostrophes should be, like That s cool instead of That's cool

(noted by Arknir)

Used curly apostrophes ‘ ’ “ ” rather than straight apostrophes ' " Replace all curly apostrophes and quotation marks with straight apostrophes and quotation marks
Character is moving in the opposite axis you intended (for instance, you specified moving 5 tiles in the X direction but the character is moving 5 tiles in the Y direction) Used advancedMove earlier in the event, and it is misbehaving Remove the advancedMove and stopAdvancedMoves command and consider an alternative. For instance, you may be able to use multiple move commands or the positionOffset command to achieve the same effect.
Character walks off into the void

(noted by Arknir)

Used /changeLocation, then /positionOffset and then had NPC walk Don't use /changeLocation and then /positionOffset. Instead use /changeToTemporaryMap and then you can use /positionOffset without issues.

NOTE: if you use move on a character after using positionOffset, they will walk off into the void. To move a character after using positionOffset, use a warp first, so positionOffsetwarpmove. Alternatively, see if you can move the character before the positionOffset.

You're using a temporary actor that you're planning to animate later (spritesheet contains the animations), and it won't display properly and instead shows a weird rectangle Did not set showFrame to the appropriate frame After the addTemporaryActor command, add showFrame <name> #
Related to above: you animated a temporary actor, but it stays stuck in the frame you specified in the original showFrame, even after you add a new showFrame command Believe it or not, setting that initial showFrame is what keeps it stuck in that frame After the animate command, you can use another animate command and set it to loop on the frame you want to show.

For instance, when you first added the temp actor, you set it to showFrame name 0. The animate command runs through frames 0 1 2, and after the animate command, you want the temp actor to stay on frame 2. Add a second animate command that loops on frame 2.

You're using quickQuestion and one of the options seems to be broken: nothing happens when you select it, and you may have warnings about an invalid command There's a slash immediately after a (break), like so:

(break)/friendship Jas 10

Delete the slash that is immediately after the break:

(break)friendship Jas 10

Remember that you can use the commands patch reload ModUniqueID and debug ebi # to speed up testing adjustments to the event.

If all else fails or you are confused, you can ask for help in #making-mods channel of the SDV Discord. Be sure to include a link of your content.json from the json validator site, your log, and a detailed description of your issue (more on that here).

Other Useful Tidbits of Knowledge

This section is a catch-all for other little things I learned, which I wanted to collect somewhere:

  • If you want multiple characters to emote at the same time, put the emote commands one after the other and add true at the end of each command like so: /emote Willy 56 true/emote Emily 32 true/emote Elliott 32 true/
  • If you want multiple characters to jump at the same time, put the jump commands one after the other like so: /jump Willy 4/jump Emily 4/jump Elliot 4/
  • If you have a lot of movement planned (either faceDirection or actual move) and you want a shortcut to getting all the directions correct, try writing in the code <up>, <down>, <left>, and <right> as needed. Then later you can search and replace all of those with the correct direction number. That way, you only have to fix the directions once.
    • Alternatively, tiakall mentioned you can think of the directions like a clock: 0 is up (12 on clock), 1 is right (3 on clock), 2 is down (6 on clock), and 3 is left (9 on clock).
  • If you are having trouble lining up characters with something, for example, Jas and Vincent are short behind a tall object like a bar / counter / shop stand, keep in mind that you can use positionOffset. For instance, for Jas and Vincent initially showing up standing on top of the shop stand: with positionOffset Jas 0 -30/positionOffset Vincent 0 -30, they will be scooched up above the shop stand to "appear" to be behind it instead, without being obscured by the top of the shop stand. See before and after positionOffset comparison from my mod Trick or Treat Event:
Example Before and After positionOffset
  • Here are some things to keep in mind about forks:
    • You can make a question fork that has different dialog responses (2+) from an NPC, and the event proceeds as normal after the different dialog. For a vanilla example of this, check out:
      • Sam's 3 heart event at the beach (ID 733330), specifically the question null part.
      • For a different approach, see Sam's 6 heart event in town (ID 45), which uses the command splitSpeak.
      • For yet another approach, see Willy's event in the Fish Shop that plays after 29 days passed (ID 16253595) and/or see the special orders board introduction event in town (ID 15389722), both which use the command quickQuestion.
    • If you want the event to proceed differently based on the player response, and not just a dialog response, it's worth noting you can only have 2 branches for the fork at a time, response A or B. After that, you can include additional forks, or "nest" them, so if you choose A, you have options C or D, while if you choose B, you have options E or F. These always come in 2. For vanilla examples, check out:
      • Simple example: Sebastian's 2 heart event in Sebastian's room (ID 2794460), specifically the question fork1 part.
      • Complex example: Penny's 8 heart event in the forest (ID 181928), specifically the question fork0 part.
      • An even more complex example is Sebastian's 6 heart event in Sebastian's room (ID 27), which uses question chooseCharacter, question fork1, and question fork0.

Ways To Add Stuff To Maps

Courtesy of Jonqora#8597 on Discord, these are explanations of a few of the commands for events.

/addBigProp can add big craftables

/addObject adds any object from springObjects

/addLantern adds any object from springObjects (but makes it glow)

/addTemporaryActor is good for anything you wanna move around, or anything weirdly shaped actually (see also /attachCharacterToTempSprite)

/removeSprite and removeTemporarySprites are useful

/changeMapTile can change part of a map to be a different tile, not sure if permanent (if so you could change it back at event end)

/makeInvisible to clear the way for movement and stuff you're adding

Usage details for each command can be found at the Event data wiki page.

Add Line Breaks in Event Scripts

Courtesy of Jonqora#8597 on Discord, this is an explanation of where you can add line breaks in events.

You can add linebreaks and extra spaces at some places in event scripts, always immediately before a /, but it depends on the command.

Adding a line break after /pause XXXX is always fine, because the pause command is never followed by more than 1 argument. The game's parser will just ignore everything after the number.

Same for /speak CharName \"text goes here\". The game will never look for a third+ argument after the dialogue string, so any line breaks or spaces after the second quotation mark will be ignored.

Problems only happen where you have commands with variable numbers of arguments or optional extra arguments. For example, /addConversationTopic topic_name would cause an error if you put a line break after it. This is because the game looks for an optional argument ([length]) if it finds anything else after topic_name. And so the line break will fail to parse as an integer argument and break.

You can also toss line breaks into dialogue strings (both inside and outside event scripts) immediately before # separators.

Example of safe line breaks in an event script:

https://cdn.discordapp.com/attachments/156109690059751424/758853928350646293/unknown.png