-
Notifications
You must be signed in to change notification settings - Fork 118
Getting Started (For Modders)
Note that this guide is for Windows users. If you're using OS X or Linux most of the tutorial will be applicable but specific file locations, etc... may be different.
Slay The Spire is written in Java. So you'll need some prior experience using the Java Programming Language or be willing to learn. This tutorial will use three tools you'll need to download:
In order to do modding for Slay The Spire you're absolutely going to need ModTheSpire link. It's also recommended that you download BaseMod to have access to an easier modding API link.
For this tutorial we are going to be using a folder called my_mods
in your Documents
folder. This folder (the my_mods
folder will be where you can place all your mods). For this example mod we will create an example_mod
folder inside my_mods
to contain all the code for this mod.
Now inside the my_mods
folder let's go ahead and create another folder called lib
(lib
is short for libraries
). This folder is where we'll place the dependencies for your mod. Go ahead and move the ModTheSpire.jar
and BaseMod.jar
that you downloaded in the last step into your lib
folder.
If this is your first time using Eclipse it will prompt you to select a Workspace location when you open it up. For the Workspace DO NOT use the default workspace. Instead we're going to use your my_mods
folder as the workspace. If you did end up using the default workspace or have used Eclipse before we're going to switch workspaces over to my_mods
. The black bars in the image are just covering up some personal information.
Now we can go ahead an create our mod using what Eclipse calls a project. So we will go to File
-> New
-> Java Project
. This will popup a modal. In the spot for the name of the project enter
example_mod
and then click Finish
. . This will create a new project for your mod! However we're not done yet because we have to configure its dependencies. Remember how earlier we put
ModTheSpire.jar
and BaseMod.jar
in the lib
folder? Well now we have to tell Eclipse that we actually put the dependencies there since it won't automatically know.
Your mod actually has one more dependency that we didn't download earlier (because if we could have downloaded it earlier it would be piracy). This is because we now need desktop-1.0.jar
as a dependency. So copy it over from your Slay The Spire directory into lib
so that your lib
folder now looks like this. .
To tell Eclipse about these dependencies we're going to need to go into the settings for your example_mod
. To do this right click on example_mod
and go down to Properties
. .
From here we're going to go to Java Build Path
-> Libraries
. .
Now use Add External JARs...
to add ModTheSpire.jar
, BaseMod.jar
, and desktop-1.0.jar
. Click okay once you've added all of them. It should look like this: .
Slay The Spire mods for the most part use Maven for building. If you have not installed Maven, go ahead and do that first. Maven requires your mod's folder structure to be set up in a specific way. Specifically all of your source code will need to be in the src/main/java
folder. To make this happen go back to the settings for your mod. .
From here we're going to go to Java Build Path
-> Source
and then highlight the example_mod/src
folder and click Remove
to remove it. Then use Add Folder
to add src/main/java
as a source folder. Click okay once you've done this. It should like like:
You will need to have a file called pom.xml
in your top level directory. This is required for Maven to build your project. An example pom.xml
file can be found in this gist.
Make sure your dependencies are pointing to the location of the correct .jar
files. ${basedir}
is the directory where your pom.xml
file is located. ..
is the parent directory.
<dependency>
<groupId>basemod</groupId>
<artifactId>basemod</artifactId>
<version>2.10.0</version>
<scope>system</scope>
<systemPath>${basedir}/../lib/BaseMod.jar</systemPath> // systemPath should be the path to where BaseMod.jar is located
</dependency>
Use mvn package
to build your mod! Maven will build a .jar
file with your mod. Your compiled .jar
file location is specified in the pom.xml
file
<target>
<copy file="target/ExampleMod.jar" tofile="../lib/ExampleMod.jar"/> // tofile location is where you can find your compiled .jar file
</target>
Congratulations! If you've made it this far you've finished setting up your development environment and should be ready to actually start developing your mod. Before continuing we're going to go over some of the fundamentals of how ModTheSpire and BaseMod work so you can use them to make your mod. ModTheSpire is the modloader for Slay The Spire and allows you to directly make changes to the game's code. This process is a bit tedious and subject to changes every time Slay The Spire is patched but may be necessary for some particularly complex features that mods try to add. BaseMod provides a more convenient API so mods for the most part can avoid directly changing the game's code. As such you are likely to use BaseMod and ModTheSpire in combination for modding projects. BaseMod's API is focused around the idea of firing events and having mods subscribe to/listen for those events. For example if you want to make a mod that heals the player 5 HP every time a card is exhausted you would use BaseMod to subscribe to the PostExhaust
event and then you could would be able to listen for that event using an event handler. In this example we will be creating a simple mod that shows how to use BaseMod's subscription system. In the future there may be tutorials showing how to use the Custom Character system and GUI but for now if you wish to use those systems take a look at the documentation here on the wiki and other mods that already use them.
To make a mod that works with BaseMod you're going to want to start out with some boilerplate code.
package example_mod;
import com.evacipated.cardcrawl.modthespire.lib.SpireInitializer;
@SpireInitializer
public class ExampleMod {
public ExampleMod() {
// TODO: make an awesome mod!
}
public static void initialize() {
new ExampleMod();
}
}
Note: If Eclipse can't find @SpireInitializer
you may have to go through the Dependencies step again since Eclipse seems to reset it when you changes source folders.
So what the above code is doing is telling ModTheSpire that we have a class called ExampleMod
that has a method called initialize
that we would like to have called once mods are loaded but before the game starts up. Inside that initialize
method we create an instance of our mod and inside that instance is where we're going to be telling BaseMod about the different events we want to listen for.
For this example we're going to be counting the number of times a card is exhausted in each battle and then report that value to the log. We will also be tracking the total number of cards exhausted in each act and reporting that after each battle too. Basically this mod could figure out that the player exhausted 2 cards in the 1st battle, then 3 cards in the 2nd battle which is 5 cards overall, etc.. To do this we will need to use three events that BaseMod provides: PostExhaust
, PostBattle
, PostDungeonInitialize
We will be using those hooks as follows. In PostDungeonInitialize
we will set the number of cards exhausted this act to 0. In PostBattle
we will print the total number of cards exhausted and the number of cards exhausted this battle. In PostExhaust
we will count the number of cards exhausted.
To setup our mod to subscribe to these events we need our ExampleMod
class to implement the corresponding interfaces: PostExhaustSubscriber
, PostBattleSubscriber
, PostDungeonInitializeSubscriber
. Then we tell BaseMod that we want to listen for those events by using BaseMod.subscribe(this)
.
package example_mod;
import com.evacipated.cardcrawl.modthespire.lib.SpireInitializer;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.rooms.AbstractRoom;
import basemod.BaseMod;
import basemod.interfaces.PostBattleSubscriber;
import basemod.interfaces.PostDungeonInitializeSubscriber;
import basemod.interfaces.PostExhaustSubscriber;
@SpireInitializer
public class ExampleMod implements PostExhaustSubscriber,
PostBattleSubscriber, PostDungeonInitializeSubscriber {
public ExampleMod() {
BaseMod.subscribe(this);
}
public static void initialize() {
new ExampleMod();
}
@Override
public void receivePostExhaust(AbstractCard c) {
}
@Override
public void receivePostBattle(AbstractRoom r) {
}
@Override
public void receivePostDungeonInitialize() {
}
}
package example_mod;
import com.evacipated.cardcrawl.modthespire.lib.SpireInitializer;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.rooms.AbstractRoom;
import basemod.BaseMod;
import basemod.interfaces.PostBattleSubscriber;
import basemod.interfaces.PostDungeonInitializeSubscriber;
import basemod.interfaces.PostExhaustSubscriber;
@SpireInitializer
public class ExampleMod implements PostExhaustSubscriber,
PostBattleSubscriber, PostDungeonInitializeSubscriber {
private int count, totalCount;
private void resetCounts() {
totalCount = count = 0;
}
public ExampleMod() {
BaseMod.subscribe(this);
resetCounts();
}
public static void initialize() {
new ExampleMod();
}
@Override
public void receivePostExhaust(AbstractCard c) {
count++;
totalCount++;
}
@Override
public void receivePostBattle(AbstractRoom r) {
System.out.println(count + " cards were exhausted this battle, " +
totalCount + " cards have been exhausted so far this act.");
count = 0;
}
@Override
public void receivePostDungeonInitialize() {
resetCounts();
}
}
Follow this guide to decompile Slay The Spire to (essentially) look at the game's source code.
Having problems? Check out this troubleshooting guide