LandTraveller

LandTraveller

Not enough ratings
Introduction to Modding
By Sayuri
This guide will help you get started in creating mods for the game, introduction you to addon packages and the Squirrel programming language.
   
Award
Favorite
Favorited
Unfavorite
Creating Addon Package
Mods are stored and distributed in plugin packages that end with the file extension ltx. There are two types of plugin packages, main modules and addon modules. The latter is more common and easier to write as they are designed to modify a single aspect of the game. We will start by creating a simple mod as a tutorial, annotating and highlighting every game character in the world you see, friend or foe. As your skill with the Squirrel programming language increases and the capability of the LandTraveller API is expanded with game updates, you will be able to create more and more complex addons.

First, you will need to create the folder that will store the content of your addon. Navigate to the game data folder. You can do this from your game library in Steam:




Then open the addon folder. You will see three plugin packages already, landt.ltx default.ltx and bench.ltx. These make up the body of content of the base game in terms of story and the default explore mode world. This is also where you will put mods you would like to install. To create a addon, create a new folder with the name of the addon (lower case ASCII letters only will work best). Lets name the addon "test" for this tutorial.



Next, we'll need to create the plugin script. Create a new file test.ltc, the name of the script should be the same as the folder, but with extension ltc. Inside the text file, write:

// Tutorial Module name = test title = "Tutorial" author = "You" major = 1 minor = 0 patch = 0 // This is only an addon main = 0

Once that's done, start the game. If everything worked, you should already see "test" appear in the list when you go to Mods from the main menu.



Since its an addon module, you don't need to select it, its already active (indicated by the blue text). The selection is for choosing a main module (or using the default one). If you go back to the addon folder, you'll also see a test.ltx file. The game compiles modules when you start it, so you've already created your first mod! Of course, it doesn't actually do anything yet..
Adding Squirrel Code
LandTraveller uses Squirrel as its modding programming language. It was designed for the purpose of adding modding support to game engines, being easy and familiar to understand yet performs quite well inside of game engines.

If you'd like to know more, you can go here:
The Squirrel Programming Language[squirrel-lang.org]

I will teach you some basic Squirrel code so its not necessary to study its documentation if you don't want to yet.

All of the resources your addon provides will need to be described in your module script. Lets add squirrel code to our addon by adding this to test.ltc:

// Our code squirrel: test { source = test.nut }

Then create a new file called test.nut inside the test folder and put this in here:

LT_log("Hello, world!");

Now open the game, press the `~ key to open the log output, then start the game in Explore mode. You should see blue text of the above message appear in the log:



You've just written and executed your first Squirrel program! Unless of course you're already familiar with the language. The function LT_log will print messages to the debug log along with everything else. What if you make a mistake while writing a program? You will see something like this instead when you start the game:



If something goes wrong during the game as the addon is running, you'll see this message (with the details being in the game's log):



LT_log is good for debugging and programming practice, but its not going to help the player who uses your mod. For that, we want to be able to get information about the world and draw it to the screen.
Drawing on the Screen
To get anything interesting to happen, to actually modify the game's behavior, you will need to use the LandTraveller API functions.

LandTraveller API[landtraveller.com]

The code that we wrote before is only executed once before the actual game starts as initialization. To draw on the screen, we need to use something called a hook. This is a Squirrel function we write that the game engine will call. For drawing on the screen, we need to set a drawing hook:

LTH_draw[landtraveller.com]

It wants the name of the function we will use. Let's write the function, and then add code that sets the hook on initialization:

function test_draw() { LT_draw_string(48,48,"Hello, world!"); } LTH_draw("test_draw");

Run the game and the text should appear on the screen:



This defines the function test_draw() first and then sets it as our drawing function. Once set in initialization, you cannot change it (it will be reported as the addon crashing). The LT_draw_string function simply draws a string, although you can have some fun with it if you look it up:

LT_draw_string[landtraveller.com]



function test_draw() { LT_draw_string(48,48,"Hello, \\c[5]world! \\i[iingotcopper.2xn]"); } LTH_draw("test_draw");

So we know how to draw to the screen, how do we get information about characters in the world and draw text next to them?
Getting Information
We want to get information about ALL the characters visible on the screen and then label them in a way that's visible, even through obstacles and walls. First, we need to look at all the characters in the current world. In LandTraveller, anything that's lose and moving about in the world, players, characters and objects, are called Entities. We can know how many there are and get any entity by index:

LT_entity_count[landtraveller.com]
LT_entity_get[landtraveller.com]

The second function returns a table that contains all the information about that entity. We can't modify the table to do anything to that entity, but we don't need to if we just want to draw information about it. Lets draw a list of all visible entities on the screen:

function test_draw() { local dx = 128; local dy = 40; // Loop over ALL entities.. for(local i = 0;i < LT_entity_count();i++) { local ent = LT_entity_get(i); if(ent.visible) // But only the ones visible on screen { LT_draw_string(dx,dy,ent.name); dy += 8; } } } LTH_draw("test_draw");

If you run the above, you'll notice the list of visible entities on the screen includes yourself and counts any entity that you might not be able to see that's just barely coming in from offscreen:



This is great, but it doesn't show us where anything is. We can use the information returned by LT_entity_get to get the location of the entity, and then convert this to screen coordinates.

LT_vec_to_screen[landtraveller.com]

Its asking for a vector and returns a vector. In LandTraveller, the world is 3D so positions have three components, x, y, and z. A vector is a Squirrel array with 3 elements in that order: x y z. If we get the entity's position from the table and convert it, we can move the text so its next to each entity:

function test_draw() { // Loop over ALL entities.. for(local i = 0;i < LT_entity_count();i++) { local ent = LT_entity_get(i); if(ent.visible) // But only the ones visible on screen { local pos = LT_vec_to_screen(ent.position); LT_draw_string(pos[0],pos[1]+12,ent.name); } } } LTH_draw("test_draw");



And that's it! We now have an addon that labels all the entities, even if they're hidden behind or inside things. Anyone you give the .ltx file to will be able to run your addon if they put it in the folder. You do not need to distribute any of the other files, just the .ltx file will do.
Change the Rules
Often you will want an addon to actually affect the gameplay or world in some way. One of the most basic ways you can impact a game like this is to take control of the damage calculations. The LandTraveller API provides hooks for modifying or overriding behavior of the game engine, so finding what hook to use is usually the starting point. In our case, the hook for damage calculation is:

LTH_damage[landtraveller.com]

Unlike with drawing, we have to create a function that takes parameters for the attacker, defender, and current damage calculation. These will be given to use every time the function is called, and the function will be called every time an attack is performed in the game. Let's implement a sort of god mode cheat by modifying the damage. The result you return gets used as the damage calculation. Add this to your code:

function test_damage(attacker,defender,damage) { damage.amount = 0; return damage; } LTH_damage("test_damage");

If you run the game, you'll see the god mode working.. on everyone. This hook is called for EVERY damage calculation no matter who! To fix this, we need some way to differentiate between enemies taking damage and the player taking damage. We can check the defender to see if they're a user (referring to an actual person playing the character).

function test_damage(attacker,defender,damage) { if(defender.isuser) damage.amount = 0; return damage; } LTH_damage("test_damage");

Now only we take no damage from attacks! Still, it would be handy if we can defeat every enemy in one hit. Lets simulate an exceptionally high critical hit that does so much damage its likely to destroy the enemy:

function test_damage(attacker,defender,damage) { if(defender.isuser) { damage.amount = 0; } else { damage.amount = defender.hpmax*3; damage.kind = 1; // 1 makes this a critical hit } return damage; } LTH_damage("test_damage");

Not only do we set the damage to three times the enemy's maximum HP, but we change the reported kind of damage so its shows up as a critical hit. Since this hook does not modify any elemental resistances, variance, and other types of damage magnification, we set the damage to far above the maximum HP just to be sure it will defeat the enemy in one hit. Of course, this isn't the only source of damage we could take, so it isn't entirely a true god mode. Still, it should make the game really easy.
Do More
This was a basic walk through of creating your first LandTraveller addon, but there's more you can do. The LandTraveller API provides the lowest level functions for interacting with the game, its up to you to write more advanced functions, design object oriented classes (if you want), and more.

An overview of what you can currently do in the full API can be found here:

LandTraveller API[landtraveller.com]


As the game is in Early Access at the time of writing this guide, this API will be extended with more and more functionality in the future.
Uploading to Steam Workshop
If you feel like sharing your mod to everyone so they can subscribe and receive updates, you'll want to upload it to the Steam Workshop.

Creating the meta file (required)

Once you've finished your cheats or memes or whatever you have the urge to share, you'll need to create a text file that describes the mod in your mod's source code folder you set up before. Go ahead and create a file with the extension .lme next to the main .ltc file:



Open this file in Notepad (or whatever text editor you prefer) and write three lines. The first line will be a short description, the second one will be the content type tag, and the third will be the theme tag. If you plan on editing the description on your item's page later to something fancy, you can leave a placeholder here as it will only be used when creating the item. The type tag and theme tags can be anything from the tags listed on LandTraveller's Steam Workshop page to the right.



More tags might be added over time, so if there's a theme you feel is really missing feel free to request adding it as a tag.

Here's an example of what to write in an .lme file:

This is a Steam Workshop world that's simply just a large version of the volcano area without the maze. Watch out, the Thermophile will show up as a fiend here! challenge dark

Note that the description must be all on one line (the example above might have been word-wrapped for you).

Setting the preview image (optional)

You don't have to decide on what the preview image should be yet, the engine will generate one for you if its missing. At any point when creating the item for the first time or updating it, you can create/edit the .png file. If creating an image, be sure its 320x180 pixels in size. An image drawn with pixel art works best! Place it next to the .lme file and the next time you create/update this item, it will appear.



It must have the same name as the main .ltc file and .lme file.

Upload!

When you're done configuring your mod for the Steam Workshop, start the game. If you created the meta files properly, you should see the option to create the Steam Workshop item appear when you select your mod from the list (under Mods from the main menu):



Just select that and the engine will create the item! If you haven't accepted the Steam Workshop legal agreement yet, it will open in the Steam overlay for you. The menu should change to this:



You can select View Online to see your new creation and edit its info, or browse for it online under LandTraveller's Steam Workshop page. When you've made changes to the mod you'd like to publish, you can come back here and select Update Steam Workshop item to do so.

And you're done! Other players will be able to subscribe to your item and it will be automatically installed the next time they start the game. If they unsubscribe, it will be automatically uninstalled upon starting the game.
3 Comments
YUNGRUSSIA 18 Jan, 2021 @ 8:02am 
неплохо:steamthumbsup:
Sayuri  [author] 9 May, 2020 @ 7:49pm 
I fixed the pages on the prop functions.

To see if an entity is a player character that is non-playable, the isplayer would be true but isuser would be false.

Over time more functionality will be added and some of the tables here will be expanded with more information.
Illuminia 9 May, 2020 @ 7:20pm 
Sounds interesting - is there any way to get properties of an NPC? I do not see anything in the "entity" class that seems like it would be able to identify an NPC, much less get properties like name / weapon preference / job etc.

Also, several links on the API Functions list under "World" give a 404 error.
LT_prop_create
LT_prop_destroy
LT_prop_get
LT_prop_parameter