Horticular

Horticular

Not enough ratings
Official Mod Guide
By inDirection Games
This is the official guide for creating modifications to Horticular. An easily read PDF version is included amongst the game files in the Mod folder.
2
   
Award
Favorite
Favorited
Unfavorite
Fundamentals
This section explains how mods are structured and loaded. While the overall concept
is fairly simple, its description is conceptual. Therefore, it is suggested that you check
the Tooling and Resources section for quicker practical information
.

What is a mod?
The official method of modifying Horticular is to create a “.mpck” pack file (see the
tools section for how) that contains all the data, including metadata, such as name
and picture. In essence, mods are their own dedicated file that is installed
independently of others by placing it in the “Mods” directory.

Anatomy
Each mod is basically a change made to the virtual file system that Horticular
interacts with, whether it be introducing new content or replacing old. In fact, there
is no difference between mods and official game data.

When the game launches, it mounts all pack files to the virtual file system, keeping
track of each file so it can access it when needed. Note that official packs are
mounted first, after which mods are applied.

Example mod
The following could be the file structure contained within a mod that adds a mega
crab to the virtual file system (more on the details later):
  • Root
    • data.xml
    • MegaCrabModByTheCrabber
      • Texture
        • mega-crab.png
      • Sound
        • mega-crab.wav
        • mega-crab-hurt.wav

Overrides
Whenever packages contain files with the same path, the last mounted package overrides
the previous ones
for that particular file. Since the base game is read first, some mods
are trivial to make, such as replacing texture assets.

Due to this, it is also good to namespace files specific to your mod by keeping this
data inside a directory with a unique name. It reduces the risk of mods writing over
each other and creating incompatibility.

Some files shouldn’t be namespaced, and you can find them under "Magic Paths" and in upcoming sections.

Overrides Example
Consider the following structure in a base-game file “Base.mpck”. It has two textures
and a sound effect
  • Root
    • Texture
      • health-bar.png
      • alert-icon.png
    • Audio
      • congratulations.wav
Now consider the following mod, “MyMod.mpck”.
  • Root
    • Texture
      • alert-icon.png
    • MySuperModByRobert
      • Audio
        • congratulations.wav
When the mod is loaded, it overrides the alert icon, re-routing access to the file to
“MyMod.mpck” instead of “Base.mpck”. However, the mod doesn’t affect the sound
effect since it is namespaced into “MySuperModByRobert”.

Development Directory
While mod files are easy to share and install, it would be a hassle to create them for
every change during development. Therefore, you can use a directory as a stand-in
for a pack file, which allows you to iterate on your work quickly. Once the mod is
finished, you just package the directory, and your mod file is ready for distribution.

Both of the following mods are equivalent in effect. The difference is that one has
been packaged and the other is in its directory form:
  • MyMod.mpck
  • MyMod
    • data.xml
    • Texture
      • tiny-crab.png
NOTE: Directories don’t contain the metadata of a pack file, such as name or image,
and are therefore not suitable for general distribution.


Mod Identifier
Each mod has a unique identifier that separates it from other mods. This ensures that the game can separate content from each other and that saves aren’t broken if the player changes their mod setup, for instance, by removing a mod or reordering some.

If the game launches with two identical identifiers, it will not let the player play and will present a list of offending mods.

Identifier recommendation
When creating a mod (see the tools section), you have to enter a unique identifier
with a minimum length, so the tool already minimizes the risk of colliding identifiers.

What you can do as a mod maker is to choose a good namespace unique to you for the risk of two mods colliding to be virtually zero. For example, official example mods start with “inDirectionGames”.

Example identifiers:
  • inDirectionGames.NewTulipVariant
  • inDirectionGames.Animal.RemoveTheGoldfish
  • inDirectionGames.2023.PinkCursor

To put things in perspective. Each of the above has less than a 10^-51 chance of colliding with another mod, given random chance and just using English letters, numbers, and the full stop.
Advanced Concepts
While you can create asset replacement mods after reading the fundamentals
section, this section covers how to make changes that alter how the game plays.

Data Entries
The game uses XML files called “data.xml” to define its content and operation. These
should be located in the root of each package and are magic paths that don’t get
overridden by other packages (see more in Magic Paths).

It is highly recommended that you edit data files with the provided editor (see the
tooling section), as the many types of values would be too cumbersome to learn or
document here.

Entry IDs
Each entry has an aggregated ID that includes information on its corresponding
module (usually one per pack) and its unique number within the module. As such,
they consist of two parts:

● Module
● Number

For two IDs to be equivalent, the values of them need to be. Therefore, multiple
packs can use the same numbering, as long as they have different modules.

NOTE: The ID value is stored as a packed integer. Therefore, it is virtually required to
use the editor for entries with a non-zero Module.


When the game launches, entries with a module of 0 will be assigned one at
runtime based on its load order. This allows mod authors to add data easily without
having to keep track of other mod modules.

Should two packs contain the same entry type with the same ID, the latest pack to
load will override the others, just like with assets. This is useful when modifying
existing content.

Additions
To add new entries, you need just add them to your mod’s data file and they will be
loaded.

It is strongly recommended to use the 0-module when adding content since it
ensures that you don’t have to coordinate entry numbers with other authors.
However, should you have a good reason for a specific module, you can still specify it,
but beware of its compatibility effects.

Modifications
Modifying existing entries is done in the same way as adding new ones. The
difference is that you specify the module and ID of the edited entry. Since the base
game comes with pre-defined static IDs, these entries are easy to modify.

It is currently not possible to modify just a single property of an entry, such as the
cost of an item, so the whole entry has to be replicated. This is easily done by copying
it from the base game (or otherwise).

Removals
It is also possible to remove entries, although a bit roundabout and rarely a good
option. This is done in the same way as modifying an entry, but the data needs to be
placed inside a “data-remove.xml” in your mod’s root directory.

You do not need to specify anything but the ID of the entry to remove (although the
editor will automatically add all the fields).

NOTE: Removing entries has a higher likelihood of breaking the game since other
entries may depend on it (other mods in particular).


Asset paths
Assets referenced in entries, such as an animal texture, will almost always be loaded
automatically through the file system. Basically, the entry itself points out its asset
path. As such, most content should not be loaded through a manifest.

Text Strings
All text is provided in localization files (one per language) containing JSON-formatted
data. The format of the data is:

<Name>: {
Value: <Value>,
Comment: <Comment>,
Revision: <Number>
},


Name = The unique identifying name of the entry.
Value = The text string.
Comment = Comment for anyone working with the file.
Revision = Version information relative to the master file (en-US) and used for
official translations. You likely don’t have to worry about this
meta-information while modding.

If a requested string does not exist (no string has the name) in the player-selected
language, the game falls back to English (en-US), the master language. If the string
does not exist at all, the name will be shown instead to indicate a fully missing string.

Adding a Language
The available languages are determined by the language files that the game finds. To
add a new one, make a mod that contains a language file in the “Localization”
folder
.

Language files require a specific name format containing an identifier and a
character set: “<identifier>_<charset>.json”. For example, given the following file
name: “en-US_latin.json” we get American English (en-US) using Latin characters.

Identifier
The identifier is arbitrary but should ideally follow the BCP47 standard using a
language (ISO-639) and region (ISO-3166) code. This allows for automatic defaulting
from the OS language.

Example identifiers:
● en-US (US English)
● sv-SE (Swedish)
● ja-JP (Japanese)

Charset
Fonts do not contain every character and may be specialized to render a certain type
of character best. Therefore, each language specifies which charset is required to
render it in the game.

Currently supported charsets:
● latin (Multiple western languages)
● japan (Japanese)
● hangul (Korean)
● chn (Simplified Chinese)

Image
To see a language in the language selector, you need an image for it as images are
used to represent each language (removing reliance on specific fonts). The image
should have the identifier: “lang/<lowercase identifier>”, for example, “lang/de-de” for
German.

The texture can be placed anywhere in the virtual file system. See the "Manifests" section for
information on how to load the image.

Changing Text
To modify or add specific text entries to an existing language, you must provide a diff
file in the same directory as the original language file.

The diff-files have the file extension “.diff.json”. For example, if the original language
file is “Localization/en-US_latin.json”, the corresponding diff file would be
“Localization/en-US_latin.diff.json”.

Once a diff-file is supplied, any strings in it will be added to the original language (or
override the existing one if one already exists). Multiple mods can alter the same
languages and they will be overridden in the standard mod load order.

NOTE: It is recommended to namespace new strings to prevent future conflicts. For
instance, MySuperCoolMod_Item_Tulip_Name.


NOTE: Should you replace the original language file instead of using a diff-file, you
may prevent compatibility with other mods or future game updates.
Advanced Concepts pt. 2
Manifests
While most assets are loaded by finding paths in data.xml, some have to be supplied
in manifest files so the game knows what and how to load them. This is mostly for
base game data such as UI textures and music.

Manifest files have the appropriate extension “.manifest”. Each line specifies an
identifier and the path to an asset, using the format: “<identifier> <path>”.

To add a manifest file to your mod, you need to add a file called “mod.manifest” at
the root of your mod. All supported assets found in it will be loaded. This is as well a
magic path that doesn’t get overwritten by following mods. You can find more of
these in the Magic Paths section.

Special asset types
Textures have optional arguments after the path. It is highly recommended to check
the manifests from the base pack to see them in action.

Source rectangle <x, y, width, height> (use - for the full texture). Useful if
multiple textures should be defined from the same image file.
Animation frames <columns,rows>. Specifies how many columns and rows
that the texture is divided into.
Frame margin. Used with animation frames to add a safety margin for each
frame, effectively reducing the size of the frame by the amount of pixels given.
Used when multiple animations or textures are embedded in a single texture
to make sure textures don’t bleed into each other. As such, a value of 0 or 1
should suffice.
Frame rate. The amount of frames per second the animation should be played
at by default.

Songs for different weathers are picked up automatically if their identifier starts with
sun or rain.

Steam Workshop
When making mods for the Steam Workshop, you don’t have to do much differently
in the actual authoring. However, Steam creates a unique directory per downloaded
workshop mod:

/Steam/steamapps/workshop/content/1928540/<mod_id>

These mod directories do not allow directory loading, but you can still do your
development in the ordinary mod directory.

Furthermore, steam mods are loaded in the order of subscription date, with the
player’s latest subscribed mod being applied last. If there are any mods in the Mods
folder, they will be applied after the workshop mods.
Tooling
All tooling can be found in the “Tools” directory of the game files.

ModMaster
This tool can create pack files and open them for inspection and unpacking.

Unpack
This view lets you inspect any existing pack file, official and mod alike. Primarily, it is
used to unpack the contents into a directory. This can be used to see how the files
are structured and access its content for editing.


1. Pack file selector. Press this button to select a pack file to open. Once
opened, this button shows the path but is still pressable to select a new file.
2. Pack information. Shows metadata of the pack, including any incorporated
image.
3. Pack content. List of all files included in the pack.
4. Unpack. Press this button to unpack the file into a directory structure.

Pack
You probably guessed it: This view packs a given directory into a pack file, ready for
use as a mod.


1. Directory selector. Selects a directory to eventually pack. Once selected, it
shows the path but is still pressable to select another one.
2. Information. These pieces of mod information need to be filled in to pack the
directory. See below for additional information on the output toggle.
3. Picture selector. While not required, it is strongly recommended to add a
picture for the mod. Press the picture to open a file picker.
4. Pack content. List of all files that will be included in the pack.
5. Pack. Press this to pack the given directory into a pack file.

Output
When packing, you can select between creating a local pack file or uploading the
data directly to the Steam Workshop.

Choosing “Local File” as output, the resulting file is stored in the same directory as
the directory that was packed. Choose this option if you want to install the mod
yourself or distribute it for installation outside of the Steam Workshop.

Choosing “Steam Workshop” as output, no file is stored. Instead, the data is
immediately uploaded to the workshop. Steam has to be running and logged in to
an account that owns the game for uploading to work!

You will be able to specify a mod ID to update in case this pack is an update to an
existing mod. The ID is the one found in the workshop and is also logged upon initial
upload (no ID provided).

You will also be able to specify tags for the workshop so that people can find your
mod. This is highly recommended, as it also affects visibility within the in-game
mod browser!

DataStudio
DataStudio is the editor that the game was made with. It lets you edit the entries for
every data type. In addition, it comes with integrated string editing and translation
functionality.

Data Entries
To get started with editing or creating entries, you need to create or open a data file
(data.xml). This is done from the File menu, but you can also specify a path as the
first program argument to open it immediately.


1. Function selection. The Data section is where you view and modify entries.
Story and Validator are covered in separate sections.
2. Data types. Select the data type you wish to change.
3. Entry operations: Add a new entry; Clone the selected entry; Delete the
selected entry; Push selected ID up/down (pushing all conflicting entries as
well); Filter the view to rows with columns containing the given string.
4. Entry rows. These are the entries of the selected data type. Click one to select
it for editing, although some properties can be modified already from the row.
5. Entry details. Shows all properties of the selected entry, editable or otherwise. This is where you make the main adjustments to the game.

Since each type comes with many unique properties, the individual values won’t be
covered here. However, you will note some recurring ones:

The unique ID of an entry is color-coded blue, shown at the top, and allows
you to modify both module and number separately. Remember that module 0
is what you should use when adding content (see the Data entry section).
Names are color-coded green. They are not editable but will show the string
value it will have. The actual key/name is specified in a specific string resource
property. Some entries have similar mechanisms for description or other text.
Note: You have to load a string file from the “Strings” menu for this to show a
real value (see String editing).
References to other entries, whether they be of the same type or a different
one, are color-coded orange and entered the same way as the unique ID. If the
ID of a referenced entry changes and is located in the same data file, this value
will be updated automatically.

Story Tab
This is a tool to visualize the quests and where they lead. Each box is hoverable for
details and can be selected to show previous and following quests.

Validator Tab
This tool checks that entry-references seem correct, for example, that all letters are
attached to a quest. Running this gives you an indication of possible issues, but
there are some legitimate cases (such as external modules) that can be ignored.
Currently doesn’t work that well for mods.

String editing
In the “Strings” tab, you find the ability to load a master string file and any
translations for the master. The master editor is good for creating new strings for
your mod, while the translation is good for creating new translations.


Resources
Following are some helpful resources to get started with mod-making.

Generic Workflow
Following is a typical workflow for creating a mod.

1. (Optional) Unpack the base game (Base.mpck) found in the Data folder. This
allows you to inspect how the game was made.
2. Create your root mod folder in the mod directory, for example,
“Horticular/Data/Mods/MySuperMod”. This lets you test the mod without
packing the files.
3. Create the mod data and place it in your new folder. Check the additional
resources in this section for how to make specific changes.
4. Test that your mod works by running the game. It should be listed on the
“Mods” page, accessed from the main menu. Iterate until happy!
5. Pack your mod folder once you are ready to show your creation to the world!

Example: Asset Replacement
Asset replacement is as simple as recreating the directory structure of the base
game and adding your version of assets.

In this example, we will change the color of the mouse cursor.

1. Unpack the base content. The unpacked directory structure shows us that
the mouse cursor is found under “Texture/Base/cursor.png” and
“Texture/Base/cursor_large.png”.
2. Create our mod root directory, “PinkMouseCursor”, in “Horticular/Data/Mods”.
3. Modify both images with pink coloring and save them with the same name
under “PinkMouseCursor/Texture/Base/<name>”.

Example: Translation
Adding a new translation is pretty straightforward. You’ll need to create translated
text strings for each in the master language. You also need to make a picture for it to
display in the language selector.

In this example, we will create a small sample of a made-up language and add a
pretty picture for it.

1. Unpack the base content. The master language can be found in
“Localization/en-us_latin.json”.
2. Create our mod root: “Horticular/Data/Mods/ExampleTranslation”.
3. Create an empty translation in your mod: “Localization/te-ST_latin.json”.
4. Translate the strings. It is recommended that you use DataStudio for this,
loading the master language from #1 and your new file from #3.
5. Create the image. It can be located anywhere, but we’re using the same
directory as the base game: “Texture/UI/Language/te_st.png”.
6. Create a manifest file in the mod root, “mod.manifest”, to instruct the game
to load the image asset. The identifier of the asset should be “lang/te-st”.

Example: Text Modification
Adding or modifying text entries to an existing language uses the same
fundamentals as when creating a translation. The main difference is that a diff-file is
used.

In this example, we will make the main menu options uppercase in the English
language.

1. Unpack the base content. The English language can be found in
“Localization/en-us_latin.json”.
2. Create our mod root: “Horticular/Data/Mods/ExampleUppercaseMenu”.
3. Create a diff-file: “Localization/en-US_latin.diff.json”.
4. Add the diff-strings to “en-US_latin.diff.json”. Here, you can either add them
manually using DataStudio (make sure to use the same names) or copy-paste
the entries to change from the original and then modify them.

Example: New Data Entry
Adding a new entry will have you creating a “data.xml” file and populating it with the
additions you want to make. For most types, you will have to add a name,
description, and an asset.

In this example, we will add a blue tulip to the game.

1. (Optional) Unpack the base content. The base game tulips can be used as a
reference.
2. Create our mod root: “Horticular/Data/Mods/NewTulipExample”.
3. Create the asset “NewTulipExampleData/tulip_blue.png”. Note the
namespace directory in case another mod adds a blue tulip. In this case, we
can copy the original asset and color it blue.
4. Add a string for the name by creating “Localization/en-US_latin.diff.json” and
opening it in DataStudio. We add the namespaced string
“ItemData_NewTulipExample_Name”, with the value "Blue Tulip".
5. Add the data entry by creating a “mod.xml” in the mod root with DataStudio.
We can create the tulip from the ground up, but in this case, we just copy an
existing tulip from the base game. We also change:
a. The cost to something more fun.
b. The name resource to the one we created.
c. The texture path to the blue one.
d. ID to 0:1 Important!
e. Unlock to Store, so the player needs to buy it from the merchant.
5. Make the tulip auto unlock by adding a new constant row with Item as Data
and AutoUnlock for its Type. Provide id 0:1 (our new tulip). This tells the game
to automatically unlock the item (though since we have set it to Store, this
means it becomes available for purchase). This is done automatically in the
default sandbox modes but the story would otherwise require you to unlock
the item through a Quest, which might be overkill for this mod.
7. Add the new data to the Nemesis mode by adding a ModeMod entry. Give it
ID 0:1 and target game mode 1:1. Now the Nemesis mode (and any
dependants) will contain the tulips and the auto-unlock entry.

Example: Data Modification
Modifying an entry is the same process as adding an entry, except that you specify a
specific module to override. As such, this is mostly for modifying base game content.
Note that this replaces the full entry and not just particular values.

Related sections:
● Data Entries
● Modifications
● DataStudio

In this example, we will change keepers to have a much higher base speed.

1. Unpack the base content so we can use its data.
2. Create our mod root: “Horticular/Data/Mods/FasterKeepersExample”.
3. Copy the Keeper entry from the base game’s data.xml into our “data.xml” in
the mod root (you might want to use DataStudio to create the mod-data file
since the XML tags need to be correct).
4. Change the speed by opening our mod’s data and modifying the Speed
property of the keeper. NOTE: We keep the ID here since we want to override
the base game and not create a new kind of keeper.
5. Change the animation frame rate by a similar factor. So, for a 2x change in
speed, we probably want a 2x change in frame rate. Note that specific
animation rows may have their own frame rate to change, too.
Resources pt. 2
Example: Sandbox
This example adds a sandbox game mode where you need to earn 1M gold as quickly
as possible.

This is the most advanced example as it touches most concepts and multiple data
types. As such, the instructions will be less thorough on details already covered in
smaller examples.

1. Create the mod folder with a data.xml
2. Add a game mode to the data
a. We use Nemesis (1:1) as the parent to access all its current and future
content.
b. We also add a custom image for the mode and resource names (filled in
later) for the name and description that will be shown in the Sandbox
selector.
c. Make sure to add exclusion criteria for story to remove all story-related
stuff, otherwise, the normal Nemesis story will run.
d. We check AutoContacts to reveal all contacts.
e. We check AutoPools to pool all unlockables to be available in stores
(and other unlock methods) without any quests unlocking them.
f. We check AutoTutorials because the player should have all the tutorials
from the start.
g. We also make sure to set a starting money and add AutoItems and
AutoGround to give the player something to start with.
h. We only allow the Hard difficulty so we make sure to only check that
option.
i. We enable most features except the Guide (tutorial stuff) and the
Competition.
j. Finally, we add a couple of placeholder string resources to the intro. This
is where the player will receive the instructions.
3. Fill in game mode assets
a. Draw the picture to use.
b. Add the sandbox name to the strings.
c. Add the sandbox description to the strings.
d. Add the introduction text to the strings.
4. Add the victory condition in the Quest table
. Enter a good name and description for the quest using string resources.
b. Set it as a primary quest
c. Set it as a non-story-only quest
d. Enable force track since it’s our starting (and only) quest.
e. The type should be Task
f. No dependencies as it’s the first (and only) task.
g. Add a complete condition, add a single “Number” condition and add
the “Money” value to it. Then set the condition to greater or equal, with
the value 1000000.
h. Finally, create an end action with a cool finish. You could add a mail that
comes in but we’re just using the “ending” command to trigger the
end.

Magic Paths
The following are the magic paths to keep in mind. These files do not override other
packs and should not be namespaced.

mod.manifest = Asset loading manifest.
data.xml = Modification and addition of game data.
data-remove.xml = Removal of game data.
Localization/<name>.json = Adding a translation of the game.
Localization/<name>.diff.json = Adding/changing a string for an existing language.

Commands
There are commands that the game can run on quest completion (see the quest
data entry).

Commands can also be run from the developer console (enabled by adding
“console_enabled=true” as a program argument or a line in “settings.ini”), opened
with F1.

Following are some useful commands:

help = Shows all commands or help for a given command if run as “help
<command>”.
set <x> <y> = Set variable x to value y.
get <x> = Prints the value of variable x.
vars = Lists all variables.
crash = Crashes the game! 😳