Tips for Making Events from a Novice by LenneDalben
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.
- Another tutorial that breaks down an event is available here on this wiki: Tutorial: Anatomy of an Event
- 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 Ways to Add Stuff to Maps explanation below, because it explained its title nicely.
- The emote ID list
- 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) anddebug ebi #
. These will help speed up minor edits+testing cycles, and troubleshooting+testing cycles.- The commands available in CP are on the troubleshooting guide under the author guide on Github.
- 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 thequickQuestion
. Sometimes it doesn't.
- Note: Airyn mentioned if you're using
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 commanddebug 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 thatdebug 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:
|
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 |
Above math redo and double check the direction the character needs to move in
ALTERNATIVELY: if you have multiple |
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 |
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 |
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:
|
Delete the slash that is immediately after the break:
|
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 actualmove
) 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: withpositionOffset 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 afterpositionOffset
comparison from my mod Trick or Treat Event:
- 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
.
- Sam's 3 heart event at the beach (ID 733330), specifically the
- 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
, andquestion fork0
.
- Simple example: Sebastian's 2 heart event in Sebastian's room (ID 2794460), specifically the
- 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:
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 |