Horizon's Gate

Horizon's Gate

Not enough ratings
Modding guide: custom NPC dialog
By Radiatoryang
How to author custom NPC dialog for Horizon's Gate
   
Award
Favorite
Favorited
Unfavorite
Introduction
This is a short guide about how to add custom NPC dialog to the game. This is useful for custom quests, game menu systems (e.g. vendors, shops, nations), and storytelling.

If you haven't read it already, then make sure you read the basic modding guide first:

https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=2059418137
Basic scripting syntax
Horizon's Gate stores NPC conversation dialog lines as a series of "nodes", listed in a .txt file. Think of every node as a notecard, where you write a little bit of dialog on each card, and the player can switch between the different cards. If you are conceptually familiar with other node-based dialog systems like Twine, then this is basically the same kind of idea.

- Dialog nodes start with "[DialogNode] ID={node ID};"
- Print lines of dialog with "statements={my dialog};"
- To move to another node, use "nextNodeID={node ID};"
- All lines must end with a semi-colon (";")
- Comments begin with two hyphens ("--")

Here's a simple example, where the player begins in "Node1", then gets an option to go to "Node2" or to end the conversation:

--This is a node called "Node1" with one simple choice at the end [DialogNode] ID=Node1; statements=A visitor? Well, welcome to Port Flint. Or what's left of it.; [DialogOption] text=What happened here?; nodeToConnectTo=Node2; [DialogOption] text=OK, bye.; nodeToConnectTo=; [DialogNode] ID=Node2; statements=What happened here?... Heh. I'm still trying to figure that one out.; nextNodeID=;

- "[DialogOption]" declares a conversation option, and clicking it links the player to the next DialogNode as declared in its "nodeToConnectTo" value
- To end a conversation, just leave "nextNodeID=" or "nodeToConnectTo=" blank.

Here's a more complicated example that animates the talker's portrait ("animations="), and checks to see if the player has enough money to select an option ("formulaReq="), and adds brief pauses to the text message animation ("<p>")

[DialogNode] ID=Node1; animations=stern; statements=A visitor?<p> ...<p> Well, welcome to Port Flint. Or what's left of it.; statements=Watch out for the gulns. They're a bit... volatile.; statements=The other locals won't be as accommodatin' as me, neither.; [DialogOption] text=What happened here?; nodeToConnectTo=Node2; [DialogOption] text=OK, bye.; nodeToConnectTo=; bottomOption=true; [DialogNode] ID=Node2; animations=sly; animations=; animations=stern; statements=What happened here?...<p> Heh. I'm still trying to figure that one out.; statements=My memory's a bit fuzzy though. See, I've been havin money troubles...; [DialogOption] text=Always happy to help the working class ($100); formulaReq=m:money - 99; nodeToConnectTo=Node3A; [DialogOption] text=(Lie) Can't afford it, sorry...; formulaReq=m:money - 99; nodeToConnectTo=Node3B; [DialogOption] text=<color=SlateGray>Can't afford it, sorry...; formulaReq=99 - m:money; nodeToConnectTo=Node3B; [DialogOption] text=Actually, I don't care.; nodeToConnectTo= bottomOption=true;

For more examples, look at the dialog files included with the game at: \Steam\steamapps\common\Horizon's Gate\Content\Data\SystemData\Dialog

Many of the dialog files are very tightly coupled to the game code, with many unique bespoke commands. Lots of game systems rely on dialog scripts to function, so be careful about modifying them. It's usually best to save a new copy of the .TXT you want to modify, and then start modding it.

Here's an excerpt from "dialog_questgiver.txt":

--JOB COMPLETE [DialogNode] ID=questgiver_job_complete; animations=; statements=<g=questLog>? Ah, I see.; statements=Well done. Here's your pay - $<math=g:questReward><adjX=-6>.; specialEffect=fx,sfx_questComplete; specialEffect=giveGlobalVarGP,questReward; specialEffect=modFame,trade,10; nextNodeID=questgiver_job_complete2; [DialogNode] ID=questgiver_job_complete_letter; animations=; statements=<g=questLog>? Ah, I see.; statements=Well done. Here's your pay - $<math=g:questReward><adjX=-6>.; specialEffect=fx,sfx_questComplete; specialEffect=giveGlobalVarGP,questReward; specialEffect=modFame,trade,10; specialEffect=modGlobalVar,questComplete_letter,1; nextNodeID=questgiver_job_complete2; [DialogNode] ID=questgiver_job_complete_cargo; animations=; statements=<g=questLog>, eh?; statements=Good job. Here's the $<math=g:questReward><adjX=-6> reward for the delivery.; specialEffect=fx,sfx_questComplete; specialEffect=giveGlobalVarGP,questReward; specialEffect=removeCargo_g,questGoal,10; specialEffect=modFame,trade,20; specialEffect=modGlobalVar,questComplete_cargo,1; nextNodeID=questgiver_job_complete2;
Mod workflow
Here's a simple step-by-step for writing and implementing some custom dialog for an NPC.

1. Create a new .TXT file and put it in the mods folder
(by default: C:\Users\{USER_NAME}\AppData\Roaming\BoatTactics\Mods)... It doesn't matter what you name the file, but you should probably give it a unique filename that won't clash with other peoples' files. (e.g. "MyUniqueModeName_dialog.txt")

2. In a text editor, declare at least one [DialogNode] and dialog line in the TXT file, and save. (I recommend using Notepad++ for your text editing needs.)

[DialogNode] ID=MyNewDialogNode1 statements=This is some test dialog! If you can see this in-game, then it's working!; nextNodeID=

3. In Horizon's Gate build mode, place an Actor NPC and middle-click on it. In its properties, change its "dialog node" value to the name of your DialogNode ID (e.g. "MyNewDialogNode1")

4. Exit build mode and test!

******

Some notes about working with dialog nodes:

- Make sure you use unique node ID names, or else they might clash with existing node IDs. For example, avoid node IDs like "test" or "node1", which are common names that other people might use for nodes too.

- OR, you can overwrite existing node IDs on purpose, to override the default dialog logic in the game!

- When the game loads, all dialog node files are loaded and combined into the same node network. You can access any node from any other node, as long as you know the ID. For example:

[DialogNode] ID=MyCustomNPC statements=I have nowhere to go, no one to remember me. [DialogOption] text=Um, want to join my crew? ($10); formulaReq=m:money - 9; nodeToConnectTo=crew_hire_buy [DialogOption] text=That's a sad story. Sorry.; nodeToConnectTo=;

Here, "crew_hire_buy" is the default DialogNode used for hiring new crew at a cafe. So this way you can reuse the existing dialog logic that's already built into the game!

*****

... And that's the basics. Again, make sure you look at the actual dialog TXT files included in the game to learn about all the custom functions and effects available for scripts. For more examples, look at the dialog files included with the game at: \Steam\steamapps\common\Horizon's Gate\Content\Data\SystemData\Dialog

Good luck!~


2 Comments
MasterofSegways 12 May, 2024 @ 7:56am 
This guide is wrong. Please remove outdated or incorrect guides.
MasterofSegways 5 May, 2024 @ 7:31am 
Hey, I copy and pasted your example dialog node from the workflow section into the text file, and it doesn't work. Is this guide outdated?