Erannorth Reborn

Erannorth Reborn

Not enough ratings
Hands on Modding: Writing Erannorth Events in Ink Script
By [ER] Raven
In this short guide I'll show you how to write your Events in Ink Script, and how to integrate them in Erannorth's native event system. Let's get started!
   
Award
Favorite
Favorited
Unfavorite
Overview - What is Ink Script
I guess you probably wonder what is Ink Script and why you, as an Erannorth modder, should care that is now (fully) supported within our own modding framework.

Ink Script was created by Inkle Studios[www.inklestudios.com], the developers of the amazing interactive fiction games like 80 Days and the Sorcery! Series. And as it happens their framework Ink[www.inklestudios.com] is open source and can be used to write all sort of CYOA stories.

Additionally there is already a visual editor Inklewriter[www.inklewriter.com] which lets you design your Ink story through an UI editor. Add your choices there, the text outcome, even view everything as a diagram to get a better grasp of how your story flows etc.

Whatever method you choose, this produces an Ink file which you can then bring into your Erannorth mod, and have your story playable in Erannorth or simply use it as random events, to add interactions with your allies, enrich challenges with more flavor etc.

The possibilities of what you can do with this robust framework (added on top of our own) are really endless.
Editors - Writing Ink script
You can write Ink script in any text editor. But if you prefer writing your stories in a 'What you see is what you get' editor you can use Inklewriter[www.inklewriter.com].



---

Using the visual editor may tempt to you skip on learning Ink script. But I recommend that you do. Otherwise you may not be able to understand what did go wrong (if something goes wrong), or how you can do the many things the visual editor doesn't support.

There is already an excellent guide on Ink itself, so no need to recycle the same things here.

You can find the full documentation here[github.com].

---

If you prefer writing directly in Ink Script, I'd recommend to try Inky[github.com]. It doesn't have any bells and whistles, but it's pretty easy to write your Ink script there, and get error messages if you leave any loose ends, empty knots etc. It more than gets the job done ;)


Connecting your Ink story with Erannorth's Event system
So you wrote your story. Excellent! And now wonder how you can make it run in Erannorth.

(Pro Tip: don't leave that part to the end)

Below you can read everything you need to know about integrating those two together. The Vanilla Event system is document in our Guides Section/Modding Guide & the patch notes. But we won't need most of these info anyway.

What we do need is:

1) A json file in My Mod/Tales/ to act as the entry point to your Event.

That's not the json compilation of your ink file. We don't need our Ink files to be exported as jsons. They are compiled on runtime. We do need an Erannorth event json file to connect your ink file with our event system.

Let's assume that my mod is called "Chronicles of Oakstead".

I want my event to be called 'A Decayed Corpse'. I need two files:

A Decayed Corpse.ink
A Decayed Corpse.json

I place my ink file in:
Mods/Chronicles of Oakstead/Inklets/A Decayed Corpse.ink

I place my json file in:
Mods/Chronicles of Oakstead/Tales/A Decayed Corpse.json

Which has these as contents:

{
"ID":"A Decayed Corpse",
"Requirements": "",
"Unique": false,
"AutoIncludeInEventNode": true,
"MainGraphic": "Corpse4",
"Title": "You find the remains of a dead adventurer",
"Inklet":"Chronicles of Oakstead/Inklets/A Decayed Corpse"
}

Here we basically just need an ID & the Inklet path and probably a graphic. Optionally we can include it in Random Events or not, make it Unique or have requirements to show up.

2) Empty & false fields (Requirements,Unique etc.) can be safely ommited. The "Inklet" field is what makes things kick. 'A Decayed Corpse' refers to my Ink story .ink file, while Chronicles of Oakstead/Inklets is the folder it's in (My Mod/Inklets)

3) You can create .ink files either in a text editor using a very easy scripting language[github.com] or with this visual tool Inklewriter[www.inklewriter.com] but export as ink rather as a json. Unity generates different json files out of the files, than the visual tool.

This alone will make your Event playable, so you can play the story from start to finish, but of course as is it has no way of interacting with your Character. At this point you should probably want to integrate it further with Erannorth and make your story interact with your Character more.
Giving Rewards, Setting Quest States, Triggering Encounters etc.
All these stuff can happen in the Vanilla system through the rewards string. In Ink script you can pass them as tags like so and Erannorth will recognize them as 'rewards' for the Player.

  • You can define rewards, pass quest states, trigger encounters etc. directly inside the inklet as tags [# TAG # TAG # TAG] i.e like so:
    # Grant:Rewards # XP:4 # AP:-4 # Encounter:Large Spider - Lv 1 # Encounter:Large Spider - Lv 2
  • You can put the above the text or next to the text as per Ink Script syntax
  • To have the tags parsed as Rewards and not as normal tags, start with # Grant:Rewards
  • You can use any reward string the vanilla Event system supports

You can read all about what you can give as rewards, quest states etc. in our modding guide, but this is something new, and you may want to use it to make your Ink stories more live with images, as there is no support for the native Ink Script image tag.

  • You can change the Background & Main graphic of an Event after the event is created at any time using ChangeCover:Graphic & ChangeBackdrop:Graphic as a 'Reward'.
  • i.e as an inklet - # Grant:Rewards # ChangeCover:Anticipate
  • i.e as a reward in Event field - ChangeCover:Anticipate

Displaying stuff about the player in the Ink Story

You can print out the following game-specific variables in your story and choices:
  • name, gender, race, class, location, area, organization, weapon, offhand, armor, cloak
  • Syntax: '>ER>variable' ie. >ER>name - this gets replaced with the PC name once the story executes. etc. These aren't Ink Script variables so they can't be used in checks using the Ink language.

Hiding Choices, Passing Requirements

You can check for any of the usual requirements directly in your Ink script and show or not certain choices based on the check outcome. That is in addition to what you can do with Ink itself, and should be used if you want your Story "talk" with your Character.
  • Syntax: Choice Text@IF:Requirements
  • ie. * [Talk with the Seer...@IF: AP:10, Race:Human]
  • In the above example * & [] are standard ink script definition of choice, Talk with the Seer... is what the player sees as choice and @IF: AP:10, Race:Human our requirements. The player will see this choice if they are both Human & Have 10 AP at that moment.
  • ie. * [Explore the Dungeon...@IF: Rations:1, QuestStateDungeon Entry:Found] etc.
  • (I added an extra space before AP & Rations because Steam tries to replace them with icons. The correct syntax is without a space there!)
  • If there aren't any valid choices the 'Continue' button is shown instead.

Some new Encounter related features you may want to know

  • You can use Encounter:[Enemies] as a node (in custom stages, challenges, event rewards etc.)
  • i.e Encounter:Con Artist - Lv 1, Large Spider - Lv 2, will trigger an Encounter with those two enemies.
  • [Enemies] can also be pulled from the DB randomly using instead of their Names: Race, Class, Faction or Environment and instead of Level ?. With ? you take a random level between max(1, SC / 2 & SC), where SC is the amount of Stages your PC has cleared.
  • Note however that this way you may bring out a boss if they match the query requirements, and killing a boss advances the stage. This isn't a problem in Challenges, or Adventure areas but may lead to a prematurely ended Gaunlets if you kill more than one boss in the same stage.
  • i.e Encounter:Con Artist - Lv 1, Wildlife - Lv ?, Canticum Noctem - Lv 4
  • or with a Inklet tag: # Grant:Rewards # Encounter:Wildlife - Lv 1 # Encounter:Large Spider - Lv ?
  • You can also specify an Element requirement in Parenthesis ie. Encounter:Shadow (Poison) - Lv 1, Wildlife (Slashing) - Lv ?, Canticum Noctem (Astral) - Lv 4
  • Always add some sort of fallback as your query can yield no results i.e Wildlife (Bludgeoning) - Lv ? at stage 1 can't find any matching enemies.

Improved Combat Integration
  • It's now possible to resume story after triggering an Encounter through Ink Script. The Event UI is hidden and the Encounter text instead appears in a different dialog box. If you end your turn after all enemies are dead the Event UI will reappear again and you can resume the story. Trying to open a different event will tell you it's not possible and also resume from where you left things in your story.
  • You can (optionally) pass a Victory Text along the rewards that will display after the Event UI reappears with # PassVictoryText:[Text]
  • i.e #PassVictoryText:You wipe the blood from your >ER>weapon and look around...

Executing ER Functions
  • You can execute a modder exposed 'function' using ExecuteFunc:[function], (that's a different thing fron Ink Script function, and doesn't interfere with them in any way.)
  • i.e ExecuteFunc: Store:Witch, will open a Witch Store. (I added an extra space before Store because steam tries to replace it with an icon. The correct syntax is without a space there!)
  • i.e ExecuteFunc:Chest, will trigger the Chest function etc.
  • You can execute only one function per choice.
  • Note, that it's possible to Execute a function that in turn triggers an Event. Be mindful, as it will replace your current event with the one you are calling. You can find a list of the exposed functions in the modding guide.

LootOne & ChooseOne Workarounds
  • Since # is used to separate tags in Ink, whenever you need to use ChooseOne or LootOne in Ink Script you can substitute the # reward divider with >> i.e # LootOne:Random Card>>Random Card

Enemy Spawn & Death Events
  • You can hook certain Events to trigger when an Enemy Spawns or Dies
  • In EnemyDB at the Enemy's Definition, use SpawnEvent:[Event] or DeathEvent:[Event] (or both) to bind these Events to that Enemy
  • These can be story specific / unique: i.e SpawnEvent:Interact with Eldanoth, DeathEvent:Eldanoth's Demise
  • Or totally generic / more than one Enemy can have them: i.e SpawnEvent:Plan Ahead, DeathEvent:Grimoire
  • If more than one Enemies of the Encounter have Spawn/Death Events and more than one triggers at the same turn, then only the last one triggered is playable
  • If an Inklet is active but hidden ie. caused this Encounter then both Spawn & Death events are ignored

Resetting Turns & Reinforcements
  • You can reset the Turns Encounter Lasted & Reinforcement Arrived counters as an Event reward using ResetTurns:x, ResetReinforcements:x
  • if you plan on having lots of Encounters in the same node, you should probably reset these before each Encounter.
  • ie. # Grant:Rewards # ResetTurns:0 # ResetReinforcements:0 #Encounter:Random

So that's all folks!
Example 1: Overriding the vanilla Draft Event
In this example we'll be overriding the vanilla Draft event that lets you draft 12 card, with one that lets you Draft 24 cards.

Let's call our mod 'Draft Override'. We need 2 files:

Mods/Draft Override/Inklets/Draft.ink
Mods/Draft Override/Tales/Draft.json


Draft.ink

VAR CardsPicked = 0
Before starting your adventure, you need to Draft your Starting Deck.
Don't miss a pick and don't pick Consumables unless you know what are you doing. You'll need all 24 cards to create a valid deck.
-> NextPick
=== NextPick ===
{ CardsPicked < 24:
+ [Pick a Card ({CardsPicked}/24)]
Pick your next card...
# Grant:Rewards # LootOne:PickFromClass>>PickFromRace>>PickFromOrganization>>PickFromClass>>PickFromRace
~ CardsPicked++
-> NextPick
- else:
* [Done]
All done! You can now start your adventure. Good luck!
-> END
}

Draft.json

{
"ID":"Draft",
"Requirements": "",
"AutoIncludeInEventNode": false,
"MainGraphic": "Fate",
"Title": "Draft your Starting Deck",
"Inklet":"Draft Override/Inklets/Draft"
}
Example 2: A new Event written in Inklewriter
I wrote this event in the visual editor for ink files Inklewriter, that's why the script has some automatically generated labels. Once I finished I added the Erannorth specific tags.


To run this event you need two files:

Mods/Event Pack/Inklets/A Piece of Parchment.ink
Mods/Event Pack/Tales/A Piece of Parchment.json

I took the .ink file by clicking the Share button. Choose there 'Get the Story in Inklestudio's Ink Format'. Don't choose the .json format. It's not the one we'll use.

A Piece of Parchment.ink

// ---- A Piece of Parchment ----
# title: A Piece of Parchment
# author: Raven
// -----------------------------


-> youNoticeAPieceO


==== youNoticeAPieceO ====
You notice a piece of parchment tacked in the wall. It reads 'Safty toll - 50 fertings'. <i>Hmm. Safe passage for 50 farthings.</i>
There is a clay pot with a several farthings conveniently located under the sign.
+ [Pay the safety toll@IF:Farthings:50]
-> youPayTheSafetyT
+ [Continue crossing the alley]
-> youIgnoreTheNote
+ [Take the coins from the pot]
-> thereMustBeAtLea

= youPayTheSafetyT
You pay the safety toll and continue on your way. 50 farthings is nothing for you, but may as well be the food of the week for someone else... # Grant:Rewards # Farthings:-50 # Karma:4
-> END

= youIgnoreTheNote
You ignore the note, determined to continue on your way. But before you can make another step, three thugs emerge from the shadows. You draw your >ER>weapon and get ready to defend your hard earned wealth… # Grant:Rewards # Encounter:Underworld - Lv ? # Encounter:Underworld - Lv ? # Encounter:Underworld - Lv ? # PassVictoryText:You have no trouble defeating the thugs.
+ [Have a closer look at the Pot]
-> youHaveAQuickLoo
+ [Leave quickly before the City Guards Arrive]
-> youMoveOutQuickl

= thereMustBeAtLea
There must be at least 100 farthings in that pot! Who in their right mind would leave them lying on the street like this?
You are about to pick them up, when you notice three thugs emerging from the shadows.
You draw your >ER>weapon and get ready to fight... # Grant:Rewards # Encounter:Underworld - Lv ? # Encounter:Underworld - Lv ? # Encounter:Underworld - Lv ? # PassVictoryText:You have no trouble defeating the thugs.
+
-> youDecideItsBett
+ [Search the thugs for valuables]
-> youFindSomeFarth

= youHaveAQuickLoo
You grab all the coins in the pot and move out quickly. # Grant:Rewards # Farthings:50
-> END

= youMoveOutQuickl
You move out quickly before the City Guards arrive...
-> END

= youDecideItsBett
You decide it's better to move out quickly before the City Guards arrive... Whatever these thugs carry, it's not worth the risk.
-> END

= youFindSomeFarth
You find some farthings and a knapsack.
As you are about to leave though, you are accosted by a Guard Patrol.
<i>"Hey you! Halt!"</i>, one of them calls out...# Grant:Rewards # Farthings:120 # Cast:Knapsack
+ [Run!@IF:Agility:17]
-> youRunAsFastAsYo
+ [Talk your way out]
-> youExplainThatYo

= youRunAsFastAsYo
You run as fast as you can. The heavy armored guards soon loose interest to chase after you and instead turn their attention to the fallen thugs.
You hear one of them yelling:
<i>"Petronius! This one is alive. Quickly call the medic. We'll deal with that scum later..."</i># Grant:Rewards # XP:20? # Order:-3
-> END

= youExplainThatYo
You explain that you were merely defending yourself. That they attacked you and attempted to kill you.
<i>They didn't really left me much of a choice...</i>, you conclude defensively.
The guard Lieutenant seems to be convinced and decides to let you go...# Grant:Rewards # XP:10? # Order:3
-> END

A Piece of Parchment.json

{
"ID":"A Piece of Parchment",
"Requirements": "Environment:Urban",
"AutoIncludeInEventNode": true,
"Unique":false,
"MainGraphic": "Alphabet",
"Title": "You notice a piece of parchment tacked in the wall",
"Inklet":"Event Pack/Inklets/A Piece of Parchment"
}
Where to go from here?
If you need more help, jump into our Discord[discord.gg] #modding channel! I'll be happy to help and welcome you, as you embark in your magical modding journey. And of course if you come into any issues, or have suggestions on improving Ink integration, I am all ears ;)

See you there!