Compare commits

...

6 Commits

Author SHA1 Message Date
dtookey
456b100799 Added a patch to enable the final act.
cleaned up some formatting in ConstructDraftPatch.java
2020-09-18 02:40:14 -04:00
dtookey
3f03dddab3 Minor formatting tweaks.
Better deployment tooling. added a project README.md (it's not very good).
Added some markdowns to work with Obsidian.md so I can remember how all of this stuff works in future.
Modified CArenaPatch to simply store whether or not the user selected the game mode.
Modified ConstructDraftPatch to set CArenaPatch.enabled to false (we're done with our part, we don't need to run until game start)
2020-09-18 02:40:14 -04:00
dtookey
982e1e2ee2 1.1 2020-09-18 02:40:14 -04:00
dtookey
77dd7f4409 1.0 2020-09-18 02:40:14 -04:00
dtookey
e334d1cb8d Game Mode shows up correctly.
Master deck is skipped during deck initialization.
todo: card picking screen for constructed.
2020-09-18 02:40:14 -04:00
dtookey
9e19ed5126 first commit 2020-09-18 02:40:14 -04:00
22 changed files with 802 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Gremious
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.

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Construct the Spire (formerly Arena)
### Custom game Mod for Constructed mode in Slay the Spire
This patches the addNonDailyMods method in CustomModeScreen to set a static boolean that signals to the rest of the
patches that the mod has been enabled.
This behavior is because I couldn't quite figure out how to detect loaded game mods during runtime from methods called
after AbstractDungeon has been initalized.

113
constructTheArena/pom.xml Normal file
View File

@ -0,0 +1,113 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--Hello! You'll basically should only need to change these names and the steam path (just below)-->
<!--The author name(s) as they appear in MTS and any other comments are in your ModTheSpire.json-->
<groupId>xyz.geniuscartel</groupId>
<artifactId>ConstructTheArena</artifactId>
<name>Construct The Arena</name>
<version>1.1</version>
<description>A default base to start your own mod from.</description>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<SlayTheSpire.version>01-23-2019</SlayTheSpire.version>
<ModTheSpire.version>3.8.0</ModTheSpire.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--CHANGE THIS TO YOUR STEAM INSTALLATION-->
<Steam.path>/home/dtookey/.steam/debian-installation/steamapps</Steam.path>
</properties>
<dependencies>
<dependency>
<groupId>com.megacrit.cardcrawl</groupId>
<artifactId>slaythespire</artifactId>
<version>${SlayTheSpire.version}</version>
<scope>system</scope>
<systemPath>${Steam.path}/common/SlayTheSpire/desktop-1.0.jar</systemPath>
<!--<systemPath>${basedir}/../lib/desktop-1.0.jar</systemPath>-->
</dependency>
<dependency>
<groupId>com.evacipated.cardcrawl</groupId>
<artifactId>modthespire</artifactId>
<version>${ModTheSpire.version}</version>
<scope>system</scope>
<systemPath>${Steam.path}/workshop/content/646570/1605060445/ModTheSpire.jar</systemPath>
<!--<systemPath>${basedir}/../lib/ModTheSpire.jar</systemPath>-->
</dependency>
<dependency>
<groupId>basemod</groupId>
<artifactId>basemod</artifactId>
<version>5.0.0</version>
<scope>system</scope>
<systemPath>${Steam.path}/workshop/content/646570/1605833019/BaseMod.jar</systemPath>
<!--<systemPath>${basedir}/../lib/BaseMod.jar</systemPath>-->
</dependency>
<dependency>
<groupId>com.evacipated.cardcrawl.mod</groupId>
<artifactId>StSLib</artifactId>
<version>1.3.2</version>
<scope>system</scope>
<systemPath>${Steam.path}/workshop/content/646570/1609158507/StSLib.jar</systemPath>
<!--<systemPath>${basedir}/../lib/StSLib.jar</systemPath>-->
</dependency>
</dependencies>
<!-- This is how your code is packaged into the jar file-->
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<excludes>
<exclude>**/*.psd</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>package</phase>
<configuration>
<target>
<!-- This moves your mod into a common folder where all mods you make can go. -->
<copy file="target/${project.artifactId}.jar" tofile="${Steam.path}/common/SlayTheSpire/mods/${project.artifactId}.jar"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>ModTheSpire.json</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>ModTheSpire.json</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,256 @@
package constructTheArena;
import basemod.BaseMod;
import basemod.ModLabeledToggleButton;
import basemod.ModPanel;
import basemod.helpers.RelicType;
import basemod.interfaces.AddCustomModeModsSubscriber;
import basemod.interfaces.EditRelicsSubscriber;
import basemod.interfaces.EditStringsSubscriber;
import basemod.interfaces.PostInitializeSubscriber;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.evacipated.cardcrawl.modthespire.lib.SpireConfig;
import com.evacipated.cardcrawl.modthespire.lib.SpireInitializer;
import com.google.gson.Gson;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.helpers.CardHelper;
import com.megacrit.cardcrawl.helpers.FontHelper;
import com.megacrit.cardcrawl.localization.RelicStrings;
import com.megacrit.cardcrawl.localization.RunModStrings;
import com.megacrit.cardcrawl.localization.UIStrings;
import com.megacrit.cardcrawl.screens.custom.CustomMod;
import constructTheArena.relics.ConstructorsBurden;
import constructTheArena.util.IDCheckDontTouchPls;
import constructTheArena.util.ResUtil;
import constructTheArena.util.TextureLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Properties;
// Please don't just mass replace "theDefault" with "yourMod" everywhere.
// It'll be a bigger pain for you. You only need to replace it in 3 places.
// I comment those places below, under the place where you set your ID.
//TODO: FIRST THINGS FIRST: RENAME YOUR PACKAGE AND ID NAMES FIRST-THING!!!
// Right click the package (Open the project pane on the left. Folder with black dot on it. The name's at the very top) -> Refactor -> Rename, and name it whatever you wanna call your mod.
// Scroll down in this file. Change the ID from "theDefault:" to "yourModName:" or whatever your heart desires (don't use spaces). Dw, you'll see it.
// In the JSON strings (resources>localization>eng>[all them files] make sure they all go "yourModName:" rather than "theDefault". You can ctrl+R to replace in 1 file, or ctrl+shift+r to mass replace in specific files/directories (Be careful.).
// Start with the DefaultCommon cards - they are the most commented cards since I don't feel it's necessary to put identical comments on every card.
// After you sorta get the hang of how to make cards, check out the card template which will make your life easier
/*
* With that out of the way:
* Welcome to this super over-commented Slay the Spire modding base.
* Use it to make your own mod of any type. - If you want to add any standard in-game content (character,
* cards, relics), this is a good starting point.
* It features 1 character with a minimal set of things: 1 card of each type, 1 debuff, couple of relics, etc.
* If you're new to modding, you basically *need* the BaseMod wiki for whatever you wish to add
* https://github.com/daviscook477/BaseMod/wiki - work your way through with this base.
* Feel free to use this in any way you like, of course. MIT licence applies. Happy modding!
*
* And pls. Read the comments.
*/
@SpireInitializer
public class ConstructTheArena implements
AddCustomModeModsSubscriber,
EditStringsSubscriber,
EditRelicsSubscriber,
PostInitializeSubscriber {
// Make sure to implement the subscribers *you* are using (read basemod wiki). Editing cards? EditCardsSubscriber.
// Making relics? EditRelicsSubscriber. etc., etc., for a full list and how to make your own, visit the basemod wiki.
public static final Logger logger = LogManager.getLogger(ConstructTheArena.class.getName());
private static String modID;
// Mod-settings settings. This is if you want an on/off savable button
public static Properties constructTheArenaSettings = new Properties();
public static final String ENABLE_PLACEHOLDER_SETTINGS = "enablePlaceholder";
public static boolean enablePlaceholder = true; // The boolean we'll be setting on/off (true/false)
//This is for the in-game mod settings panel.
private static final String MODNAME = "Construct The Arena";
private static final String AUTHOR = "Virgil"; // And pretty soon - You!
private static final String DESCRIPTION = "A deck constructor mod for concept testing and general shenanigans.";
// =============== INPUT TEXTURE LOCATION =================
//Mod Badge - A small icon that appears in the mod settings menu next to your mod.
public static final String BADGE_IMAGE = "constructTheArenaResources/images/Badge.png";
// =============== /INPUT TEXTURE LOCATION/ =================
// =============== SUBSCRIBE, CREATE THE COLOR_GRAY, INITIALIZE =================
public ConstructTheArena() {
setModID("constructTheArena");
constructTheArenaSettings.setProperty(ENABLE_PLACEHOLDER_SETTINGS, "FALSE"); // This is the default setting. It's actually set...
try {
SpireConfig config = getConfig();
config.load();
enablePlaceholder = config.getBool(ENABLE_PLACEHOLDER_SETTINGS);
} catch (Exception e) {
e.printStackTrace();
}
logger.info("Done adding mod settings");
}
// ====== NO EDIT AREA ======
// DON'T TOUCH THIS STUFF. IT IS HERE FOR STANDARDIZATION BETWEEN MODS AND TO ENSURE GOOD CODE PRACTICES.
// IF YOU MODIFY THIS I WILL HUNT YOU DOWN AND DOWNVOTE YOUR MOD ON WORKSHOP
public static void setModID(String ID) { // DON'T EDIT
Gson coolG = new Gson(); // EY DON'T EDIT THIS
// String IDjson = Gdx.files.internal("IDCheckStringsDONT-EDIT-AT-ALL.json").readString(String.valueOf(StandardCharsets.UTF_8)); // i hate u Gdx.files
InputStream in = ConstructTheArena.class.getResourceAsStream("/IDCheckStringsDONT-EDIT-AT-ALL.json"); // DON'T EDIT THIS ETHER
IDCheckDontTouchPls EXCEPTION_STRINGS = coolG.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), IDCheckDontTouchPls.class); // OR THIS, DON'T EDIT IT
if (ID.equals(EXCEPTION_STRINGS.DEFAULTID)) { // DO *NOT* CHANGE THIS ESPECIALLY, TO EDIT YOUR MOD ID, SCROLL UP JUST A LITTLE, IT'S JUST ABOVE
throw new RuntimeException(EXCEPTION_STRINGS.EXCEPTION); // THIS ALSO DON'T EDIT
} else if (ID.equals(EXCEPTION_STRINGS.DEVID)) { // NO
modID = EXCEPTION_STRINGS.DEFAULTID; // DON'T
} else { // NO EDIT AREA
modID = ID; // DON'T WRITE OR CHANGE THINGS HERE NOT EVEN A LITTLE
} // NO
} // NO
public static String getModID() { // NO
return modID; // DOUBLE NO
} // NU-UH
private static void pathCheck() { // ALSO NO
Gson coolG = new Gson(); // NOPE DON'T EDIT THIS
// String IDjson = Gdx.files.internal("IDCheckStringsDONT-EDIT-AT-ALL.json").readString(String.valueOf(StandardCharsets.UTF_8)); // i still hate u btw Gdx.files
InputStream in = ConstructTheArena.class.getResourceAsStream("/IDCheckStringsDONT-EDIT-AT-ALL.json"); // DON'T EDIT THISSSSS
IDCheckDontTouchPls EXCEPTION_STRINGS = coolG.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), IDCheckDontTouchPls.class); // NAH, NO EDIT
String packageName = ConstructTheArena.class.getPackage().getName(); // STILL NO EDIT ZONE
FileHandle resourcePathExists = Gdx.files.internal(getModID() + "Resources"); // PLEASE DON'T EDIT THINGS HERE, THANKS
if (!modID.equals(EXCEPTION_STRINGS.DEVID)) { // LEAVE THIS EDIT-LESS
if (!packageName.equals(getModID())) { // NOT HERE ETHER
throw new RuntimeException(EXCEPTION_STRINGS.PACKAGE_EXCEPTION + getModID()); // THIS IS A NO-NO
} // WHY WOULD U EDIT THIS
if (!resourcePathExists.exists()) { // DON'T CHANGE THIS
throw new RuntimeException(EXCEPTION_STRINGS.RESOURCE_FOLDER_EXCEPTION + getModID() + "Resources"); // NOT THIS
}// NO
}// NO
}// NO
// ====== YOU CAN EDIT AGAIN ======
@SuppressWarnings("unused")
public static void initialize() {
BaseMod.subscribe(new ConstructTheArena());
}
// ============== /SUBSCRIBE, CREATE THE COLOR_GRAY, INITIALIZE/ =================
// =============== POST-INITIALIZE =================
@Override
public void receivePostInitialize() {
logger.info("Loading badge image and mod options");
// Load the Mod Badge
Texture badgeTexture = TextureLoader.getTexture(BADGE_IMAGE);
// Create the Mod Menu
ModPanel settingsPanel = new ModPanel();
// Create the on/off button:
ModLabeledToggleButton enableNormalsButton = new ModLabeledToggleButton("This is the text which goes next to the checkbox.",
350.0f, 700.0f, Settings.CREAM_COLOR, FontHelper.charDescFont, // Position (trial and error it), color, font
enablePlaceholder, // Boolean it uses
settingsPanel, // The mod panel in which this button will be in
(label) -> {
}, // thing??????? idk
(button) -> { // The actual button:
enablePlaceholder = button.enabled; // The boolean true/false will be whether the button is enabled or not
try {
// And based on that boolean, set the settings and save them
SpireConfig config = getConfig();
config.setBool(ENABLE_PLACEHOLDER_SETTINGS, enablePlaceholder);
config.save();
} catch (Exception e) {
e.printStackTrace();
}
});
settingsPanel.addUIElement(enableNormalsButton); // Add the button to the settings panel. Button is a go.
BaseMod.registerModBadge(badgeTexture, MODNAME, AUTHOR, DESCRIPTION, settingsPanel);
}
// =============== / POST-INITIALIZE/ =================
private SpireConfig getConfig() throws IOException {
return new SpireConfig("constructTheArena", "constructTheArenaConfig", constructTheArenaSettings);
}
// this adds "ModName:" before the ID of any card/relic/power etc.
// in order to avoid conflicts if any other mod uses the same ID.
public static String makeID(String idText) {
return getModID() + ":" + idText;
}
//<editor-fold name="add custom game mode">
/*======================================================================================
add custom game mode
======================================================================================*/
@Override
public void receiveCustomModeMods(List<CustomMod> list) {
list.add(new CustomMod(getModID() + ":" + getModID(), "b", false));
}
@Override
public void receiveEditStrings() {
BaseMod.loadCustomStringsFile(RunModStrings.class, ResUtil.getLocRes("eng", "constructTheArena-RunModStrings.json"));
BaseMod.loadCustomStringsFile(RelicStrings.class, ResUtil.getLocRes("eng", "constructTheArena-RelicStrings.json"));
BaseMod.loadCustomStringsFile(UIStrings.class, ResUtil.getLocRes("eng", "constructTheArena-UIStrings.json"));
}
//<editor-fold name="Add Relics">
/*======================================================================================
Add Relics
======================================================================================*/
@Override
public void receiveEditRelics() {
BaseMod.addRelic(new ConstructorsBurden(), RelicType.SHARED);
}
//</editor-fold>
//</editor-fold>
}

View File

@ -0,0 +1,25 @@
package constructTheArena.patches;
import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePrefixPatch;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//generateMap in AbstractDungeon.java
@SpirePatch(
clz = AbstractDungeon.class,
method = "generateMap"
)
public class CArenaEnableLastActPatch {
private final static Logger logger = LogManager.getLogger(CArenaEnableLastActPatch.class.getName());
@SpirePrefixPatch
public static void Prefix() {
if (CArenaPatch.isEnabled()) {
Settings.isFinalActAvailable = true;
}
}
}

View File

@ -0,0 +1,41 @@
package constructTheArena.patches;
import com.evacipated.cardcrawl.modthespire.lib.SpireInsertPatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.megacrit.cardcrawl.screens.custom.CustomModeScreen;
import com.megacrit.cardcrawl.trials.CustomTrial;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
@SpirePatch(
clz = CustomModeScreen.class,
method = "addNonDailyMods"
)
public class CArenaPatch {
private final static Logger logger = LogManager.getLogger(CArenaPatch.class.getName());
private static boolean enabled = false;
@SpireInsertPatch(
rloc = 1,
localvars = {"modId"}
)
public static void Insert(CustomModeScreen __instance, CustomTrial trial, ArrayList<String> modIds, String modId) {
if (modId.equals("constructTheArena:constructTheArena")) {
//do nothing for now
enabled = true;
}
}
public static boolean isEnabled() {
return enabled;
}
public static void setEnabled(boolean b) {
enabled = b;
}
}

View File

@ -0,0 +1,3 @@
#CArenaPatch
This method simply detects if the game mod was selected by the user and stores the decision in a boolean.

View File

@ -0,0 +1,26 @@
package constructTheArena.patches;
import com.evacipated.cardcrawl.modthespire.lib.ByRef;
import com.evacipated.cardcrawl.modthespire.lib.SpireInsertPatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@SpirePatch(
clz = AbstractPlayer.class,
method = "initializeStarterDeck"
)
public class CArenaSkipMasterDeckPatch {
@SpireInsertPatch(
loc = 409,
localvars = {"addBaseCards"}
)
public static void Insert(AbstractPlayer __instance, @ByRef boolean[] addBaseCards) {
if (CArenaPatch.isEnabled()) {
addBaseCards[0] = false;
}else{
addBaseCards[0] = true;
}
}
}

View File

@ -0,0 +1,9 @@
#CArenaSkipMasterDeckPatch
This patch inserts a call inside initializeStarterDeck in AbstractPlayer
This encapsulates and provides a reference to addBaseCards inside the method. There was a bug where subsequent games
would not load the starting deck because the logic for detecting enabled game mods was not what I was expecting.
That being said, this checks the [[CArenaPatch]] class to see if the mod was enabled and bases its decision off of that.
It's a bit of a hack, yes, but it works.

View File

@ -0,0 +1,84 @@
package constructTheArena.patches;
import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePrefixPatch;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.CardGroup;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.helpers.CardLibrary;
import com.megacrit.cardcrawl.helpers.ModHelper;
import com.megacrit.cardcrawl.localization.UIStrings;
import com.megacrit.cardcrawl.neow.NeowEvent;
import com.megacrit.cardcrawl.unlock.UnlockTracker;
import constructTheArena.relics.ConstructorsBurden;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
@SpirePatch(
clz = NeowEvent.class,
method = "dailyBlessing"
)
public class ConstructDraftPatch {
private final static Logger logger = LogManager.getLogger(ConstructDraftPatch.class.getName());
private final static int CardLimit = 40;
private static final UIStrings uiStrings = CardCrawlGame.languagePack.getUIString("ConstructModeInstructions");
@SpirePrefixPatch
public static void Prefix() {
if (CArenaPatch.isEnabled()) {
ArrayList<String> mods = ModHelper.getEnabledModIDs();
mods.remove("SealedDeck");
ModHelper.setMods(mods);
CardGroup constructGroup = new CardGroup(CardGroup.CardGroupType.UNSPECIFIED);
//add master deck to draw pool
TreeSet<String> dedupedMasterDeck = new TreeSet<>(AbstractDungeon.player.getStartingDeck());
for (String cardName : dedupedMasterDeck) {
AbstractCard card = CardLibrary.getCard(AbstractDungeon.player.chosenClass, cardName);
for (int i = 0; i < 4; i++) {
constructGroup.addToTop(card.makeCopy());
}
}
//add all other eligible cards to the draw pool
ArrayList<AbstractCard> cardPool = new ArrayList<>();
AbstractDungeon.player.getCardPool(cardPool);
//sort it so it's all pretty
cardPool.sort(Comparator.comparing(card -> card.name));
for (AbstractCard card : cardPool) {
for (int i = 0; i < 4; i++) {
constructGroup.addToTop(card.makeCopy());
}
}
Iterator<AbstractCard> cards = constructGroup.group.iterator();
AbstractCard c;
while (cards.hasNext()) {
c = cards.next();
UnlockTracker.markCardAsSeen(c.cardID);
}
AbstractDungeon.gridSelectScreen.open(constructGroup, 40, true, uiStrings.TEXT[0] + CardLimit + uiStrings.TEXT[1]);
AbstractDungeon.getCurrRoom().spawnRelicAndObtain(Settings.WIDTH / 2.0F, Settings.HEIGHT / 2.0F, new ConstructorsBurden());
CArenaPatch.setEnabled(false); //turne off deck skipping and whatnot
}
}
}

View File

@ -0,0 +1,13 @@
#ConstructDraftPatch
This prefixes the dailyBlessing method of the NeowEvent. This checks the [[CArenaPatch]] class to see if the game mod was
enabled. At the end of the patched method call, this will set CArenaPatch.enabled to false in order to make sure
subsequent (potentially non-cosntructed) games will have the master deck and normal card rewards.
The current ruleset is thus:
4 copies of every card available to the player's card pool
4 copies of each of the cards in the character's master deck
Maximum of 40 selections
After the card selection dialgue is complete, the [[ConstructorsBurden]] relic will be added to the player

View File

@ -0,0 +1,45 @@
package constructTheArena.relics;
import com.fasterxml.jackson.core.type.ResolvedType;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.helpers.ImageMaster;
import com.megacrit.cardcrawl.relics.AbstractRelic;
import constructTheArena.util.ResUtil;
public class ConstructorsBurden extends AbstractRelic {
private final static String imgPathLarge = ResUtil.getImageRes("relics", "constructorsBurdenLarge.png");
private final static String imgPath = ResUtil.getImageRes("relics", "constructorsBurden.png");
public ConstructorsBurden() {
super("constructTheArena:ConstructorsBurden", "", RelicTier.SPECIAL, LandingSound.HEAVY);
imgUrl = imgPath;
img = ImageMaster.loadImage(imgPath);
largeImg = ImageMaster.loadImage(imgPathLarge);
outlineImg = ImageMaster.loadImage(imgPath);
}
@Override
public AbstractRelic makeCopy() {
return new ConstructorsBurden();
}
@Override
public int changeNumberOfCardsInReward(int NumberOfCards) {
return -10;
}
@Override
public String getUpdatedDescription() {
if (AbstractDungeon.player != null) {
return setDescription(AbstractDungeon.player.chosenClass);
}
return setDescription((AbstractPlayer.PlayerClass) null);
}
private String setDescription(AbstractPlayer.PlayerClass c) {
return this.DESCRIPTIONS[0];
}
}

View File

@ -0,0 +1,4 @@
#ConstructorsBurden
Simple abstract relic that reduces card rewards by 10 in order to negate all potential card rewards. There may be a case
where card rewards can exceed 10, but I can't think of one.

View File

@ -0,0 +1,10 @@
package constructTheArena.util;
public class IDCheckDontTouchPls {
public String DEFAULTID;
public String DEVID;
public String EXCEPTION;
public String PACKAGE_EXCEPTION;
public String RESOURCE_FOLDER_EXCEPTION;
public String RESOURCES;
}

View File

@ -0,0 +1,42 @@
package constructTheArena.util;
public class ResUtil {
private final static String baseResourceDirectory = "constructTheArenaResources/";
private static String buildPath(StringBuilder sb, String... parts) {
for (int i = 0; i < parts.length; i++) {
String s = parts[i];
sb.append(s);
if (i < parts.length - 1) {
sb.append("/");
}
}
return sb.toString();
}
public static String getResource(String... parts){
StringBuilder sb = new StringBuilder();
sb.append(baseResourceDirectory);
return buildPath(sb, parts);
}
/**
* Creates a path string for the desired localized text resource
* @param locale localization abbreviateion (i.e. eng, rus, etc...)
* @param resourceName name of text asset (myText.json)
* @return resource location
*/
public static String getLocRes(String locale, String resourceName){
String localization = "localization/" + locale;
return getResource(localization, resourceName);
}
public static String getImageRes(String category, String resourceName) {
String localization = "images/" + category;
return getResource(localization, resourceName);
}
}

View File

@ -0,0 +1,50 @@
package constructTheArena.util;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.utils.GdxRuntimeException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.HashMap;
// Thank you Blank The Evil!
// Welcome to the utilities package. This package is for small utilities that make our life easier.
// You honestly don't need to bother with this unless you want to know how we're loading the textures.
public class TextureLoader {
private final static HashMap<String, Texture> textures = new HashMap<>();
public static final Logger logger = LogManager.getLogger(TextureLoader.class.getName());
/**
* @param textureString - String path to the texture you want to load relative to resources,
* Example: "theDefaultResources/images/ui/missing_texture.png"
* @return <b>com.badlogic.gdx.graphics.Texture</b> - The texture from the path provided
*/
public static Texture getTexture(final String textureString) {
if (textures.get(textureString) == null) {
try {
loadTexture(textureString);
} catch (GdxRuntimeException e) {
logger.error("Could not find texture: " + textureString);
return getTexture("constructTheArenaResources/images/ui/missing_texture.png");
}
}
return textures.get(textureString);
}
/**
* Creates an instance of the texture, applies a linear filter to it, and places it in the HashMap
*
* @param textureString - String path to the texture you want to load relative to resources,
* Example: "img/ui/missingtexture.png"
* @throws GdxRuntimeException
*/
private static void loadTexture(final String textureString) throws GdxRuntimeException {
Texture texture = new Texture(textureString);
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
textures.put(textureString, texture);
}
}

View File

@ -0,0 +1,8 @@
{
"DEFAULTID": "theDefault",
"DEVID": "theDefaultDev",
"EXCEPTION": "Go to your constructor in your class with SpireInitializer and change your mod ID from \"theDefault\"",
"PACKAGE_EXCEPTION": "Rename your theDefault folder (package) to match your mod ID! ",
"RESOURCE_FOLDER_EXCEPTION": "Rename your theDefaultResources folder to match your mod ID!",
"RESOURCES": "Resources"
}

View File

@ -0,0 +1,12 @@
{
"modid": "${project.artifactId}",
"name": "${project.name}",
"author_list": ["Virgil"],
"credits": "Basemod, ModTheSpire",
"description": "${project.description}",
"version": "${project.version}",
"sts_version": "${SlayTheSpire.version}",
"mts_version": "${ModTheSpire.version}",
"dependencies": ["basemod", "stslib"],
"update_json": ""
}

View File

@ -0,0 +1,9 @@
{
"constructTheArena:ConstructorsBurden": {
"NAME": "Constructor's Burden",
"FLAVOR": "You no longer receive card rewards.",
"DESCRIPTIONS": [
"Number of card rewards set to 0."
]
}
}

View File

@ -0,0 +1,6 @@
{
"constructTheArena:constructTheArena": {
"NAME": "Construct the Spire",
"DESCRIPTION": "Constructed Deck Mode"
}
}

View File

@ -0,0 +1,9 @@
{
"ConstructModeInstructions": {
"TEXT": [
"Select up to ",
" cards."
]
}
}

7
deploy.sh Normal file
View File

@ -0,0 +1,7 @@
#! /bin/bash
rm ~/.steam/debian-installation/steamapps/common/SlayTheSpire/ConstructTheArena/content/ConstructTheArena.jar
cp constructTheArena/target/ConstructTheArena.jar ~/.steam/debian-installation/steamapps/common/SlayTheSpire/ConstructTheArena/content/ConstructTheArena.jar
cd ~/.steam/debian-installation/steamapps/common/SlayTheSpire || exit
java -jar mod-uploader.jar upload -w ConstructTheArena