Erannorth Renaissance

Erannorth Renaissance

Not enough ratings
Hands on Modding: Creating your Stories with Ink
By [ER] Raven
Hi folks, In this guide, we’ll discuss how to integrate Ink scripting into your mods, allowing you to create custom stories, dialogues, and interactive events for the game. With Ink support, you can write branching narratives, skill-based choices, and dynamic interactions that respond to the player’s stats, inventory, and relationships.
   
Award
Favorite
Favorited
Unfavorite
What is Ink?
Ink is a simple yet powerful way to write interactive stories. It lets you create branching dialogue, track choices, and react to the player’s stats—all in a clean and readable format. There is no need to deal with complicated code; just focus on writing your story.

// This is a simple Ink story with branching dialogue

Hello, traveler. What brings you here?

* ["I'm looking for adventure." ]
-> adventure
* ["Just passing through." ]
-> passing_through

== adventure ==
Ah, a seeker of excitement! There’s plenty to be found if you know where to look.

* ["Do you have any leads?" ]
-> leads
* ["Actually, I changed my mind." ]
-> change_mind

== leads ==
I hear rumors of an old ruin nearby. Dangerous, but full of treasure.
-> END

== change_mind ==
No shame in that. The road ahead is long.
-> END

== passing_through ==
Safe travels, then. Watch your step on the road.
-> END

However, I am not here to teach you Ink from scratch—this guide is about using your Ink stories inside Erannorth Renaissance. If you're new to Ink or want to learn more about how it works, check out the official Ink documentation here:

Ink Scripting Language - Official Guide[github.com]

Once you’re familiar with the basics, this guide will show you how to connect your Ink stories to the game, use in-game variables, and trigger events to make your content feel fully integrated.
Adding your Ink Stories & Conversations
To add your own Ink stories to the game, follow these steps:

  • Ink stories must be provided as plain-text .ink files inside:
    Mods/ModName/Inklets

  • Each story's title must be unique, as it will serve as the Story ID in the game.
    - Consider adding your modder initials or a unique prefix to avoid conflicts.
    - Example: Instead of just Dark Prophecy.ink, use something like JD's Dark Prophecy.ink


You can generate your mod's structure using the built-in Modding Wizard. In the explorer window that opens, place your Ink files in the Inklets folder.


Once your file is in the right place, the game will be able to recognize and load your story when needed. (Requires: Erannorth Renaissance 0.6.52 or later.)

You can have as many Ink files there as you need. To call them in-game, use their ID in the appropriate section. For instance, if I were writing the Rs Flavio Convo.ink file for a custom companion, I’d do something like this:

Using the build-in Ink Editor
During the game's development, I also added a built-in Ink editor. You can use it to write short stories directly or paste in your stories to import them. It has some basic features like highlighting and line numbering.

However, for longer stories, it's still recommended to write your Ink files in your editor of choice and then import them into the game, as we discussed above.

Ink Variables & Game Data Sync
One of the most powerful features of our Ink integration is that your stories can react to game data in real time. You can access a variety of character stats, inventory items, and world information, allowing your Ink stories to feel truly dynamic.

For instance, let’s say you need to check the player's level somewhere. First, declare:
VAR Level = 0
This variable now holds the player's level; you can just use it in your Ink script.

That's all there is to it.

The following native Ink variables automatically sync with game data
  • Level (int)
  • HP (int)
  • AP (int)
  • Farthings (int)
  • Rations (int)
  • Name (string)
  • Gender (string)
  • Region (string)
  • Terrain (string)
  • Weapon (string)
  • Offhand (string)
  • Armor (string)
  • Attire (string)
  • Trinket (string)
  • Ring (string)
  • Amulet (string)
  • Cloak (string)
  • Mount (string)
  • Coercion (int)
  • Diplomacy (int)
  • Stalwart (int)
  • Warfare (int)
  • Perception (int)
  • Subterfuge (int)
  • Connections (int)
  • Survival (int)
  • Herbalism (int)
  • Druidism (int)
  • Primal (int)
  • Occult (int)
  • Rituals (int)
  • Alchemy (int)
  • Religion (int)
  • PartySize (int)

The following variables sync automatically if structured properly
  • Regional Fame: RegionName (e.g., Taymoor_Marsh (int))
  • Perks: PerkName (e.g., Bloodline_of_Amaranth (bool))
  • Companions: CompanionName (e.g., Janus (bool))
  • Companion Relationships: Rel_CompanionName (e.g., Rel_Janus (int))
  • Item Quantity: Qty_ItemName (e.g., Qty_Skeleton_Key (int))

For instance, we could check our relationship with Tabitha, and if it's greater than 10, recruit her

Triggering In-Game Effects with Ink Tags
You can also trigger in-game effects by calling pre-defined Lua methods directly from your script. This lets you change relationships, grant rewards, start quests, and much more, making your stories feel like a natural part of the game.

To call a provided Lua method, use an Ink tag in the format:
ie. # MethodName("parameter1", "parameter2", ...)

These tags run in the background, applying their effects and, if needed, providing output in the conversation log without disrupting the flow of dialogue.

e.g., # PartyXP("25") # Relationship("Marie", -10)

Provided Methods

1. Relationship & Social Effects
  • Relationship("actorId", influence) - Modifies the relationship with the specified actor.
  • Flirt("actorId", influence, "feedback") - Adjusts romance with an actor and lowers it with other romancable companions.
  • ChoiceEffect("actorId", "choice", "feedback") - Applies influence for a specific dialogue choice.
  • PartyEffect("choice", "feedback") - Applies the choice effect to all party members.
  • RelationshipHidden("actorId", influence) - Changes relationship without showing UI feedback.

2. Economy & Items
  • ExchangeAll("itemName") - Converts all of a specific item into Farthings and potential Fame.
  • Pay("farthings") - Deducts the specified amount of Farthings from the player.
  • PCAddItem("itemName", amt) - Adds an item to the player’s inventory.
  • PCRemoveItem("itemName", amt) - Removes an item from the player’s inventory.
  • RemoveItem("actorId", "category", "itemName", amt) - Removes an item from a specific actor’s inventory.

3. Experience & Progression
  • XP("actorIDs", "XPval") - Grants XP to a specific actor.
  • PartyXP("XPval") - Grants XP to the entire party.
  • PartyLost() - Removes all Farthings from the party and grants a small amount of XP.
  • IncreaseSkill("skill") - Increases a specific skill by 1.

4. Health & Survival
  • PartyRest() - Fully restores HP for all party members and advances time.
  • Wound("actorId", hp) - Inflicts a temporary wound, reducing HP.
  • PCFeed() - Restores the player’s HP, increases corruption, and advances time.

5. Morality & Corruption
  • Corruption(int v) - Modifies the player’s corruption level.
  • Murder("actorId") - Kills an NPC, increases corruption, and modifies relationships.

6. Quests & Journal Entries
  • StartQuest("questIdOrName") - Starts a quest.
  • CompleteQuest("questIdOrName", "objectiveToComplete") - Marks a quest as completed.
  • ProgressQuest("questIdOrName", "objectiveToCreate") - Progresses the quest to a new objective.
  • CompleteQObjective("questIdOrName", "objectiveToComplete") - Completes an objective.
  • AdvanceQuest("questIdOrName", "objectiveToComplete", "objectiveToCreate") - Progress the quest to an objective.
  • FailedQuest("questIdOrName", "objectiveToFail") - Marks a quest as failed.
  • MarkEntry("entryName") - Sets a journal entry as the active quest.
  • AddEntry("entryName", "entryType", "entryDescription") - Adds a new journal entry.
  • UpdateEntry("entryName", "entryType", "entryDescription") - Updates an existing journal entry.

7. Encounters & Combat
  • StartEncounter("bandId", "species", "battlefield", minEnemies, maxEnemies, "rewards") - Starts a combat encounter.
  • Encounter("bandId", "battlefield") - Starts a battle with an existing band.
  • ThisEncounter() - Triggers an encounter with the current conversant’s band.
  • ThisEncounterResolve() - Ends the current encounter and returns to the world map.
  • ThisEncounterRewards() - Distributes rewards from an ongoing encounter.
  • ThisEncounterSpoils() - Opens the barter UI for looted items.

8. World Interaction & Travel
  • TeleportTo("tileCoords") - Moves the player to specific map coordinates.
  • LocalFame(int infl) - Adjusts the player’s fame in the current region.
  • LocalFameIn("region", int infl) - Adjusts fame in a specific region.
  • AdvanceTime(int time) - Moves the game clock forward.
  • WaitTill(int time) - Sets the in-game clock to a specific time.
  • WaitTillSegment("segment") - Sets the clock to a time segment (e.g., "Night").

9. Party & NPC Management
  • Recruit("actorId") - Adds an NPC to the player’s party.
  • Dismiss("actorId") - Moves an NPC to reserves.
  • DismissAll() - Moves all active party members to reserves.
  • DismissPermanently("actorId") - Removes an NPC permanently.
  • Enemy("actorId") - Makes an NPC hostile.
  • Ally("actorId") - Converts an NPC into an ally and recruits them in Reserves.
  • ExportActor("actorId") - Exports an NPC to the actor cache.
  • RewardActor("actorId", "reward") - Grants a reward to an NPC.
  • LockCompanion("actorId") - Prevents an NPC from being dismissed or replaced.
External Methods: Checking Game Conditions
Ink lets you check game conditions using external methods, which allow your stories to react dynamically based on quests, skills, items, decisions, and more.

External methods do not change game data—they only check information. You can use them to unlock dialogue choices, determine outcomes, or trigger conditional events.

External methods work like functions that return true or false.

Before using an External method it must be declared. Let's say your story includes Rolls.

EXTERNAL Roll(string, string)

Later, you can use it like so:

~ temp HerbalismRoll = Roll("Herbalism", "Moderate")

And use {HerbalismRoll} as a condition to show or hide a choice.

The following external methods are available

You only need to declare them as EXTERNAL if you plan on using them.

1. Skill Checks & Rolls
These methods allow you to check skill rolls to determine success or failure.

  • Roll("skill", "difficulty") - Rolls a skill check. Difficulty can be Easy, Moderate, or Hard.
  • ActorRoll("actorId", "skill", "difficulty") - Rolls a skill check for a specific actor.
  • Chance(number probability) - Rolls a random chance (e.g., `Chance(75)` = 75% success).


2. Quest & Objective Tracking
Check the status of quests and objectives:

  • QuestInProgress("questName") - Returns `true` if the quest is currently active.
  • QuestNotStarted("questName") - Returns `true` if the quest hasn’t been started yet.
  • QuestCompleted("questName") - Returns `true` if the quest is fully completed.
  • ObjectiveCompleted("questName", "objectiveName") - Returns `true` if a specific quest objective is completed.
  • ObjectiveInProgress("questName", "objectiveName") - Returns `true` if a specific objective is currently active.


3. Player Decisions & Events
Check if a decision or event has occurred:

  • CheckDecision("decisionName") - Returns `true` if the player made this decision.
  • DecisionWasMade("decisionName") - Returns `true` if the decision was made, regardless of the outcome.
  • HasOccurred("eventName") - Returns `true` if an event has already happened.
  • HasNotOccurred("eventName") - Returns `true` if the event hasn’t happened yet.
  • ShouldTrigger("triggerName") - Returns `true` if the event trigger should fire.


4. Time & Environment Checks
Check in-game time and environmental conditions:

  • IsNight() - Returns `true` if it is currently nighttime.
  • IsSegment("segmentName") - Returns `true` if the game is in a specific time segment.


5. Economy & Inventory Checks
Check if the player has enough money or items:

  • CanPay("farthings") - Returns `true` if the player has enough Farthings to pay.
  • PCHasItem("itemName", number quantity) - Returns `true` if the player has the specified item in the required quantity.
  • PCTag("tagName") - Returns `true` if the player has a specific tag.


6. NPC & Relationship Checks
Check the status of relationships and companions:

  • HasTag("actorId", "tagName") - Returns `true` if the actor has a specific tag.
  • CanRomance("actorId") - Returns `true` if the NPC is romanceable.


7. Activity & Log Checks
Check if an in-game activity has been logged:

  • HasActivityOccurred("activityName", number time) - Returns `true` if an activity has occurred X times.


Below are two examples of how you could use external methods in your Ink files:



Limitations & Important Notes
Before you start creating your own Ink stories, there’s one important limitation to keep in mind:

Saving is Disabled During Custom Ink Stories.

To prevent conflicts and ensure smooth integration, the game does not allow saving while a modded Ink story is active. This means:
  • Players must complete the conversation before they can save their progress.
  • If they exit the game mid-story, they will need to start that conversation again.

Additionally, TTS (Text-to-Speech) is also disabled for modded stories.
Wrapping Up
With Ink integration, you can bring your own stories, characters, and decisions into the game, making Erannorth Renaissance even more immersive. Whether you’re creating a simple dialogue exchange or a sprawling interactive questline, this guide should give you everything you need to get started.

If you run into issues or have any questions, feel free to reach out! Happy modding!