Sign in to follow this  
rooks

Your First Mod

Recommended Posts

rooks    240

Overview

This is a very brief set of instructions on how to create a new empty mod for Griftlands.  This is not a tutorial and assumes basic knowledge of Lua.  The best way to learn how to add specific pieces of content to your mod is to subscribe to Shel's Adventure and Havarian and view the code.  These example mods illustrate many basic features, like adding cards, grafts, and new campaigns.

 

Running the game in debug

Running the game in debug will unlock a slew of facilities to aid you in development.  It is not strictly necessary to run in debug to either run or develop mods, but it will probably be helpful.


 Epic -> Go to Settings > Griftlands and check "Additional Command Line Parameters".  In the edit box, enter --debug.
 Steam -> Right click Griftlands in your library and click "Properties".  Click "Set Launch Options", enter --debug in the edit box and click Ok.

A description of all the game's debug functionality is beyond the scope of this article, but for our purposes, it is useful to know that CTRL+5 will open a debug panel listing any mods the game has discovered.  Once you create a mod or (eventually) install other user-created mod content, you will see their appearance here.  You can enable or disable them from this panel.

Creating an empty mod

Browse to your Griftlands save directory.
  Windows/Steam -> %APPDATA%/Klei/Griftlands/steam-<steamID>/
  Windows/Epic -> %APPDATA%/Klei/Griftlands/<EpicID>/

If you see a saves/ directory, a log.txt, and other game-generated files, you will know you are in the right place!  Create a new folder named 'mods' if one doesn't already exist.  This folder houses all local mod content.

Inside the 'mods' folder, create another folder with the name of your mod.

Inside that folder, create a text file called modinit.lua.  This file will be executed when your mod is installed and enabled.  This file should return a table which will serve as your mod's run-time state.  There are a few properties it can have which have special meaning.  Here are some of them:

  OnLoad: this must be a function that receives one parameter, your mod's table.  This function is called by the game after loading all core game content and is where your mod can load its own assets and game content.

  OnPreLoad: this must a be a function that receives one parameter, your mod's table.  This function is similar to OnLoad, but is called BEFORE the game loads all its game content.  In general, the only reason to use OnPreLoad is to load .po files for translations, because these need to be in memory before the rest of the game content is loaded for string lookup.

  alias: This is an optional (but useful) string which specifies a filepath alias by which your mod can reference files within its directory.

  title: This is the name that will represent your mod when you see it in game. When you upload your mod to Workshop for the first time, it will be named after this string.

  description: This is a description of what your mod is. When you upload your mod to Workshop for the first time, it will receive this description.

  previewImagePath: This is a path to a filename of a .png within your mod directory that will be used as the when your item is seen in the Workshop.
 

Sharing Your Mod

One way to share your mod is simply to distribute your folder to players.  They can then use the above process to copy your mod in to their local mods/ folder.

If you are playing Grifltands on Steam, the preferred way is to use Steam Workshop to distribute your mods, and also download other mods.  Note that the mods distributed through Steam Workshop do not appear in your local user folder, but in a special Steam folder on your computer.


Uploading to Steam Workshop

To share a mod that you have locally in your settings folder, you must first enable --debug mode.  Then, hit CTRL+5 to open the Mod inspector.  In this panel you should see your own mod listed.

Click the "Upload to Workshop" button to upload your mod to Steam!

The first time your mod is uploaded, you may notice a new file called steam_workshop.txt in your mod folder.  You should keep this file, as it references the workshop id of your mod.  The next time you upload to Workshop, this file is used to update the same workshop item you previously uploaded.


Deleting your mod from Workshop

If you no longer wish to distribute your mod, you can Delete it by signing into Steam Workshop and clicking the "Delete" option under Owner Controls.

Note that any user which has already subscribed and downloaded your mod will continue to have access to it, until they Unsubscribe.

If you wish to later redistribute your mod again, you will need to ensure you are creating a NEW workshop item for it.  To do this, delete the auto-generated file steam_workshop.txt in your mod folder.  This will ensure a new workshop item is generated the next time you upload.  If you try to Upload your mod with the old workshop id that was previously deleted, you will receive an error when Uploading.

 

Example Mods

To get started, a good way is to download the example mods from Steam Workshop and inspect their contents.  One is the Havarian mod, which should serve as a simple example of adding new language support.  The other is called Shel's Adventure, and has examples of other types of supported mod content.  (I should make clear that this mod is not meant to be a fully playable campaign, just an implementation example)

 

 

  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites
Hekateras    443

Sweet, can't wait to try this out, thank you!
Question, is there any ETA on tools to import custom graphics into the game (icons, anims, anim reskins)? Would go a long way towards making interesting new cards and NPCs and the like.

Share this post


Link to post
Share on other sites
RageLeague    1485

The game's engine supports both .tex file(KleiTex, not LaTeX) and .png files. If you want to add images, it's very easy to add .png files.

I have no idea what you would do if you want to add custom animation, though.

  • Like 1

Share this post


Link to post
Share on other sites
RageLeague    1485

It's very confusing, but the workshop items are stored here:

C:\Program Files (x86)\Steam\steamapps\workshop\content\601840

For the shel mod in particular, the item is here:

C:\Program Files (x86)\Steam\steamapps\workshop\content\601840\2217590179

Or something along those lines

Share this post


Link to post
Share on other sites
rooks    240
On 9/22/2020 at 12:52 PM, Scrumch said:

As in making a whole new outfit for one of the characters.

The process for making an entire outfit involves a couple of external tools and scripts that aren't included in the game unfortunately.  I imagine with some skilled reverse engineering it would be possible, but for now it's a bit beyond the scope of what's possible with the existing mod tools.

  • Thanks 2

Share this post


Link to post
Share on other sites
demian564    9

RageLeague but the workshop items are stored here:

T for response, in mod files i found just `custom` Shel`s cards not her basic starters

My goal is to change Shel starters from main grifters stuff to more tricky gameplay, using existing cards in the game, some manipulation stuff and npc traders cards if possible.

So, which file should i change to do  it ? 

Sorry for noob questions

 

Share this post


Link to post
Share on other sites
RageLeague    1485

Under shel_adventure.lua, there's this code at the bottom:

local decks = 
{
    NegotiationDeck("negotiation_basic", "PC_SHEL")
        :AddCards{ 
            fast_talk = 3,
            threaten = 3,
            deflection = 3,
            bravery = 1,
        },
    
    BattleDeck("battle_basic", "PC_SHEL")
        :AddCards{ 
            stab = 2,
            feint = 3,
            uppercut = 1,
            fightdirty = 1,
            berserk = 1,
        },
}

for k,v in ipairs(decks) do
    Content.AddDeck(v)
end

Do something similar to this.

  • Like 1

Share this post


Link to post
Share on other sites
demian564    9

38b437bd0d3bd4cda7d0d5a1f0df34c8.jpgf01194e6620e382dfe472cbb322e0b1b.jpg

1st of all thanks rooks and rage for the guide

Can i share mu 1st ever modding result here :) 

screens are new starting neg and battle decks, gameplay is very differ from standard grifter starting with, a lot more controling, and maybe too OP for start but at least Shel survives 1 vs 2 battles now

here is code 

--------------------------------------------------------------------------------

local decks = 
{
    NegotiationDeck("negotiation_basic", "PC_SHEL")
        :AddCards{ 
            admiralty_manipulate = 1,
            scapegoat = 1,
            dissect = 2,
            boiler = 3,
            bravery = 1,
            admiralty_manipulate2 = 1,
            turnabout = 2,
            caprice = 1,
        },
    
    BattleDeck("battle_basic", "PC_SHEL")
        :AddCards{ 
            tripwire = 2,
            waylay = 2,
            muddle = 1,
            kidney_shot = 1,
            carapace = 1,
            fightdirty = 1,
            berserk = 1,
            zig_zag = 1,
            thirst = 1,
            prototype_drone = 1,
        },
}

e53ef528c5d9b9f768f498c238131bcd.jpgjust looks all the barrels + revision in hand  = so much juice

Edited by demian564
  • Like 1

Share this post


Link to post
Share on other sites
demian564    9

hello again

another question is how to change RETIRE condition from resolve loss to total amount of shills in vault ? like 5000? or maybe scaling with days or current run prestige level ? any tips or just alt version pls

prob it os sleep_at_home.lua code

                    local RESOLVE_PER_DAY = cxt.mod_id == nil and 500 or Content.GetModSetting( cxt.mod_id, "resolve_per_day" )
                    local resolve, max_resolve = cxt.caravan:GetResolve()
                    local retire = max_resolve <= RESOLVE_PER_DAY
                    ConvoUtil.DoSleep( cxt )
                    if retire then
                        cxt:Dialog( "DIALOG_RETIRE" )

Share this post


Link to post
Share on other sites
RageLeague    1485

Right now there is no good way to do so in game.

I've helped written a way to clear convo functions so you can rewrite them. You can find the code for it in JuniorElder's Griftlands Expanded mod.

Here's the code.

-- MIT License

-- Copyright (c) 2020 RageLeague

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:

-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.

-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.

----------------------------------------------------------------------------------------
-- Additional methods for the convo class. This is useful for modifying existing states.
----------------------------------------------------------------------------------------

-- Get an existing state of the convo
function Convo:GetState(id)
    self.default_state = self.states[id]
    return self
end

-- Clear all functions under this convo
function Convo:ClearFn()
    assert(self.default_state, "NO STATE PUSHED")
    self.default_state.fns = {}
    return self
end

The code is so simple that I don't know if adding an MIT license under my name is a good idea or not. I'm not a lawyer.

Usage:

Content.GetConvoStateGraph(convo_id)
    :GetState(state_id)
    :ClearFn()
    :Fn(function(cxt)
        -- insert override code here
    end)

I haven't written anything out that allows you to modify existing hub, though. I haven't felt the need to do so yet.

Share this post


Link to post
Share on other sites
Wumpus the 19th    1237
17 minutes ago, RageLeague said:

Right now there is no good way to do so in game.

I've helped written a way to clear convo functions so you can rewrite them. You can find the code for it in JuniorElder's Griftlands Expanded mod.

Here's the code.


-- MIT License

-- Copyright (c) 2020 RageLeague

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:

-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.

-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.

----------------------------------------------------------------------------------------
-- Additional methods for the convo class. This is useful for modifying existing states.
----------------------------------------------------------------------------------------

-- Get an existing state of the convo
function Convo:GetState(id)
    self.default_state = self.states[id]
    return self
end

-- Clear all functions under this convo
function Convo:ClearFn()
    assert(self.default_state, "NO STATE PUSHED")
    self.default_state.fns = {}
    return self
end

The code is so simple that I don't know if adding an MIT license under my name is a good idea or not. I'm not a lawyer.

Usage:


Content.GetConvoStateGraph(convo_id)
    :GetState(state_id)
    :ClearFn()
    :Fn(function(cxt)
        -- insert override code here
    end)

I haven't written anything out that allows you to modify existing hub, though. I haven't felt the need to do so yet.

Yeah i was confused about that one. Not the code, that's the usual amount of confused for me. I was surprised to find an entire legal contract inside it.

Share this post


Link to post
Share on other sites
RageLeague    1485
10 minutes ago, Wumpus the 19th said:

Yeah i was confused about that one. Not the code, that's the usual amount of confused for me. I was surprised to find an entire legal contract inside it.

Yeah I mean, this is when I helped JuniorElder integrate their mod bosses to the regular campaign, so I just put that there just to make sure anyone can use it, and show that I worked on this code, not JuniorElder . At least, I think this is how it worked.

I might drop the license to public domain, or something, because this code is so simple that literally anyone can make it. But I'm not a lawyer, so I'm not sure the best course of action is.

The base game also used many open source code under the MIT license, like the yaml parser, the json module, etc., and at the start of each code segment it's basically the same thing with the year and the person's name changed to something else.

Edited by RageLeague
  • Like 1

Share this post


Link to post
Share on other sites
johnruby    45

Hello, I'm currently working on a mod for improved Traditional Chinese translation, and I have a question:

Once the game gets officially updated, how do I update the translation mod accordingly?

It seems that all the texts in the .po file are not listed in accordance with their last update date.

Will the dev publish a patch note detailing every change to the in-game text?

Or, do I have to check every line of the text in the .po file to find out every change done by each update?

Thanks!

Share this post


Link to post
Share on other sites
RageLeague    1485

If you use a po file editor like POEdit, it has an option to update your po file with a new po template file, and you can update your po file with the latest strings this way.

Otherwise there's no easy way to update po files to have the latest strings unless you write a script, at which point you might as well use POEdit.

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this