Tutorial: Final Boss of Events

From Stardew Modding Wiki
Jump to navigation Jump to search


So you wanna be an event guru

You want to know how to do some crazy things? You want the immersive-cutscene heart-wrenching events? You've come to the right place.

Step inside, take a seat, this is going to take awhile.

Data/Events/Temp

From other event tutorials, you've probably seen:

changeToTemporaryMap <MAP> false/bgColor 0 0 0/ambientLight 0 0 0

This is how you get the farmer to a temporary map, it does not need a full Data/Locations, but it does need to be loaded and it does need it's own Data/Event/<LOCATION> blank.json

"So how do I get to this temporary map?" You might ask. You'd have to start from somewhere viable, whether that be the Farmhouse, Farm, Beach, Railroad, take your pick.

Some things that you probably SHOULDN'T use as a TemporaryMap: Farm, "Why?" you might ask, well, unless you want the event to not show the farmhouse, it's probably not in your best interest.

"Why is there bgColor/ambientLight in this changeToTemporaryMap command?" A good question! Temporary maps are outside of the bounds of normal game logic, it does not concern itself with game time, and it does not draw the cloud backgrounds.

"Okay, so I've changed to this temporary map, now what?" You have quite a few choices, you can continue in the Data/Event/Temp block to wreak havoc amongst any map that you wish, or you can swap back to a normal changeLocation command to drop the farmer off.

Note: you will have to do the changeLocation BEFORE the switchEvent, or else the event will throw an error that there is no such event in that location.

question fork, got a knife?

Forks are generally used for yes/no questions. For a yes, it is easy to transition to the forked subevent.

The "no" aspect is for the second option in the question, where it ignores the /fork command and continues with the rest of the script.

"Lance.10Heart.pt2.12": "What should I say?#'Yes!'#'Sorry, I don't feel the same.'",

/question fork0 \"{{i18n:Lance.10Heart.pt2.12}}\"/fork LEFeelingsYes/pause 400/

Because I'm in a temporary map before the question fork, I make an editdata on the temp.json

{
  "Action": "EditData",
  "Target": "data/events/temp",
  "Entries": {
    "LEFeelingsYes": "pause 500/end"
  }
},

The /fork LEFeelingsYes is like a switchEvent, it will immediately transition into the subeventID and continue from there instead of the remainder of the event script.

What does that look like in game?

The "What should I say?" Comes up as the title of the question, the "Yes!" is the topmost option, and the "Sorry, I don't feel the same" is the bottommost option.

switchEvents and You!

So you want to keep your quickQuestions clean, or say you want to have branching paths that go to different locations, switchEvents are just for you!

switchEvents let you "continue" from the original event script with a whole new ID, this allows you to put anything you want in this new separate bubble outside of the main event script.

If you wanted to add a mailflag because the farmer said "No I don't wanna date you." you can do that with a switchEvent. (you can also do this inside of the quickQuestion, but we're here on a mission to make the obnoxiously long event scripts, not dilly dally!)

So how does a switchEvent work? You'll notice how

{{ModId}}_Answer1

doesn't require the MUSIC_ID/Viewport/Actors? You can think of the switchEvent as a fork in the road. You're still continuing your drive, but you just took a left instead of a right.

"3QKEY": "This is the Question.#'This is answer 1.'#'This is answer 2.'#'This is answer 3.'",
"i18nkey": "I am the NPC talking"

Lets take these i18n keys for a ride.

Note that I will not be adding comments INSIDE of the event script, it makes it messy and I don't personally write events on new lines.

{ 
  "LogName": "ALWAYS PUT YOUR LOGNAMES, ALWAYS.",
  "Action": "EditData",
  "Target": "data/events/Farm",
  "Entries": {
    "{{ModId}}_Heart0/": "<MUSIC_ID>
/<VIEWPORT X> <VIEWPORT Y>
/<ACTOR 1> <ACTOR 1 X POS> <ACTOR 1 Y POS> <ACTOR 1 FACING DIRECTION> <ACTOR 2> <ACTOR 2 X POS> <ACTOR 2 Y POS> <ACTOR 2 FACING DIRECTION>
/begin your event scripts here
/but wait, I wish to throw in a question for the player
/quickQuestion {{i18n:3QKEY}}(break)I am the script for answer 1\\I am continuing the script for answer 1\\switchEvent {{ModId}}_Answer1(break)I am the script for answer 2\\I am continuing the script for answer 2\\switchEvent {{ModId}}_Answer2(break)I am the script for answer 3\\I am continuing the script for answer 3
/BUT WAIT, I'M CIRCLING BACK TO THIS MAIN EVENT
/speak <NPC> \"{{i18n:i18nkey}}\"
/pause 300
/end", //take note that you need a comma because you have multiple "subevents" in this block
    "{{ModId}}_Answer1": "pause 300/I am continuing where the switchEvent for answer 1 is/", //take note how this one doesn't start like a standard event entry? think of this as continuing the original event script
    "{{ModId}}_Answer2": "pause 300/I am continuing where the switchEvent for answer 1 is/",
  } //close your entries
} //close your editdata

Notice how the event commands require \\ for every new command? Inside of a (break) quickQuestion, the commands will play out and stick to the <Answer> given until either it hits a / or a new (break)

Obviously switchEvents are best used for questions, as it gives the player choice in whichever branching path they chose.

quickQuestion Loops, the loops, brother!

Let's take the above example to start a loop. I will be using actual event commands rather than commentary.

{ 
  "LogName": "ALWAYS PUT YOUR LOGNAMES, ALWAYS.",
  "Action": "EditData",
  "Target": "data/events/Farm",
  "Entries": {
    "{{ModId}}_Heart0/": "continue/64 15/farmer 64 15 2/pause 300/switchEvent {{ModId}}_Looping",

    "{{ModId}}_Looping": "pause 300/quickQuestion {{i18n:3QKEY}}(break)switchEvent {{ModId}}_Answer1(break)switchEvent {{ModId}}_Answer2(break)switchEvent {{ModId}}_Answer3",

    "{{ModId}}_Answer1": "pause 300/message \"{{i18n:Speak}}\"/pause 300/switchEvent {{ModId}}_Looping",

    "{{ModId}}_Answer2": "pause 300/message \"{{i18n:Hear}}\"/pause 300/switchEvent {{ModId}}_Looping",

    "{{ModId}}_Answer3": "pause 300/end",
  } //close your entries
} //close your editdata

As you can see, Answer1 will loop back to the Looping subevent, which pulls back up the quickQuestion. The only way to break out of the loop is if the player selects Answer3.

Also note, subevent IDs do not require a / as it already assumes itself as a command.

Portrait Overlays Mid-Event?!

Yes!

Your portrait overlays will work if you've set them to update OnLocationChanged.

If you use a changeLocation/changeToTemporaryMap inside of your event, it will apply the overlay if you've set a mailflag to the overlay.

Let's use an example from my mod:

This is the overlay that requires the mailflag with the update set to OnLocationChange

    {
      "LogName": "Lance's Beard",
      "Action": "EditImage",
      "PatchMode": "Overlay",
      "Update": "OnLocationChange",
      "When": {
        "HasFlag": "{{ModId}}_Beard",
        "Portrait": "Vanilla Compliant"
      },
      "Target": "Portraits/Lance_Spring, Portraits/Lance_Summer, Portraits/Lance_Fall, Portraits/Lance_Winter_Indoor, Portraits/Lance_Winter_Outdoor, Portraits/Lance_Beach, Portraits/Lance_Flower, Portraits/Lance_Luau, Portraits/Lance_Spirit, Portraits/Lance_XMas",
      "FromFile": "assets/{{TargetPathOnly}}/Lance/Vanilla Compliant/LanceBeard.png"
    },

Now let's use it in an event:

{ 
  "LogName": "ALWAYS PUT YOUR LOGNAMES, ALWAYS.",
  "Action": "EditData",
  "Target": "data/events/Farm",
  "Entries": {
    "{{ModId}}_Heart0/": "continue/64 15/farmer 64 15 2/pause 300/switchEvent {{ModId}}_Looping",

    "{{ModId}}_Looping": "pause 300/quickQuestion {{i18n:3QKEY}}(break)switchEvent {{ModId}}_Answer1(break)switchEvent {{ModId}}_Answer2(break)switchEvent {{ModId}}_Answer3",

    "{{ModId}}_Answer1": "pause 300/addmailreceived {{ModId}}_Beard true/globalfade/viewport -1000 -1000/changeLocation Farmhouse/changeLocation Farm/globalfadetoclear .007 true/viewport 64 15/switchEvent {{ModId}}_Looping", //adds the beard overlay with a true mailreceived

    "{{ModId}}_Answer2": "pause 300/addmailreceived {{ModId}}_Beard false/globalfade/viewport -1000 -1000/changeLocation Farmhouse/changeLocation Farm/globalfadetoclear .007 true/viewport 64 15/switchEvent {{ModId}}_Looping", //removes the beard overlay with a false mailreceived

    "{{ModId}}_Answer3": "pause 300/end",
  } //close your entries
} //close your editdata

setSkipActions are your best friend!

So you've dug into the 1.6 migrations page, you're now curious, insatiable about what possibilities you can do.

I introduce to you, setSkipActions.

Set trigger actions that should run if the player skips the event. You can list multiple actions delimited with #, or omit [actions] so no actions are run. When the player skips, the last setSkipActions before that point is applied.

Let's take yet another example where I changed the dialogue for Lance in SVE:

    { //Lance 0 heart EVENT - An Introduction
      "LogName": "Heart Event - 0",
      "Action": "EditData",
      "Target": "data/events/Farm",
      "Entries": {
        "LEAnIntroduction/e 6951319/": "continue/-500 -500/farmer -50 -50 2 Lance -100 -100 0/setSkipActions addItem (O)FlashShifter.StardewValleyExpandedCP_Lance's_Schedule/skippable/pause 1250/emote farmer 16/pause 100/speak Lance \"{{i18n:Lance.0heart.05}}\"/pause 750/faceDirection Lance 3 true/pause 900/faceDirection Lance 0 true/pause 275/faceDirection Lance 1 true/pause 825/faceDirection Lance 0 true/pause 500/speak Lance \"{{i18n:Lance.0heart.06}}\"/pause 750/emote farmer 8/pause 250/speak Lance \"{{i18n:Lance.0heart.07}}\"/pause 900/speak Lance \"{{i18n:Lance.0heart.08}}[FlashShifter.StardewValleyExpandedCP_Lance's_Schedule]\"/pause 350/emote farmer 32/pause 250/speak Lance \"{{i18n:Lance.0Heart.09}}\"/pause 400/speak Lance \"{{i18n:Lance.0heart.011}}\"/setSkipActions/end"
      }
    },

I've placed the setSkipAction with an item before the skippable command, so that it ensures the item will be given as soon as the event is deemed 'skippable'.

If the player actually watches the entire event, the very last setSkipAction will be used, and it will not give an item since it is already given in dialogue.

playerControl got you down?

Say you want to give the player wiggle room to move around in the map. Let's give them playerControl!

Usually the ID after the playerControl is like a placebo, I generally only use the 'jellies' one, untested for other IDs.

So what does it look like, and what can you do with it?

{
  "Action": "EditData",
  "Target": "Data/Events/Farm",
  "Entries": {
    "{{ModId}}_playerControl/": "continue/0 0/farmer 0 0 0 Marlon 0 0 0/addconversationtopic {{ModId}}_ControlRepro 1/speak Marlon \"Well g'day.\"/skippable/switchEvent {{ModId}}_playerControl1",
    "{{ModId}}_playerControl1": "pause 300/speak Marlon \"Avi is too lazy to do i18n strings.\"/pause 300/addmailreceived {{Modid}}_playercontrolexplored/playerControl jellies",
    //continues to this event once playercontrol is skipped?
    "{{ModId}}_playerControl2/e {{ModId}}_playerControlrepro/n {{ModId}}_playercontrolexplored": "continue/0 0/farmer 0 0 0 Marlon 0 0 0/skippable/pause 300/speak Marlon \"This is the third dialogue box.\"/pause 300/end"
  }
},

"Woah, you've skipped several steps, how does that subevent playerControl2 have CONDITIONALS?" Technically, it isn't actually a subevent, as soon as it has conditionals, it is considered as if you made a brand new EditData block.

"Okay okay, so what does all of that even mean?" As you'll notice, I immediately give the player a 'mailflag' that solves the very next event. These are instantaneous, and can trigger subsequent events.

positionOffset, no longer a menace

So you really want those immersive events where an NPC scoots in, gives a kiss, maybe you're like me, maybe you just wanted a diggy dang ladder climbing animati--

I introduce positionOffset!

positionOffset determines based on PIXELS rather than TILES, so you can think of each command of positionOffset as a little pixel scooch of whatever actor you're using it on.

This is a very large code block, but I'll give you my ladder climbing code (because YOU'RE worth it!)

{
  "LogName": "Monster Hunting Yes After",
  "Action": "EditData",
  "Target": "data/events/temp",
  "Entries": {
    "PelicanYesAfter": "pause 300/ignoreCollisions Lance/ignoreCollisions farmer/globalfadetoclear .007 true/viewport 12 393/faceDirection farmer 0/faceDirection Lance 0/playSound doorClose/warp Lance 6 386/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 11/positionOffset Lance 0 5/pause 100/showFrame Lance 10/positionOffset Lance 0 5/pause 100/showFrame Lance 9/positionOffset Lance 0 5/pause 100/showFrame Lance 10/move Lance 0 1 2/pause 300/waitForAllStationary/move Lance 6 0 2/faceDirection Lance 3/playSound doorClose/warp farmer 6 386/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 13/positionOffset farmer 0 5/pause 100/showFrame farmer 12/positionOffset farmer 0 5/pause 100/showFrame farmer 14/positionOffset farmer 0 5/pause 100/showFrame farmer 12/move farmer 0 2 2/pause 100/move farmer 5 0 1/pause 300/speak Lance \"{{i18n:Pelican.1}}\"/pause 300/speak Lance \"{{i18n:Pelican.2}}\"/pause 500/message \"{{i18n:Pelican.3}}\"/pause 500/emote Lance 40/shake Lance 300/pause 500/speak Lance \"{{i18n:Pelican.4}}\"/pause 900/speak Lance \"{{i18n:Pelican.5}}\"/pause 500/emote farmer 56/ignoreCollisions farmer/ignoreCollisions Lance/facedirection farmer 2/pause 300/showFrame Lance 21/showFrame farmer 70/pause 200/switchEvent LEDateTransition"
  }
},

HOLY COW! THAT'S A LOT! What does it even look like, Aviroen!?

Glad you asked! Here's a short video of what it looks like. https://youtu.be/ezAMbaBuUbQ

positionOffsets are fun for doing things like this, you can also scooch NPCs in together in-between movements like if someone wanted a group photo and everyone is being crammed into a small space.

The possibilities are endless.

TemporaryAnimatedSprite and your larger-than-life NPCs

Live from down under, codeblocks from our favorite Abagaianye.

The benefits of the temporaryanimatedsprite is that you can set it's depth to be higher or lower than something, say you wish to put a rug down but you don't want to edit the map just for an event? Use TemporaryAnimatedSprite.

"temporaryAnimatedSprite TileSheets\\critters 0 192 32 32 1500 2 9999 18 14 false false 1 0.0 1 0 0 0/ -- add squirrel/
pause 1000/
removeTemporarySprites/ -- remove sitting squirrel/
temporaryAnimatedSprite TileSheets\\critters 64 192 32 32 75 6 9999 18 14 false false 1 0.0 1 0 0 0 motion 4 0/ -- add running squirrel/
pause 700/
removeTemporarySprites/ -- remove running squirrel to stop it running out the other side of the trees/"

TemporaryAnimatedSprites have the combined effort of the animate command and the regular addtemporaryactor. It also lets you completely remove the sprite with removeTemporarySprites, and you won't have to worry about bringing these actors along to a new location.

"temporaryAnimatedSprite Characters\\Aba.Hiria_Weekend 0 192 16 32 1500 1 9999 2 3 false false 9 0.0 1 0 0 0/ -- add Hiria sitting sprite/
pause 250/
removeTemporarySprites/
warp Aba.Hiria 3 5/
faceDirection Aba.Hiria 1/
pause 250/"

addTemporaryActor, your new friend in having ephemeral actors

Temporary actors must be loaded prior to calling them in your event, I like to put them at the top of my event.json just so I know they're all there, nice and snug.

{
  "LogName": "EVENT CHAR LOADS",
  "Action": "Load",
  "Target": "Characters/FallenAdventurerFemale, Characters/FallenAdventurerFemale1, Characters/FallenAdventurerFemale2, Characters/FallenAdventurerFemale3, Characters/FallenAdventurerMale, Characters/FallenAdventurerMale1, Characters/FallenAdventurerMale2, Characters/FallenAdventurerMale3, Characters/gFlame, Characters/gFlame1, Characters/gFlame2, Characters/gFlame3, Characters/ritualcircle, Characters/falllefti, Characters/fallleftL, Characters/flowerheart, Characters/lights, Characters/pinktree, Characters/springlefti, Characters/springleftL, Characters/LEarrow",
  "FromFile": "assets/{{TargetPathOnly}}/EventActors/{{TargetWithoutPath}}.png"
},

You'll notice I just shove them straight into the Characters as if they're like a normal NPC, this makes it easier to call on them later.

Let's see an example where I use them.

{ //Lance 11 heart EVENT - War Recollections
  "LogName": "Heart Event - 11",
  "Action": "EditData",
  "Target": "data/events/Farm",
  "Entries": {
    "LEBattleground/e LEFeelings/e 908078/f Lance 2750/O Lance/": "continue/-100000 -100000/farmer -1000 -1000 0 Lance -1000 -1000 0 Alesia -1000 -1000 0/skippable/warp Lance -1000 -1000/warp Alesia -1000 -1000/warp farmer -1000 -1000/viewport 64 15/playsound doorClose/warp farmer 64 15/addobject 65 18 79/move farmer 0 3 2/facedirection farmer 1/pause 50/facedirection farmer 2/pause 50/facedirection farmer 3/pause 50/facedirection farmer 0/pause 50/facedirection farmer 1/pause 100/emote farmer 40/pause 300/playsound newRecipe/message \"{{i18n:Lance.11Heart.pre}}\"/pause 100/emote farmer 16/speed farmer 6/move farmer 10 0 1 true/globalfade/viewport -1000000 -1000000/removeObject 65 18/changeLocation Custom_CastleVillageOutpost/addTemporaryActor Brianna 16 32 -100 -100 2/ignoreCollisions farmer/ignoreCollisions Lance/addtemporaryactor LEarrow 16 16 -100000 -100000 0 false/ignoreCollisions LEarrow/addTemporaryActor Drake 16 32 -99 -99 2/addTemporaryActor Gale 16 32 -98 -98 2/addTemporaryActor Edmund 16 32 -97 -97 2/addTemporaryActor Jolyne 16 32 -96 -96 2/addTemporaryActor FallenAdventurerMale 16 32 45 8 2/addTemporaryActor FallenAdventurerMale1 16 32 48 8 2/addTemporaryActor FallenAdventurerMale2 16 32 43 11 2/addTemporaryActor FallenAdventurerMale3 16 32 45 10 2/addTemporaryActor FallenAdventurerFemale 16 32 46 10 2/addTemporaryActor FallenAdventurerFemale1 16 32 52 12 2/addTemporaryActor FallenAdventurerFemale2 16 32 48 11 2/addTemporaryActor FallenAdventurerFemale3 16 32 45 13 2/"
    }
}

Obviously the meat of the event is removed, but you can add these temporary actors at any point and they will appear on the tiles that you've set.

You can also use the size requirements to do things like make your npc fish (if you've created a spritesheet, much like Fishmonger)

farmer showFrame is still the devil

So you want that cute frame of the farmer where it gives a kiss?

You gotta make sure that the farmer is using the correct faceDirection before you force showFrame on the farmer.

"Why is it like that?" Well, the farmer is a paper doll, just because you set a showFrame, doesn't mean the rest of the farmer is going to recognize that.

A lot of the time, if you do a showFrame without a faceDirection prior, the farmer's face will be... terrifying.

As a bonus, I'll give you a cute little snippet of handholding, into a kiss.

"facedirection Lance 1/facedirection farmer 3/showFrame Lance 20/showframe farmer 89 true/warp farmer 64 15/warp Lance 63 15/globalfadetoclear .007 true/viewport 65 15/pause 300/speak Lance \"{{i18n:Pelican.6.11.2}}\"/pause 300/emote farmer 56/pause 100/emote Lance 56/showFrame Lance 28/playsound dwoop/showframe farmer 101 true/pause 600/end"

I have modified the spritesheet so that Lance's frame 20 is holding hands (facing right), and using the standard frame 28 as the "kiss" frame.

beginSimultaneousCommand is your unrequited love

So you want a bunch of commands to fire off at once, but they don't have the "continuous" bool in their command, look no further! beginSimultaneousCommand is your new chaotic unrequited love.

"beginsimultaneouscommand/pause 300/textabovehead Vincent \"{{i18n:Lance.8Heart.15}}\"/move Leo 2 0 1 true/emote farmer 20/speed Vincent 7/move Vincent 2 0 1 true/speed Vincent 7/textabovehead Leo \"{{i18n:Lance.8Heart.15}}\"/move Vincent 0 1 2 true/textabovehead Jas \"{{i18n:Lance.8Heart.15}}\"/faceDirection Vincent 2/ignoreCollisions Jas/move Jas 0 1 2 true/faceDirection Penny 1/faceDirection farmer 1/faceDirection Jas 1/endsimultaneouscommand"

All of the commands between begin and end fire off simultaneously. Some of them, like "move" will not overwrite one another, so you can move an NPC twice and it will still go through one at a time.

Well what does THAT look like? https://youtu.be/NrAoN8U7HHs

When all of the kids shout "Lance!" that is where the textabovehead Vincent comes into play.

SpaceCore bonus content

SpaceCore has some great additional event commands.

Below I've put in the setDating command for the 8 heart (because I've set the romanceability to a GSQ in the data/character)

"Where's the rest of this event?" Well you see, this is a broken up switchEvent! I have switched out of the location prior with a changeLocation, and now I can pull these subevent IDs.

    {
      //Lance 8 heart pt2
      "Action": "EditData",
      "Target": "data/events/Farm",
      "Entries": {
        "LEFinally": "warp farmer 64 15/facedirection farmer 2/warp Lance 64 18/facedirection Lance 0/globalFadeToClear .007 true/viewport 64 15/pause 600/speak Lance \"{{i18n:Lance.8Heart.38}}\"/pause 300/emote farmer 8/pause 500/shake Lance 100/speak Lance \"{{i18n:Lance.8Heart.39}}\"/pause 500/shake Lance 100/speak Lance \"{{i18n:Lance.8Heart.40}}\"/pause 500/shake Lance 100/speak Lance \"{{i18n:Lance.8Heart.41}}\"/pause 500/jump farmer/emote farmer 16/pause 200/emote farmer 60/pause 500/shake Lance 200/pause 200/speak Lance \"{{i18n:Lance.8Heart.42}}\"/pause 500/emote farmer 16/pause 200/emote farmer 40/pause 200/emote farmer 60/pause 500/quickquestion {{i18n:Lance.8Heart.43}}(break)speak Lance \"{{i18n:Lance.8Heart.43.1}}\"(break)speak Lance \"{{i18n:Lance.8Heart.43.2}}\"(break)speak Lance \"{{i18n:Lance.8Heart.43.3}}\"/pause 800/shake Lance 100/pause 500/emote Lance 40/pause 300/speak Lance \"{{i18n:Lance.8Heart.44}}\"/pause 500/shake Lance 100/speak Lance \"{{i18n:Lance.8Heart.45}}\"/quickquestion {{i18n:Lance.8Heart.46}}(break)switchEvent LEFinallyYes(break)speak Lance \"{{i18n:Lance.8Heart.46.1}}\"\\pause 400\\emote Lance 40\\pause 400\\speak Lance \"{{i18n:Lance.8Heart.46.2}}\"/end",
        "LEFinallyYes": "pause 500/jump Lance/shake Lance 100/move Lance -1 0 0/move Lance 0 -3 1/ignoreCollisions Lance/faceDirection farmer 3/showFrame farmer 89 true/playsound dwoop/positionOffset Lance 5 -5/showFrame Lance 20/speak Lance \"{{i18n:Lance.8Heart.47}}\"/pause 500/emote Lance 32/pause 200/speak Lance \"{{i18n:Lance.8Heart.48}}\"/pause 500/emote Lance 32/speak Lance \"{{i18n:Lance.8Heart.49}}\"/pause 500/speak Lance \"{{i18n:Lance.8Heart.50}}\"/pause 500/emote Lance 40/pause 200/speak Lance \"{{i18n:Lance.8Heart.51}}\"/pause 200/emote farmer 20/pause 100/emote Lance 20/pause 300/showFrame farmer 101 true/playsound dwoop/showFrame Lance 28/pause 800/showframe Lance 20/showframe farmer 89 true/speak Lance \"{{i18n:Lance.8Heart.53}}\"/pause 800/emote farmer 20/emote Lance 20/pause 800/setDating Lance true/end"
      }
    },

You can even get SpaceCore to delay the wedding date with player choice!

"Choose your Wedding Date" from SpaceCore:

    {
      "Action": "EditData",
      "Target": "data/events/temp",
      "Entries": {
        "LEFeelingsYes": "pause 500/emote farmer 20/jump Lance/showframe farmer 89/removeobject 41 29/pause 300/shake Lance 300/speak Lance \"{{i18n:Lance.10Heart.pt2.13}}\"/positionoffset Lance -5 0/shake Lance 300/speak Lance \"{{i18n:Lance.10Heart.pt2.14}}\"/pause 600/speak Lance \"{{i18n:Lance.10Heart.pt2.15}}\"/pause 500/speak Lance \"{{i18n:Lance.10Heart.pt2.16}}\"/pause 300/emote Lance 20/emote farmer 20/pause 300/speak Lance \"{{i18n:Lance.10Heart.pt2.17}}\"/shake Lance 300/pause 600/speak Lance \"{{i18n:Lance.10Heart.pt2.18}}\"/pause 600/jump Lance/emote farmer 16/speak Lance \"{{i18n:Lance.10Heart.pt2.19}}\"/pause 600/speak Lance \"{{i18n:Lance.10Heart.pt2.20}}\"/quickQuestion {{i18n:Lance.10Heart.pt2.21}}(break)setEngaged Lance false 1\\addmailreceived {{ModId}}_1DayEngage(break)setEngaged Lance false 2\\addmailreceived {{ModId}}_2DayEngage(break)setEngaged Lance false 3\\addmailreceived {{ModId}}_3DayEngage(break)setEngaged Lance false 4\\addmailreceived {{ModId}}_4DayEngage(break)setEngaged Lance false 5\\addmailreceived {{ModId}}_5DayEngage/pause 600/speak Lance \"{{i18n:Lance.10Heart.pt2.22}}\"/pause 600/emote Lance 20/shake Lance 200/speak Lance \"{{i18n:Lance.10Heart.pt2.23}}\"/pause 200/emote farmer 20/emote Lance 20/globalfade/viewport -10000 -10000/playsound wand/changeLocation Farm/viewport -10000 -10000/warp farmer 65 15/warp Lance 64 15/facedirection farmer 3/showFrame farmer 89 true/showframe Lance 20/globalfadetoclear .007 true/viewport 64 15/pause 600/speak Lance \"{{i18n:Lance.10Heart.pt2.24}}\"/pause 600/quickquestion {{i18n:Lance.10Heart.pt2.25}}(break)switchEvent LEFeelingsTRANSITION(break)speak Lance \"{{i18n:Lance.10Heart.pt2.25.no}}\"/end"
      }
    },

Wedding bonus content

1.6 brought about an earthquake, but it sure brought great things along with it. Having custom weddings was one of them.

{ //well here we go female spotted
  "LogName": "New Beach Cutscene",
  "Action": "EditData",
  "Target": "Data/Weddings",
  "When": {
    "PlayerGender": "Female",
    "Custom Wedding": true
  },
  "TargetField": [
    "EventScript"
  ],

  "Entries": {
    "Lance": "sweet/-100000 -100000/farmer 43 41 2 Lance 44 55 48 Lewis 43 57 0 Camilla 44 57 0 otherFarmers 40 55 0[SetupContextualWeddingAttendees]/globalFade/specificTemporarySprite wedding/addTemporaryActor FirstSlashATTEND 94 47 46 49 2/changePortrait Lance Wedding/changePortrait Camilla LEWedding/changeLocation Custom_FableReef/playMusic wedding/viewport 44 52 clamp/showFrame Lance 53/beginSimultaneousCommand/move farmer 0 14 1/showFrame Lance 49/endSimultaneousCommand/beginSimultaneousCommand/showFrame farmer 89/endSimultaneousCommand/pause 500/speak Lewis \"[GenderedText [EscapedText [LocalizedText Strings\\StringsFromCSFiles:Utility.cs.5367 [DayOfMonth] [Season]]] [EscapedText [LocalizedText Strings\\StringsFromCSFiles:Utility.cs.5369 [DayOfMonth] [Season]]]]\"/pause 300/speak Lewis \"{{i18n:Wedding.01}}\"/pause 200/speak Lewis \"{{i18n:Wedding.02}}\"/shake Camilla 1000/speak Camilla \"{{i18n:Wedding.03}}\"/emote Camilla 28/jump Lewis 3/shake Lewis 50/speak Lewis \"{{i18n:Wedding.04}}\"/pause 400/message \"{{i18n:Wedding.05}}\"/pause 300/speak Lance \"{{i18n:Wedding.FCall.02}}\"/pause 200/beginSimultaneousCommand/emote farmer 20/emote Lance 20/endSimultaneousCommand/pause 300/speak Lewis \"{{i18n:Wedding.07}}\"/pause 300/speak Lewis \"{{i18n:Wedding.08}}\"/beginSimultaneousCommand/[ContextualWeddingCelebrations]/playsound dwoop/showFrame Lance 50/showFrame farmer 101/endSimultaneouscommand/pause 1000/beginSimultaneousCommand/showFrame Lance 49/showFrame farmer 89/endSimultaneousCommand/pause 300/message \"{{i18n:Wedding.09}}\"/message \"{{i18n:Wedding.10}}\"/globalFade/viewport -1000 -1000/changeToTemporaryMap custom_FableReef false/bgColor 0 0 0/ambientLight 0 0 0/switchEvent LE.JustMarried"
  }
},

"Woah! That's a lot of fancy things going on there! What's going on?!"

Because EventScript is nested, you'll need to dig into there before you're allowed to add your own custom entry.

This specifically targets for the NPCName, so if you'll need to use the NPC's internal name as the entry key.