├── src └── main │ ├── resources │ ├── ModTheSpire.json │ └── localization.json │ └── java │ └── textTheSpire │ ├── AbstractWindow.java │ ├── Window.java │ ├── Discard.java │ ├── Deck.java │ ├── Relic.java │ ├── Hand.java │ ├── Logs.java │ ├── Orbs.java │ ├── Player.java │ ├── Custom.java │ ├── Event.java │ ├── Monster.java │ ├── Map.java │ ├── Inspect.java │ └── Choices.java ├── .gitignore ├── README.md ├── TextTheSpire.iml └── pom.xml /src/main/resources/ModTheSpire.json: -------------------------------------------------------------------------------- 1 | { 2 | "modid": "${project.artifactId}", 3 | "name": "${project.name}", 4 | "author_list": ["Wensber"], 5 | "description": "${project.description}", 6 | "version": "${project.version}", 7 | "sts_version": "${SlayTheSpire.version}", 8 | "mts_version": "${ModTheSpire.version}", 9 | "dependencies": ["basemod", "CommunicationMod"] 10 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # Mobile Tools for Java (J2ME) 8 | .mtj.tmp/ 9 | 10 | # Package Files # 11 | *.jar 12 | *.war 13 | *.ear 14 | *.zip 15 | *.tar.gz 16 | *.rar 17 | 18 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 19 | hs_err_pid* 20 | 21 | # Eclipse 22 | .classpath 23 | .project 24 | .settings/ 25 | 26 | # IntelliJ 27 | .idea/ 28 | out/ 29 | CommunicationMod.iml 30 | 31 | # maven 32 | target/ 33 | dependency-reduced-pom.xml -------------------------------------------------------------------------------- /src/main/java/textTheSpire/AbstractWindow.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | abstract class AbstractWindow { 4 | 5 | Window window; 6 | 7 | boolean isVisible; 8 | 9 | public void update(){ 10 | if(isVisible) { 11 | String s = getText(); 12 | 13 | if (s.length() > 0 && !s.equals("\r\n")) { 14 | window.setVisible(true); 15 | window.setText(s); 16 | } else { 17 | window.setVisible(false); 18 | } 19 | }else{ 20 | window.setVisible(false); 21 | } 22 | } 23 | 24 | abstract String getText(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Window.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.layout.GridLayout; 5 | import org.eclipse.swt.widgets.*; 6 | import org.lwjgl.Sys; 7 | 8 | public class Window { 9 | 10 | Shell shell; 11 | Text label; 12 | 13 | String currentText; 14 | 15 | public Window(Display d, String header, int w, int h){ 16 | shell = new Shell(d); 17 | shell.setSize(w,h); 18 | shell.setLocation(200,400); 19 | shell.setText(header); 20 | label = new Text(shell, SWT.MULTI); 21 | label.setSize(w,h); 22 | label.setEditable(false); 23 | shell.setVisible(true); 24 | shell.open(); 25 | 26 | currentText = ""; 27 | 28 | } 29 | 30 | public void setText(String s){ 31 | 32 | currentText = s; 33 | 34 | label.getDisplay().asyncExec(new Runnable() { 35 | @Override 36 | public void run() { 37 | if(!label.isDisposed() && !shell.isDisposed() && !s.equals(label.getText())) { 38 | label.setText(s); 39 | } 40 | } 41 | }); 42 | 43 | } 44 | 45 | public String getText(){ 46 | return currentText; 47 | } 48 | 49 | public void setVisible(boolean b){ 50 | shell.getDisplay().asyncExec(new Runnable() { 51 | @Override 52 | public void run() { 53 | if(!shell.isDisposed()){ 54 | shell.setVisible(b); 55 | } 56 | } 57 | }); 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Discard.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.cards.AbstractCard; 5 | import com.megacrit.cardcrawl.cards.CardGroup; 6 | import com.megacrit.cardcrawl.core.CardCrawlGame; 7 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 8 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 9 | import communicationmod.CommandExecutor; 10 | import org.apache.logging.log4j.core.tools.picocli.CommandLine; 11 | import org.eclipse.swt.widgets.Display; 12 | 13 | public class Discard extends AbstractWindow{ 14 | 15 | public Discard(Display display){ 16 | isVisible = true; 17 | window = new Window(display,"Discard",300,300); 18 | } 19 | 20 | public String getText(){ 21 | 22 | if(window.shell.isDisposed()) { 23 | Display.getDefault().dispose(); 24 | Gdx.app.exit(); 25 | } 26 | 27 | StringBuilder s = new StringBuilder(); 28 | s.append("\r\n"); 29 | 30 | //Not in dungeon 31 | if(CardCrawlGame.dungeon == null || !CommandExecutor.isInDungeon() || !CardCrawlGame.isInARun()){ 32 | return ""; 33 | } 34 | 35 | //In combat 36 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 37 | 38 | CardGroup h = AbstractDungeon.player.discardPile; 39 | 40 | 41 | s.append("Size: ").append(h.size()).append("\r\n"); 42 | 43 | if(h.size() > 0) { 44 | for (AbstractCard c : h.group) { 45 | s.append(c.name).append("\r\n"); 46 | } 47 | } 48 | 49 | return s.toString(); 50 | 51 | }else{ 52 | //Not in combat 53 | return ""; 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Deck.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.cards.AbstractCard; 5 | import com.megacrit.cardcrawl.cards.CardGroup; 6 | import com.megacrit.cardcrawl.core.CardCrawlGame; 7 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 8 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 9 | import communicationmod.CommandExecutor; 10 | import org.eclipse.swt.widgets.Display; 11 | 12 | public class Deck extends AbstractWindow{ 13 | 14 | public Deck(Display display){ 15 | isVisible = true; 16 | window = new Window(display,"Deck",300,300); 17 | } 18 | 19 | public String getText(){ 20 | 21 | if(window.shell.isDisposed()){ 22 | Display.getDefault().dispose(); 23 | Gdx.app.exit(); 24 | } 25 | 26 | StringBuilder s = new StringBuilder(); 27 | s.append("\r\n"); 28 | 29 | //Not in dungeon 30 | if(CardCrawlGame.dungeon == null || !CommandExecutor.isInDungeon() || !CardCrawlGame.isInARun()){ 31 | return ""; 32 | } 33 | 34 | //Show remaining deck in combat 35 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 36 | 37 | CardGroup h = AbstractDungeon.player.drawPile; 38 | 39 | s.append("Size: ").append(h.size()).append("\r\n"); 40 | 41 | if(h.size() > 0) { 42 | for (AbstractCard c : h.group) { 43 | s.append(c.name).append("\r\n"); 44 | } 45 | } 46 | 47 | return s.toString(); 48 | 49 | }else{ 50 | //Show master deck out of combat 51 | CardGroup h = AbstractDungeon.player.masterDeck; 52 | 53 | s.append("Size: ").append(h.size()).append("\r\n"); 54 | 55 | if(h.size() > 0) { 56 | for (int i=0;i relics = AbstractDungeon.player.relics; 38 | 39 | for(int i=relics.size()-1; i>=0; i--){ 40 | AbstractRelic r = relics.get(i); 41 | if(r.counter >= 0){ 42 | s.append(i).append(":").append(r.name).append(" ").append(r.counter).append("\r\n"); 43 | }else{ 44 | s.append(i).append(":").append(r.name).append("\r\n"); 45 | } 46 | } 47 | 48 | ArrayList blights = AbstractDungeon.player.blights; 49 | 50 | if(blights.size() > 0){ 51 | s.append("Blights\r\n"); 52 | for(int i=blights.size()-1; i>=0; i--){ 53 | AbstractBlight r = blights.get(i); 54 | if(r.counter >= 0){ 55 | s.append(i+relics.size()).append(":").append(r.name).append(" ").append(r.counter).append("\r\n"); 56 | }else{ 57 | s.append(i+relics.size()).append(":").append(r.name).append("\r\n"); 58 | } 59 | } 60 | } 61 | 62 | 63 | return s.toString(); 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Hand.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.cards.AbstractCard; 5 | import com.megacrit.cardcrawl.cards.CardGroup; 6 | import com.megacrit.cardcrawl.core.CardCrawlGame; 7 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 8 | import com.megacrit.cardcrawl.potions.AbstractPotion; 9 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 10 | import communicationmod.CommandExecutor; 11 | import org.eclipse.swt.widgets.Display; 12 | 13 | import java.util.ArrayList; 14 | 15 | public class Hand extends AbstractWindow{ 16 | 17 | 18 | public Hand(Display display){ 19 | isVisible = true; 20 | window = new Window(display,"Hand",300,300); 21 | } 22 | 23 | public String getText(){ 24 | 25 | if(window.shell.isDisposed()){ 26 | Display.getDefault().dispose(); 27 | Gdx.app.exit(); 28 | } 29 | 30 | StringBuilder s = new StringBuilder(); 31 | s.append("\r\n"); 32 | 33 | //If not in dungeon 34 | if(CardCrawlGame.dungeon == null || !CommandExecutor.isInDungeon() || !CardCrawlGame.isInARun()){ 35 | return ""; 36 | } 37 | 38 | //If in combat 39 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 40 | 41 | CardGroup h = AbstractDungeon.player.hand; 42 | 43 | int count = 1; 44 | for(AbstractCard c : h.group){ 45 | int cost = handCost(c); 46 | if(cost == -2) { 47 | s.append(count).append(":").append(c.name).append("\r\n"); 48 | } else if(cost == -1) { 49 | s.append(count).append(":").append(c.name).append(" X").append("\r\n"); 50 | } else { 51 | s.append(count).append(":").append(c.name).append(" ").append(cost).append("\r\n"); 52 | } 53 | count++; 54 | } 55 | 56 | ArrayList pl = AbstractDungeon.player.potions; 57 | count = 0; 58 | if (pl.size() > 0) { 59 | s.append("Potions:\r\n"); 60 | for (AbstractPotion po : pl) { 61 | s.append(count).append(":").append(po.name).append("\r\n"); 62 | count++; 63 | } 64 | } 65 | 66 | return s.toString(); 67 | 68 | }else{ 69 | //If not in combat 70 | return ""; 71 | } 72 | } 73 | 74 | /* 75 | Params: 76 | c - Any card in your hand 77 | Returns: 78 | Current cost of c 79 | */ 80 | public static int handCost(AbstractCard c){ 81 | if (c.freeToPlay()) { 82 | return 0; 83 | } else{ 84 | return c.costForTurn; 85 | } 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Logs.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.megacrit.cardcrawl.core.CardCrawlGame; 4 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 5 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 6 | import communicationmod.CommandExecutor; 7 | import org.eclipse.swt.widgets.Display; 8 | 9 | import java.util.ArrayList; 10 | 11 | public class Logs { 12 | 13 | public Window logs; 14 | 15 | private String log; 16 | 17 | private int playerHp; 18 | private ArrayList monsterHp; 19 | 20 | public Logs(Display display){ 21 | logs = new Window(display,"Log",450,525); 22 | log = ""; 23 | //logs.setText(log); 24 | playerHp = 0; 25 | monsterHp = new ArrayList<>(); 26 | } 27 | 28 | public String getText(){ 29 | return log; 30 | } 31 | 32 | public void output(String s){ 33 | log = "\r\n" + s + log; 34 | logs.setText(log); 35 | } 36 | 37 | public void update(){ 38 | 39 | if(!CommandExecutor.isInDungeon()){ 40 | return; 41 | } 42 | 43 | if(AbstractDungeon.player.currentHealth != playerHp){ 44 | if(playerHp < AbstractDungeon.player.currentHealth){ 45 | output("Played healed " + (AbstractDungeon.player.currentHealth - playerHp)); 46 | }else{ 47 | output("Played took " + (playerHp - AbstractDungeon.player.currentHealth)); 48 | } 49 | playerHp = AbstractDungeon.player.currentHealth; 50 | } 51 | 52 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 53 | if(AbstractDungeon.getCurrRoom().monsters.monsters.size() > monsterHp.size()){ 54 | for(int i=monsterHp.size();i AbstractDungeon.getCurrRoom().monsters.monsters.get(i).currentHealth){ 64 | output("Monster " + i + " : " + AbstractDungeon.getCurrRoom().monsters.monsters.get(i).name + " took " + (monsterHp.get(i) - AbstractDungeon.getCurrRoom().monsters.monsters.get(i).currentHealth)); 65 | monsterHp.set(i, AbstractDungeon.getCurrRoom().monsters.monsters.get(i).currentHealth); 66 | } 67 | } 68 | }else{ 69 | monsterHp.clear(); 70 | } 71 | 72 | } 73 | 74 | } 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TextTheSpire 2 | 3 | Author: Wensber - textthespire@gmail.com 4 | 5 | https://steamcommunity.com/sharedfiles/filedetails/?edit=true&id=2130936088 6 | https://github.com/Wensber/TextTheSpire 7 | 8 | Description: 9 | 10 | This is a mod for the game Slay the Spire and provides screen reader accessibility. 11 | It does so by providing lots of windows displaying the game information and a prompt window for inputting commands. 12 | Descriptions of the windows and commands are provided with the help command. 13 | 14 | This mod supports Windows 64 bit. Other versions of the mod are experimental and can be found: 15 | 16 | win32 : https://steamcommunity.com/sharedfiles/filedetails/?id=2254163848 17 | 18 | mac : https://steamcommunity.com/sharedfiles/filedetails/?id=2254164037 19 | 20 | linux : https://steamcommunity.com/sharedfiles/filedetails/?id=2254164205 21 | 22 | Requirements: 23 | 24 | Steam - https://steamcommunity.com/ 25 | 26 | Slay the Spire - https://store.steampowered.com/app/646570/Slay_the_Spire/ 27 | 28 | Java - https://www.oracle.com/java/technologies/javase-jre8-downloads.html 29 | 30 | Text the Spire - https://steamcommunity.com/sharedfiles/filedetails/?id=2130936088 31 | 32 | CommunicationMod - https://steamcommunity.com/sharedfiles/filedetails/?id=2131373661 33 | 34 | BaseMod - https://steamcommunity.com/workshop/filedetails/?id=1605833019 35 | 36 | ModTheSpire - https://steamcommunity.com/sharedfiles/filedetails/?id=1605060445 37 | 38 | If you don't already have a screen reader, you can NVDA for free from https://www.nvaccess.org/ 39 | 40 | Recommendations: 41 | 42 | Read the Spire, mod that can auto read changes in windows: https://github.com/pitermach/ReadTheSpire 43 | 44 | Mod to enable achievements: https://steamcommunity.com/sharedfiles/filedetails/?id=1692554109 45 | This one is almost a requirement as one of the characters Watcher does not seem to unlock without this. 46 | 47 | Gameplay mechanics guide: https://slay-the-spire.fandom.com/wiki/Gameplay 48 | 49 | Known Issues: 50 | 51 | If a old run that you finished or overwrote appears again you can delete the run in the saves folder in the main Slay the Spire directory. 52 | This folder is just the run saves and won't delete anything else. 53 | This issue should be fixed now that restart has been replaced with abandon but might still appear for a bit if you've used the restart command recently. 54 | 55 | Donations: 56 | 57 | As of right now, I am not accepting donations and recommend you support NVDA instead. https://www.nvaccess.org/support-us/ 58 | 59 | Installation: 60 | 61 | Note: If you use gog go here https://forum.audiogames.net/topic/35130/slay-the-spire-now-accessible/ 62 | 63 | Step 1: 64 | 65 | If you have not yet, install Steam, create an account, and install Java. 66 | 67 | Step 2: 68 | 69 | Download Slay the Spire from the Steam webpage. You do not need to do so through the Steam client which is harder for screen readers. 70 | Subscribe to both BaseMod and ModTheSpire. 71 | 72 | Step 3: 73 | 74 | Find the Slay the Spire directory. In Windows the directory path should be similar to C/Program Files x 86/Steam/steamapps/common/SlayTheSpire. 75 | 76 | Step 4: 77 | 78 | Create a shortcut of the file mts-launder.jar on your desktop. This is how you will start the game. 79 | 80 | Step 5: 81 | 82 | Double click mts-launder to launch the mod. The first time you will need to select the mods. 83 | There is a select all option on the Mod the Spire window that will show up. 84 | Afterwards they will be auto selected. Hit enter to start the game. One more step. 85 | 86 | Step 6: 87 | 88 | You will need to set a save file name if you don't have a save file yet. The Choices window should tell you how. -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Orbs.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.cards.AbstractCard; 5 | import com.megacrit.cardcrawl.cards.CardGroup; 6 | import com.megacrit.cardcrawl.characters.AbstractPlayer; 7 | import com.megacrit.cardcrawl.core.CardCrawlGame; 8 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 9 | import com.megacrit.cardcrawl.orbs.*; 10 | import com.megacrit.cardcrawl.potions.AbstractPotion; 11 | import com.megacrit.cardcrawl.relics.AbstractRelic; 12 | import com.megacrit.cardcrawl.relics.GoldPlatedCables; 13 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 14 | import communicationmod.CommandExecutor; 15 | import guardian.characters.GuardianCharacter; 16 | import org.eclipse.swt.widgets.Display; 17 | 18 | import java.util.ArrayList; 19 | 20 | public class Orbs extends AbstractWindow{ 21 | 22 | public Orbs(Display display){ 23 | isVisible = true; 24 | window = new Window(display,"Orbs",300,300); 25 | } 26 | 27 | public String getText(){ 28 | 29 | if(window.shell.isDisposed()){ 30 | Display.getDefault().dispose(); 31 | Gdx.app.exit(); 32 | } 33 | 34 | StringBuilder s = new StringBuilder(); 35 | s.append("\r\n"); 36 | 37 | //If not in dungeon 38 | if(CardCrawlGame.dungeon == null || !CommandExecutor.isInDungeon() || !CardCrawlGame.isInARun()){ 39 | return ""; 40 | } 41 | 42 | //If in combat 43 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 44 | 45 | AbstractPlayer p = AbstractDungeon.player; 46 | 47 | ArrayList ol = p.orbs; 48 | 49 | int frostTotal = 0; 50 | int lightningTotal = 0; 51 | 52 | for(AbstractOrb o : ol){ 53 | if(o instanceof Lightning){ 54 | lightningTotal += o.passiveAmount; 55 | } 56 | if(o instanceof Frost){ 57 | frostTotal += o.passiveAmount; 58 | } 59 | } 60 | 61 | for(AbstractRelic r : AbstractDungeon.player.relics){ 62 | if(r instanceof GoldPlatedCables){ 63 | if(ol.get(0) instanceof Frost){ 64 | frostTotal += ol.get(0).passiveAmount; 65 | } else if(ol.get(0) instanceof Lightning){ 66 | lightningTotal += ol.get(0).passiveAmount; 67 | } 68 | break; 69 | } 70 | } 71 | 72 | if(frostTotal > 0 || lightningTotal > 0){ 73 | s.append("End of Turn Passive Totals:\r\n"); 74 | if(frostTotal > 0){ 75 | s.append("Frost: ").append(frostTotal).append("\r\n"); 76 | } 77 | if(lightningTotal > 0){ 78 | s.append("Lightning: ").append(lightningTotal).append("\r\n"); 79 | } 80 | } 81 | 82 | s.append("Front\r\n"); 83 | 84 | int count = 0; 85 | 86 | for (AbstractOrb o : ol) { 87 | if (o instanceof Dark) { 88 | s.append(count).append(". Dark ").append(o.evokeAmount).append("\r\n"); 89 | } else{ 90 | if(TextTheSpire.downfall && AbstractDungeon.player instanceof GuardianCharacter){ 91 | s.append(count).append(". ").append(o.name).append(" ").append(o.passiveAmount).append("\r\n"); 92 | } else { 93 | s.append(count).append(". ").append(o.name).append("\r\n"); 94 | } 95 | } 96 | count++; 97 | } 98 | 99 | s.append("Back\r\n"); 100 | return s.toString(); 101 | 102 | }else{ 103 | //If not in combat 104 | return ""; 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Player.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.characters.AbstractPlayer; 5 | import com.megacrit.cardcrawl.core.CardCrawlGame; 6 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 7 | import com.megacrit.cardcrawl.orbs.*; 8 | import com.megacrit.cardcrawl.potions.AbstractPotion; 9 | import com.megacrit.cardcrawl.powers.AbstractPower; 10 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 11 | import com.megacrit.cardcrawl.stances.NeutralStance; 12 | import com.megacrit.cardcrawl.ui.panels.EnergyPanel; 13 | import communicationmod.CommandExecutor; 14 | import org.eclipse.swt.widgets.Display; 15 | import org.eclipse.swt.widgets.Text; 16 | import theHexaghost.GhostflameHelper; 17 | import theHexaghost.TheHexaghost; 18 | import theHexaghost.ghostflames.AbstractGhostflame; 19 | import theThorton.ThortMod; 20 | import theThorton.characters.TheThorton; 21 | import theThorton.utilPatch.GhostsThortonEvent; 22 | 23 | import java.util.ArrayList; 24 | 25 | public class Player extends AbstractWindow{ 26 | 27 | public Player(Display display){ 28 | isVisible = true; 29 | window = new Window(display,"Player",300,300); 30 | } 31 | 32 | public String getText(){ 33 | 34 | if(window.shell.isDisposed()){ 35 | Display.getDefault().dispose(); 36 | Gdx.app.exit(); 37 | } 38 | 39 | StringBuilder s = new StringBuilder(); 40 | s.append("\r\n"); 41 | 42 | //Not in dungeon 43 | if(CardCrawlGame.dungeon == null || !CommandExecutor.isInDungeon() || !CardCrawlGame.isInARun()){ 44 | return ""; 45 | } 46 | 47 | AbstractPlayer p = AbstractDungeon.player; 48 | 49 | //In combat show all player stats 50 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 51 | 52 | s.append("Block: ").append(p.currentBlock).append("\r\n"); 53 | s.append("Health: ").append(p.currentHealth).append("/").append(p.maxHealth).append("\r\n"); 54 | s.append("Energy: ").append(EnergyPanel.totalCount).append("\r\n"); 55 | 56 | //Display orbs if Defect or have channeled orbs 57 | 58 | //If not neutral stance display it 59 | if (!(p.stance instanceof NeutralStance)) { 60 | s.append("Stance: ").append(p.stance.name).append("\r\n"); 61 | } 62 | 63 | if(TextTheSpire.thorton && AbstractDungeon.player instanceof TheThorton){ 64 | s.append("Business Cards : ").append(ThortMod.businessCardAmt).append("/").append(ThortMod.businessCardMax).append("\r\n"); 65 | s.append("Investments : ").append(ThortMod.investmentAmt).append("/").append(ThortMod.investmentMax).append("\r\n"); 66 | s.append("Flee : ").append(ThortMod.fleeAmt).append("/").append(ThortMod.fleeMax).append("\r\n"); 67 | } 68 | 69 | int count = 0; 70 | ArrayList po = p.powers; 71 | if(po.size() > 0) { 72 | s.append("Powers:\r\n"); 73 | for (AbstractPower ap : po) { 74 | s.append(count).append(": ").append(ap.name).append(" ").append(ap.amount).append("\r\n"); 75 | count++; 76 | } 77 | } 78 | 79 | if(TextTheSpire.downfall && AbstractDungeon.player instanceof TheHexaghost){ 80 | s.append("Ghostflames:\r\n"); 81 | count = 0; 82 | for(AbstractGhostflame gf : GhostflameHelper.hexaGhostFlames){ 83 | s.append(count).append(":").append(gf.getName().replace("Ghostflame", "")); 84 | if(GhostflameHelper.activeGhostFlame == gf){ 85 | s.append("active "); 86 | }else{ 87 | s.append("inactive "); 88 | } 89 | if(gf.charged){ 90 | s.append("ignite\r\n"); 91 | }else{ 92 | s.append("extinguish\r\n"); 93 | } 94 | count++; 95 | } 96 | } 97 | 98 | }else{ 99 | 100 | //Out of combat show persistent stats 101 | s.append("Health: ").append(p.currentHealth).append("/").append(p.maxHealth).append("\r\n"); 102 | 103 | s.append("Gold:").append(p.gold).append("\r\n"); 104 | 105 | if(TextTheSpire.thorton && AbstractDungeon.player instanceof TheThorton){ 106 | s.append("Business Cards : ").append(ThortMod.businessCardAmt).append("/").append(ThortMod.businessCardMax).append("\r\n"); 107 | s.append("Investments : ").append(ThortMod.investmentAmt).append("/").append(ThortMod.investmentMax).append("\r\n"); 108 | s.append("Flee : ").append(ThortMod.fleeAmt).append("/").append(ThortMod.fleeMax).append("\r\n"); 109 | } 110 | 111 | //Hand window is gone so show potions in player out of combat 112 | ArrayList pl = p.potions; 113 | 114 | int count = 0; 115 | if (pl.size() > 0) { 116 | s.append("Potions:\r\n"); 117 | for (AbstractPotion po : pl) { 118 | s.append(count).append(": ").append(po.name).append("\r\n"); 119 | count++; 120 | } 121 | } 122 | } 123 | 124 | return s.toString(); 125 | 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /TextTheSpire.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Custom.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import basemod.ReflectionHacks; 4 | import com.badlogic.gdx.Gdx; 5 | import com.megacrit.cardcrawl.cards.AbstractCard; 6 | import com.megacrit.cardcrawl.cards.CardGroup; 7 | import com.megacrit.cardcrawl.characters.AbstractPlayer; 8 | import com.megacrit.cardcrawl.core.CardCrawlGame; 9 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 10 | import com.megacrit.cardcrawl.events.shrines.GremlinMatchGame; 11 | import com.megacrit.cardcrawl.events.shrines.GremlinWheelGame; 12 | import com.megacrit.cardcrawl.helpers.TipTracker; 13 | import com.megacrit.cardcrawl.map.MapRoomNode; 14 | import com.megacrit.cardcrawl.rewards.RewardItem; 15 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 16 | import com.megacrit.cardcrawl.screens.custom.CustomMod; 17 | import com.megacrit.cardcrawl.screens.custom.CustomModeCharacterButton; 18 | import com.megacrit.cardcrawl.screens.custom.CustomModeScreen; 19 | import com.megacrit.cardcrawl.screens.mainMenu.MainMenuScreen; 20 | import com.megacrit.cardcrawl.screens.stats.StatsScreen; 21 | import com.megacrit.cardcrawl.shop.ShopScreen; 22 | import com.megacrit.cardcrawl.shop.StorePotion; 23 | import com.megacrit.cardcrawl.shop.StoreRelic; 24 | import com.megacrit.cardcrawl.ui.buttons.LargeDialogOptionButton; 25 | import communicationmod.ChoiceScreenUtils; 26 | import communicationmod.CommandExecutor; 27 | import communicationmod.patches.GremlinMatchGamePatch; 28 | import org.eclipse.swt.widgets.Display; 29 | 30 | import java.util.ArrayList; 31 | 32 | public class Custom extends AbstractWindow{ 33 | 34 | public Custom(Display display){ 35 | isVisible = true; 36 | window = new Window(display,"Custom", 300, 300); 37 | } 38 | 39 | @SuppressWarnings("unchecked") 40 | public String getText(){ 41 | 42 | if(window.shell.isDisposed()){ 43 | Display.getDefault().dispose(); 44 | Gdx.app.exit(); 45 | } 46 | 47 | if(CardCrawlGame.mainMenuScreen == null || CardCrawlGame.mainMenuScreen.screen != MainMenuScreen.CurScreen.CUSTOM || CardCrawlGame.mainMenuScreen.customModeScreen == null || CommandExecutor.isInDungeon()){ 48 | return ""; 49 | } 50 | 51 | StringBuilder s = new StringBuilder(); 52 | s.append("\r\nCustom Mode\r\n"); 53 | 54 | s.append("Character Selected "); 55 | 56 | StringBuilder options = new StringBuilder("\r\nOptions\r\n"); 57 | 58 | for(int i=0; i < CardCrawlGame.mainMenuScreen.customModeScreen.options.size(); i++){ 59 | CustomModeCharacterButton c = CardCrawlGame.mainMenuScreen.customModeScreen.options.get(i); 60 | if(c.selected){ 61 | s.append(c.c.getClass().getSimpleName()); 62 | } 63 | options.append(i).append(" ").append(c.c.getClass().getSimpleName()).append("\r\n"); 64 | } 65 | 66 | s.append(options); 67 | 68 | s.append("Ascension "); 69 | if(CardCrawlGame.mainMenuScreen.customModeScreen.isAscensionMode){ 70 | s.append(CardCrawlGame.mainMenuScreen.customModeScreen.ascensionLevel).append("\r\n"); 71 | }else{ 72 | s.append("Off\r\n"); 73 | } 74 | 75 | s.append("Seed"); 76 | 77 | String seed = (String) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.customModeScreen, CustomModeScreen.class, "currentSeed"); 78 | 79 | if(seed == null || seed.isEmpty()) { 80 | s.append(" none\r\n"); 81 | }else{ 82 | s.append("\r\n").append(seed).append("\r\n"); 83 | } 84 | 85 | s.append("Mods\r\n"); 86 | 87 | ArrayList modList = (ArrayList) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.customModeScreen, CustomModeScreen.class, "modList"); 88 | 89 | for(int i=0; i modList = (ArrayList) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.customModeScreen, CustomModeScreen.class, "modList"); 137 | 138 | for(CustomMod c : modList){ 139 | if(c.selected){ 140 | s.append(c.name).append("\r\n"); 141 | } 142 | } 143 | 144 | return s.toString(); 145 | } 146 | 147 | } 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Event.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import basemod.ReflectionHacks; 4 | import com.badlogic.gdx.Gdx; 5 | import com.megacrit.cardcrawl.core.CardCrawlGame; 6 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 7 | import com.megacrit.cardcrawl.events.AbstractEvent; 8 | import com.megacrit.cardcrawl.events.AbstractImageEvent; 9 | import com.megacrit.cardcrawl.events.GenericEventDialog; 10 | import com.megacrit.cardcrawl.events.RoomEventDialog; 11 | import com.megacrit.cardcrawl.mod.replay.monsters.replay.FadingForestBoss; 12 | import com.megacrit.cardcrawl.monsters.AbstractMonster; 13 | import com.megacrit.cardcrawl.relics.AbstractRelic; 14 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 15 | import com.megacrit.cardcrawl.screens.DeathScreen; 16 | import com.megacrit.cardcrawl.screens.GameOverScreen; 17 | import com.megacrit.cardcrawl.screens.GameOverStat; 18 | import com.megacrit.cardcrawl.screens.VictoryScreen; 19 | import com.megacrit.cardcrawl.screens.leaderboards.LeaderboardEntry; 20 | import com.megacrit.cardcrawl.screens.mainMenu.MainMenuScreen; 21 | import com.megacrit.cardcrawl.screens.mainMenu.PatchNotesScreen; 22 | import com.megacrit.cardcrawl.ui.DialogWord; 23 | import com.megacrit.cardcrawl.unlock.AbstractUnlock; 24 | import communicationmod.ChoiceScreenUtils; 25 | import communicationmod.CommandExecutor; 26 | import org.eclipse.swt.widgets.Display; 27 | 28 | import javax.smartcardio.Card; 29 | import java.awt.*; 30 | import java.util.ArrayList; 31 | 32 | public class Event extends AbstractWindow{ 33 | 34 | 35 | public Event(Display display){ 36 | isVisible = true; 37 | window = new Window(display,"Event",400,500); 38 | } 39 | 40 | @SuppressWarnings("unchecked") 41 | public String getText(){ 42 | 43 | if(window.shell.isDisposed()){ 44 | Display.getDefault().dispose(); 45 | Gdx.app.exit(); 46 | } 47 | 48 | StringBuilder s = new StringBuilder(); 49 | s.append("\r\n"); 50 | 51 | if(AbstractDungeon.screen == AbstractDungeon.CurrentScreen.DEATH){ 52 | s.append("Death\r\nScore ").append(DeathScreen.calcScore(false)).append("\r\n"); 53 | for(GameOverStat g : ((ArrayList)ReflectionHacks.getPrivate(AbstractDungeon.deathScreen, GameOverScreen.class, "stats"))){ 54 | if(g.label != null){ 55 | s.append(g.label).append(": ").append(g.value); 56 | if(g.description != null){ 57 | s.append(", ").append(g.description); 58 | } 59 | s.append("\r\n"); 60 | } 61 | } 62 | 63 | ArrayList unlockBundle = ((ArrayList)ReflectionHacks.getPrivate(AbstractDungeon.deathScreen, GameOverScreen.class, "unlockBundle")); 64 | 65 | if(unlockBundle != null){ 66 | for(AbstractUnlock u : unlockBundle){ 67 | switch (u.type){ 68 | case CARD: 69 | s.append("Unlock Card ").append(TextTheSpire.inspectCard(u.card)).append("\r\n"); 70 | break; 71 | case RELIC: 72 | s.append("Unlock Relic ").append(TextTheSpire.inspectRelic(u.relic)).append("\r\n"); 73 | break; 74 | } 75 | } 76 | } 77 | 78 | return s.toString(); 79 | } 80 | if(AbstractDungeon.screen == AbstractDungeon.CurrentScreen.VICTORY){ 81 | s.append("Victory\r\nScore").append(VictoryScreen.calcScore(true)).append("\r\n"); 82 | 83 | for(GameOverStat g : ((ArrayList)ReflectionHacks.getPrivate(AbstractDungeon.victoryScreen, GameOverScreen.class, "stats"))){ 84 | if(g.label != null){ 85 | s.append(g.label).append(": ").append(g.value); 86 | if(g.description != null){ 87 | s.append(", ").append(g.description); 88 | } 89 | s.append("\r\n"); 90 | } 91 | } 92 | 93 | ArrayList unlockBundle = ((ArrayList)ReflectionHacks.getPrivate(AbstractDungeon.victoryScreen, GameOverScreen.class, "unlockBundle")); 94 | 95 | if(unlockBundle != null){ 96 | for(AbstractUnlock u : unlockBundle){ 97 | switch (u.type){ 98 | case CARD: 99 | s.append("Unlock Card ").append(TextTheSpire.inspectCard(u.card)).append("\r\n"); 100 | break; 101 | case RELIC: 102 | s.append("Unlock Relic ").append(TextTheSpire.inspectRelic(u.relic)).append("\r\n"); 103 | break; 104 | } 105 | } 106 | } 107 | 108 | return s.toString(); 109 | } 110 | if(AbstractDungeon.screen == AbstractDungeon.CurrentScreen.UNLOCK){ 111 | if(AbstractDungeon.unlockScreen.unlock.type == AbstractUnlock.UnlockType.CHARACTER){ 112 | s.append("Unlock Character\r\n").append(AbstractDungeon.unlockScreen.unlock.player.getClass().getSimpleName()).append("\r\n"); 113 | return s.toString(); 114 | } 115 | } 116 | 117 | if(CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.screen == MainMenuScreen.CurScreen.DAILY && !CommandExecutor.isInDungeon()){ 118 | s.append(TextTheSpire.inspectDaily()); 119 | return s.toString(); 120 | } 121 | 122 | if(CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.screen == MainMenuScreen.CurScreen.LEADERBOARD && !CommandExecutor.isInDungeon()){ 123 | s.append("Leaderboard\r\n"); 124 | for(LeaderboardEntry e : CardCrawlGame.mainMenuScreen.leaderboardsScreen.entries){ 125 | s.append(e.rank).append(". ").append(e.name).append(" : "); 126 | for(int i=0;i words; 169 | 170 | if (AbstractDungeon.getCurrRoom().event instanceof AbstractImageEvent || fable) { 171 | words = (ArrayList) basemod.ReflectionHacks.getPrivateStatic(GenericEventDialog.class, "words"); 172 | } else { 173 | words = (ArrayList) basemod.ReflectionHacks.getPrivate(AbstractDungeon.getCurrRoom().event.roomEventText, RoomEventDialog.class, "words"); 174 | } 175 | 176 | 177 | for(DialogWord w : words){ 178 | body.append(w.word); 179 | char punctuation = w.word.charAt(w.word.length()-1); 180 | if(punctuation == '.' || punctuation == '?' || punctuation == '!'){ 181 | body.append("\r\n"); 182 | }else{ 183 | body.append(" "); 184 | } 185 | } 186 | 187 | s.append(body.toString()); 188 | 189 | return s.toString(); 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Monster.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import charbosses.bosses.AbstractCharBoss; 4 | import charbosses.stances.AbstractEnemyStance; 5 | import charbosses.stances.EnNeutralStance; 6 | import charbosses.ui.EnemyEnergyPanel; 7 | import com.badlogic.gdx.Gdx; 8 | import com.megacrit.cardcrawl.cards.AbstractCard; 9 | import com.megacrit.cardcrawl.core.CardCrawlGame; 10 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 11 | import com.megacrit.cardcrawl.monsters.AbstractMonster; 12 | import com.megacrit.cardcrawl.orbs.AbstractOrb; 13 | import com.megacrit.cardcrawl.orbs.Dark; 14 | import com.megacrit.cardcrawl.powers.AbstractPower; 15 | import com.megacrit.cardcrawl.relics.AbstractRelic; 16 | import com.megacrit.cardcrawl.relics.RunicDome; 17 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 18 | import com.megacrit.cardcrawl.stances.NeutralStance; 19 | import communicationmod.CommandExecutor; 20 | import org.eclipse.swt.widgets.Display; 21 | 22 | import java.util.ArrayList; 23 | 24 | public class Monster extends AbstractWindow{ 25 | 26 | public int totalDmg = 0; 27 | 28 | public Monster(Display display){ 29 | isVisible = true; 30 | window = new Window(display,"Monster", 400, 600); 31 | } 32 | 33 | public String getText(){ 34 | 35 | if(window.shell.isDisposed()){ 36 | Display.getDefault().dispose(); 37 | Gdx.app.exit(); 38 | } 39 | 40 | StringBuilder s = new StringBuilder(); 41 | 42 | //If not in dungeon 43 | if(CardCrawlGame.dungeon == null || !CommandExecutor.isInDungeon() || !CardCrawlGame.isInARun()){ 44 | return ""; 45 | } 46 | 47 | //If in combat 48 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 49 | 50 | int count = 0; 51 | int totalAlive = 0; 52 | totalDmg = 0; 53 | 54 | for(AbstractMonster m : AbstractDungeon.getCurrRoom().monsters.monsters){ 55 | 56 | if(m.currentHealth > 0) { 57 | 58 | totalAlive++; 59 | 60 | s.append(count).append(": ").append(m.name).append("\r\n"); 61 | s.append("Block: ").append(m.currentBlock).append("\r\n"); 62 | s.append("HP: ").append(m.currentHealth).append("/").append(m.maxHealth).append("\r\n"); 63 | 64 | if (!runicDome() && !(TextTheSpire.downfall && m instanceof AbstractCharBoss)) 65 | s.append(monsterIntent(m)); 66 | 67 | int powCount = 0; 68 | ArrayList p = m.powers; 69 | if(p.size() > 0) { 70 | s.append("Powers:\r\n"); 71 | for (AbstractPower ap : p) { 72 | s.append(powCount).append(": ").append(ap.name).append(" ").append(ap.amount).append("\r\n"); 73 | powCount++; 74 | } 75 | } 76 | 77 | if(TextTheSpire.downfall && m instanceof AbstractCharBoss){ 78 | s.append("Hand:\r\n"); 79 | int hand_count = 0; 80 | for(AbstractCard c : ((AbstractCharBoss) m).hand.group){ 81 | s.append(hand_count).append(": ").append(c.name).append("\r\n"); 82 | hand_count++; 83 | } 84 | s.append("Energy: ").append(EnemyEnergyPanel.totalCount).append("\r\n"); 85 | if(((AbstractCharBoss) m).orbs.size() > 0){ 86 | int orb_count = 0; 87 | s.append("Orbs:\r\n"); 88 | for(AbstractOrb o : ((AbstractCharBoss) m).orbs){ 89 | if (o instanceof Dark) { 90 | s.append(orb_count).append(": ").append(count).append("Dark ").append(o.evokeAmount).append("\r\n"); 91 | } else { 92 | s.append(orb_count).append(": ").append(o.name).append("\r\n"); 93 | } 94 | } 95 | } 96 | if (((AbstractCharBoss) m).stance instanceof AbstractEnemyStance) { 97 | s.append("Stance: ").append(((AbstractEnemyStance)((AbstractCharBoss) m).stance).ID).append("\r\n"); 98 | } 99 | s.append("Relics:\r\n"); 100 | int relic_count = 0; 101 | for(AbstractRelic r : ((AbstractCharBoss) m).relics){ 102 | if(r.counter >= 0){ 103 | s.append(relic_count).append(": ").append(r.name).append(" ").append(r.counter).append("\r\n"); 104 | }else{ 105 | s.append(relic_count).append(": ").append(r.name).append("\r\n"); 106 | } 107 | relic_count++; 108 | } 109 | s.append("b [h/o/r] [index]\r\n"); 110 | } 111 | } 112 | count++; 113 | 114 | } 115 | 116 | if(!(TextTheSpire.downfall && AbstractDungeon.getCurrRoom().monsters.monsters.get(0) instanceof AbstractCharBoss)) 117 | s.insert(0, "\r\nCount: " + totalAlive + "\r\n" + "Incoming: " + totalDmg + "\r\n"); 118 | 119 | return s.toString(); 120 | 121 | }else{ 122 | //If not in combat 123 | return ""; 124 | } 125 | } 126 | 127 | public boolean runicDome(){ 128 | for(AbstractRelic r : AbstractDungeon.player.relics){ 129 | if(r instanceof RunicDome){ 130 | return true; 131 | } 132 | } 133 | return false; 134 | } 135 | 136 | /* 137 | Params: 138 | m - any Monster on the field 139 | Returns: 140 | String containing m's intent 141 | */ 142 | public String monsterIntent(AbstractMonster m){ 143 | 144 | AbstractMonster.Intent i = m.intent; 145 | int multi; 146 | 147 | if (i == AbstractMonster.Intent.ATTACK) { 148 | multi = getMulti(m); 149 | if(multi > 1) { 150 | totalDmg += m.getIntentDmg() * multi; 151 | return "Intent: Attack " + m.getIntentDmg() + " x " + multi + "\r\n"; 152 | } else { 153 | totalDmg += m.getIntentDmg(); 154 | return "Intent: Attack " + m.getIntentDmg() + "\r\n"; 155 | } 156 | } else if (i == AbstractMonster.Intent.ATTACK_BUFF) { 157 | multi = getMulti(m); 158 | if(multi > 1) { 159 | totalDmg += m.getIntentDmg() * multi; 160 | return "Intent: Attack/Buff " + m.getIntentDmg() + " x " + multi + "\r\n"; 161 | } else { 162 | totalDmg += m.getIntentDmg(); 163 | return "Intent: Attack/Buff " + m.getIntentDmg() + "\r\n"; 164 | } 165 | } else if (i == AbstractMonster.Intent.ATTACK_DEFEND) { 166 | multi = getMulti(m); 167 | if(multi > 1) { 168 | totalDmg += m.getIntentDmg() * multi; 169 | return "Intent: Attack/Defend " + m.getIntentDmg() + " x " + multi + "\r\n"; 170 | } else { 171 | totalDmg += m.getIntentDmg(); 172 | return "Intent: Attack/Defend " + m.getIntentDmg() + "\r\n"; 173 | } 174 | } else if (i == AbstractMonster.Intent.ATTACK_DEBUFF) { 175 | multi = getMulti(m); 176 | if(multi > 1) { 177 | totalDmg += m.getIntentDmg() * multi; 178 | return "Intent: Attack/Debuff " + m.getIntentDmg() + " x " + multi + "\r\n"; 179 | } else { 180 | totalDmg += m.getIntentDmg(); 181 | return "Intent: Attack/Debuff " + m.getIntentDmg() + "\r\n"; 182 | } 183 | } else if (i == AbstractMonster.Intent.BUFF) { 184 | return "Intent: Buff" + "\r\n"; 185 | } else if (i == AbstractMonster.Intent.DEBUFF) { 186 | return "Intent: Debuff" + "\r\n"; 187 | } else if (i == AbstractMonster.Intent.STRONG_DEBUFF) { 188 | return "Intent: Strong Debuff" + "\r\n"; 189 | } else if (i == AbstractMonster.Intent.DEFEND) { 190 | return "Intent: Defend" + "\r\n"; 191 | } else if (i == AbstractMonster.Intent.DEFEND_DEBUFF) { 192 | return "Intent: Defend/Debuff" + "\r\n"; 193 | } else if (i == AbstractMonster.Intent.DEFEND_BUFF) { 194 | return "Intent: Defend/Buff" + "\r\n"; 195 | } else if (i == AbstractMonster.Intent.ESCAPE) { 196 | return "Intent: Escape" + "\r\n"; 197 | } else if (i == AbstractMonster.Intent.MAGIC) { 198 | return "Intent: MAGIC" + "\r\n"; 199 | } else if (i == AbstractMonster.Intent.NONE) { 200 | return "Intent: NONE" + "\r\n"; 201 | } else if (i == AbstractMonster.Intent.SLEEP) { 202 | return "Intent: Sleep" + "\r\n"; 203 | } else if (i == AbstractMonster.Intent.STUN) { 204 | return "Intent: Stun" + "\r\n"; 205 | } else if (i == AbstractMonster.Intent.UNKNOWN) { 206 | return "Intent: Unknown" + "\r\n"; 207 | } else{ 208 | return "Intent: Loading" + "\r\n"; 209 | } 210 | } 211 | 212 | /* 213 | Params: 214 | m - Monster on field 215 | Returns: 216 | The number of hits in m's intent 217 | */ 218 | public int getMulti(AbstractMonster m){ 219 | 220 | return (int) basemod.ReflectionHacks.getPrivate(m, AbstractMonster.class, "intentMultiAmt"); 221 | 222 | } 223 | 224 | } 225 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Map.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 5 | import com.megacrit.cardcrawl.dungeons.TheEnding; 6 | import com.megacrit.cardcrawl.map.MapRoomNode; 7 | import com.megacrit.cardcrawl.mod.replay.rooms.PsuedoBonfireRoom; 8 | import com.megacrit.cardcrawl.mod.replay.rooms.TeleportRoom; 9 | import com.megacrit.cardcrawl.rooms.*; 10 | import communicationmod.ChoiceScreenUtils; 11 | import communicationmod.CommandExecutor; 12 | import communicationmod.patches.DungeonMapPatch; 13 | import communicationmod.patches.MapRoomNodeHoverPatch; 14 | import downfall.patches.EvilModeCharacterSelect; 15 | import org.eclipse.swt.widgets.Display; 16 | import replayTheSpire.patches.BonfirePatches; 17 | 18 | import java.util.ArrayList; 19 | 20 | public class Map extends AbstractWindow{ 21 | 22 | public Map(Display display){ 23 | isVisible = true; 24 | window = new Window(display,"Map", 550, 425); 25 | } 26 | 27 | public String getText(){ 28 | 29 | if(window.shell.isDisposed()){ 30 | Display.getDefault().dispose(); 31 | Gdx.app.exit(); 32 | } 33 | 34 | if(TextTheSpire.downfall && EvilModeCharacterSelect.evilMode){ 35 | return downfallMap(); 36 | } 37 | 38 | if(Inspect.has_inspected && AbstractDungeon.currMapNode.y >= Inspect.destination.y){ 39 | Inspect.has_inspected = false; 40 | } 41 | 42 | StringBuilder s = new StringBuilder(); 43 | s.append("\r\n"); 44 | 45 | //Is only displayed when on map screen 46 | if(CommandExecutor.isInDungeon() && !(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT)) { 47 | 48 | s.append(AbstractDungeon.bossKey).append("\r\n"); 49 | 50 | ArrayList> m = AbstractDungeon.map; 51 | //Current position 52 | s.append("Current= Floor:").append(AbstractDungeon.currMapNode.y + 1).append(" X:").append(AbstractDungeon.currMapNode.x).append("\r\n"); 53 | s.append("\r\n"); 54 | 55 | //Either display all nodes. 56 | if(AbstractDungeon.currMapNode.y == 15 || AbstractDungeon.currMapNode.y == -1) { 57 | 58 | int currFloor = AbstractDungeon.currMapNode.y; 59 | 60 | if(currFloor == 15) 61 | currFloor = -1; 62 | 63 | for (int i = m.size() - 1; i >= (currFloor + 1); i--) { 64 | 65 | 66 | for (MapRoomNode n : m.get(i)) { 67 | 68 | if (n.hasEdges()) { 69 | s.append(nodeType(n)).append("Floor:").append(i + 1).append(" X:").append(n.x).append("\r\n"); 70 | } 71 | 72 | } 73 | 74 | s.append("\r\n"); 75 | 76 | } 77 | }else{ 78 | 79 | //Or only display ones reachable from current node 80 | StringBuilder limitedMap = new StringBuilder(); 81 | StringBuilder limitedFloor; 82 | StringBuilder limitedNode; 83 | 84 | ArrayList current = new ArrayList(); 85 | ArrayList prev = new ArrayList(); 86 | 87 | prev.add(AbstractDungeon.currMapNode); 88 | 89 | for(int i=(AbstractDungeon.currMapNode.y + 1);i 0) { 102 | limitedFloor.append(limitedNode); 103 | current.add(n); 104 | } else if(AbstractDungeon.player.hasRelic("WingedGreaves") && (AbstractDungeon.player.getRelic("WingedGreaves")).counter > 0 && n.getParents().size() > 0){ 105 | limitedFloor.append("Winged ").append(nodeType(n)).append(" Floor:").append(i + 1).append(" X: ").append(n.x).append("\r\n"); 106 | } 107 | 108 | } 109 | 110 | limitedFloor.append("\r\n"); 111 | 112 | prev.clear(); 113 | prev.addAll(current); 114 | current.clear(); 115 | limitedMap.insert(0, limitedFloor); 116 | 117 | } 118 | 119 | s.append(limitedMap); 120 | 121 | } 122 | 123 | return s.toString(); 124 | 125 | }else{ 126 | return ""; 127 | } 128 | } 129 | 130 | public String downfallMap(){ 131 | StringBuilder s = new StringBuilder("\r\n"); 132 | 133 | if(Inspect.has_inspected && AbstractDungeon.currMapNode.y <= Inspect.destination.y){ 134 | Inspect.has_inspected = false; 135 | } 136 | 137 | if(CommandExecutor.isInDungeon() && !(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT)) { 138 | 139 | s.append(AbstractDungeon.bossKey).append("\r\n"); 140 | 141 | ArrayList> m = AbstractDungeon.map; 142 | //Current position 143 | int currFloor = AbstractDungeon.currMapNode.y; 144 | if(currFloor == -1) 145 | currFloor = 15; 146 | 147 | s.append("Current= Floor:").append(currFloor + 1).append(" X:").append(AbstractDungeon.currMapNode.x).append("\r\n"); 148 | s.append("\r\n"); 149 | 150 | //Either display all nodes. 151 | if(currFloor == 15) { 152 | 153 | for (int i = 0; i < m.size(); i++) { 154 | 155 | for (MapRoomNode n : m.get(i)) { 156 | 157 | if (n.hasEdges()) { 158 | s.append(nodeType(n)).append("Floor:").append(i + 1).append(" X:").append(n.x).append("\r\n"); 159 | } 160 | 161 | } 162 | 163 | s.append("\r\n"); 164 | 165 | } 166 | }else{ 167 | 168 | //Or only display ones reachable from current node 169 | StringBuilder limitedMap = new StringBuilder(); 170 | StringBuilder limitedFloor; 171 | StringBuilder limitedNode; 172 | 173 | ArrayList current = new ArrayList(); 174 | ArrayList prev = new ArrayList(); 175 | 176 | prev.add(AbstractDungeon.currMapNode); 177 | 178 | for(int i=(AbstractDungeon.currMapNode.y - 1);i>=0;i-- ){ 179 | limitedFloor = new StringBuilder(); 180 | 181 | for(MapRoomNode n : m.get(i)){ 182 | limitedNode = new StringBuilder(); 183 | 184 | for (MapRoomNode child : prev) { 185 | if (child.isConnectedTo(n)) { 186 | limitedNode.append(nodeType(n)).append(" Floor:").append(i + 1).append(" X: ").append(n.x).append("\r\n"); 187 | break; 188 | } 189 | } 190 | if(limitedNode.length() > 0) { 191 | limitedFloor.append(limitedNode); 192 | current.add(n); 193 | } else if(AbstractDungeon.player.hasRelic("WingedGreaves") && (AbstractDungeon.player.getRelic("WingedGreaves")).counter > 0 && n.getParents().size() > 0){ 194 | limitedFloor.append("Winged ").append(nodeType(n)).append(" Floor:").append(i + 1).append(" X: ").append(n.x).append("\r\n"); 195 | } 196 | 197 | } 198 | 199 | limitedFloor.append("\r\n"); 200 | 201 | prev.clear(); 202 | prev.addAll(current); 203 | current.clear(); 204 | limitedMap.insert(0, limitedFloor); 205 | 206 | } 207 | 208 | s.append(limitedMap); 209 | 210 | } 211 | 212 | return s.toString(); 213 | 214 | }else{ 215 | return ""; 216 | } 217 | } 218 | 219 | public static void downfallMapChoice(int choice){ 220 | MapRoomNode currMapNode = AbstractDungeon.getCurrMapNode(); 221 | if(currMapNode.y == 0) { 222 | if(choice == 0) { 223 | DungeonMapPatch.doBossHover = true; 224 | return; 225 | } else { 226 | throw new IndexOutOfBoundsException("Only a boss node can be chosen here."); 227 | } 228 | } 229 | ArrayList nodeChoices = getMapScreenNodeChoices(); 230 | MapRoomNodeHoverPatch.hoverNode = nodeChoices.get(choice); 231 | MapRoomNodeHoverPatch.doHover = true; 232 | AbstractDungeon.dungeonMapScreen.clicked = true; 233 | } 234 | 235 | public static ArrayList getMapScreenNodeChoices() { 236 | ArrayList choices = new ArrayList<>(); 237 | MapRoomNode currMapNode = AbstractDungeon.getCurrMapNode(); 238 | ArrayList> map = AbstractDungeon.map; 239 | if(!AbstractDungeon.firstRoomChosen) { 240 | for(MapRoomNode node : map.get(14)) { 241 | if (node.hasEdges()) { 242 | choices.add(node); 243 | } 244 | } 245 | } else { 246 | for (ArrayList rows : map) { 247 | for (MapRoomNode node : rows) { 248 | if (node.hasEdges()) { 249 | boolean normalConnection = currMapNode.isConnectedTo(node); 250 | boolean wingedConnection = currMapNode.wingedIsConnectedTo(node); 251 | if (normalConnection || wingedConnection) { 252 | choices.add(node); 253 | } 254 | } 255 | } 256 | } 257 | } 258 | return choices; 259 | } 260 | 261 | /* 262 | Params: 263 | n - any MapRoomNode 264 | Returns: 265 | A String representing the type of node n is 266 | */ 267 | public static String nodeType(MapRoomNode n){ 268 | if(n.getRoom() == null) 269 | return "null"; 270 | if(n.getRoom() instanceof MonsterRoomElite){ 271 | if(n.hasEmeraldKey) 272 | return "Emerald Key "; 273 | else 274 | return "Elite "; 275 | }else if(TextTheSpire.replayTheSpire && n == BonfirePatches.bonfireNode){ 276 | return "Bonfire "; 277 | }else { 278 | String s = n.getRoom().getClass().getSimpleName(); 279 | if (s.equals("EventRoom")) 280 | return "Unknown "; 281 | if (s.substring(s.length() - 4).equals("Room")) { 282 | return s.substring(0, s.length() - 4) + " "; 283 | } else { 284 | return s + " "; 285 | } 286 | } 287 | } 288 | 289 | } 290 | -------------------------------------------------------------------------------- /src/main/resources/localization.json: -------------------------------------------------------------------------------- 1 | { 2 | "ENG": { 3 | "help": { 4 | "base": "Here are a list of commands you can perform.\nFor more details enter help followed by a command.\nExample:\nhelp start\nAll commands are input in the prompt window.\ntutorial\nascension\nquit\nseed\nstats\ncomp\nhistory\nvolume\nlang\nachieve\nmod\nleader\npotion\nchoice\npower\nend\nshow\nhide\nChoices\nDeck\nDiscard\nEvent\nHand\nexhaust\nOutput\nLog\nSave\nLoad\nMap\npath\nMonster\nOrbs\nPlayer\nRelic", 5 | "ascension": "ascension\nThis command lists all the ascension modifiers.", 6 | "quit": "quit\nWhile in a run, this command saves and quits to main menu.\nWhile on the main menu, this command quits the game.\nAnother easy way to close the game would be to close the ModTheSpire window.", 7 | "seed": "seed\nThis command displays the run's seed to the output window.\nA seed is used for random number generation.\nIt can be input when starting a run to have a set seed.", 8 | "stats": "stats\nThis command displays your save file's statistics to output.\nWill not work on a fresh save file.", 9 | "comp": "comp\nThis is the Compendium command.\nThere are various categories and subcategories.\nThe Categories are\ni for Ironclad\ns for Silent\nd for Defect\nw for Watcher\np for Potions\nr for Relics\nRelics has subcategories.\nThese are i, s, d, w, and sh.\nsh is shared and is all of the shared relics.\nFollowing any command by a number will inspect the item at that index.\nExamples\ncomp i\ncomp s 5\ncomp p\ncomp r w\ncomp r sh 10", 10 | "history": "history\nThis is the Run History command.\nFrom the main menu you can active the Run History screen.\nAlmost all commands will be disabled while on this screen.\nYou can input close at any time to close Run History.\nRead the Choices window to navigate Run History.\nThere is currently an issues with Run History.\nSome objects are named differently in the code than what they actually are.\nAs Run History only uses text and not abstract objects, it would be difficult to grab the actual name.\nFor now Run History is using these code names.", 11 | "volume": "volume\nThis displays the current volume settings to output.\nIt can also change the settings.\nThe different volume types are master, music, and sound effects.\nThere is an additional toggle for background ambience sounds.\nThe format is\nvolume master/music/sound number\nThe number needs to be a decimal between 0 and 1.\nExamples:\nvolume master 0.5\nvolume ambience", 12 | "lang": "lang\nThis displays the current language and available languages.\nChange the language with lang followed by the index of the language you want.\nExample:\nlang 0\nOnly game text like card descriptions and monster names will change.\nThis does not affect the mod's text as it hasn't been translated yet.\nRestart the game for the display to update.", 13 | "achieve": "achieve\nThis displays to output the list of locked and unlocked achievements.\nachieve number displays the description of a given achievement.\nachieve can be shortened to a.", 14 | "mod": "mod\nThis displays to output some notes on certain loaded content mods.\nIf a mod isn't listed here then it either works out of the box or hasn't been implemented yet.", 15 | "leader": "leader\nFrom the main menu this opens up the leaderboard screen.\nThe leaderboard is displayed in the Event window.\nThe Choices window displays the leaderboard options.\nOption 1 is char which is which Character.\nOption 2 is region.\nOption 3 is type.\nFor all options used the format:\n[option] [number]\nExamples:\nchar 1\nregion 0\ntype 2\nUse the commands + and - to shift which ranks to display on the leaderboard.\nUse the command mine while region is set to Global to display your scores.", 16 | "potion": "potion\nThis command lets you interact with your potions.\nThere are 3 different options.\nuse. discard, and inspect.\nThe format for use is\npotion use [potion number] [enemy number]\nEnemy number is optional for potions without targets.\nThe format for discard is\npotion discard [potion number]\nThe format for inspect is\npotion inspect [potion number]\nInspect displays what the potion does to the output window.\npotion can be shortened to pot, use to u, discard to d, and inspect to i.\nExamples:\npot u 1 1\npot d 2\npot i 1", 17 | "choice": "choice\nNot to be confused with choices, which is one of the windows.\nchoice displays the info for one of the choices in the choices window in the output window.\nThe format is\nchoice [choice number]\nchoice can be shortened to c.\nExample:\nc 1", 18 | "power": "power\nThis command inspects one of your or a monster's powers.\nThe format to inspect one of your powers is\npower player [power number]\nThe format to inspect a monster's power is\npower monster [monster number] [power number]\npower can be shortened to pow, monster to m, and player to p.\nExample:\npow p 1\npow m 1 2", 19 | "end": "end\nThis command ends your turn.", 20 | "show": "show and hide\nThese commands allow you to hide and unhide windows.\nThe format is\n[show/hide] window name\nYou may also use all for window name to show or hide all windows besides output and prompt.\nExamples:\nhide all\nshow map", 21 | "hide": "show and hide\nThese commands allow you to hide and unhide windows.\nThe format is\n[show/hide] window name\nYou may also use all for window name to show or hide all windows besides output and prompt.\nExamples:\nhide all\nshow map", 22 | "Choices": "choices\nThis command displays the text in the choices window in the output window.\nThe choices window has all of the available choices you can make.\nChoices are either numbered or are a single word.\nEntering either the number or the word selects that choice.", 23 | "Deck": "deck\nThis command displays the text in the deck window in the output window.\nThe deck window displays your deck size and all cards in the deck.\nOut of combat it displays your master deck.\nIn combat it displays your current deck.", 24 | "Discard": "discard\nThis command displays the text in the discard window in the output window.\nThe discard window displays your discard size and all cards in your discard.", 25 | "Event": "event\nThis command displays the event name and text in the event window in the output window.\nThe event window displays the event dialogue and is often used for other dialogue include run score on death or victory.", 26 | "Hand": "hand\nThis command has two options.\nThe first option displays the text in the hand window in the output window.\nThe hand window contains the cards in your hand and your potions.\nThe second option displays the info of a card in your hand in the output window.\nThe format is\nhand [card number]\nhand can be shortened to h.\nExample:\nh 1\nTo play cards in hand input the card number.\nIf the card has a target input the target number after it.\nExamples:\n0\n1 2", 27 | "exhaust": "exhaust\nThis command displays your exhaust pile in Output.\nNote that exhaust does not have a window as there are very few reasons to need to check the exhaust pile.", 28 | "Output": "output\nThis window displays output from various sources.\nThis is the only window that cannot display its text to the output window.\nIt also cannot be hidden.", 29 | "Log": "log\nThis window displays the log.\nYou can also display the log to output with the log command.\nThis log is meant to be a combat log and is still quite basic.\nIt will track:\nChanges in health and powers for the player and monsters.\nUsed cards and potions.\nApplied powers to playrs and monsters.\nExhausted cards.\nThe user's inputs.", 30 | "Save": "save/load\nThese commands let you save and load the output window for later viewing.\nFormat is\nsave/load [anything no spaces]\nExample that saves the output of a map command:\nmap 6 4\nsave 6-4\nload 6-4", 31 | "Load": "save/load\nThese commands let you save and load the output window for later viewing.\nFormat is\nsave/load [anything no spaces]\nExample that saves the output of a map command:\nmap 6 4\nsave 6-4\nload 6-4", 32 | "Map": "map\nThe map window displays the map that the user can reach.\nThe map command has several uses.\nThe first is to simply display the text in the map window to the output window.\nThe next is to inspect the map.\nThis lets you set a destination and display a map that the user can reach and can reach the destination.\nThis destination will also be tracked in the choice window when moving on the map.\nOptionally you can set a different starting position.\nIf you do so the destination will not be tracked in the choice window.\nmap can be shortened to m\nFormat is:\nmap [start floor] [start x] [floor] [x]\nExamples:\nmap 6 4\nmap 3 1 6 4\nBoth examples had destination 6 4.\nFor a different way to inspect the map check the path command.", 33 | "path": "path\nThe path command is closely related to the map command.\nIt displays all of the unique paths from point a to point b and tallies the types of nodes on each path.\nIf point a is not set if defaults to where the user is.\nFormat is:\npath [a floor] [a x] [b floor] [b x]\nExamples:\npath 6 4\npath 3 1 6 4\nBoth examples had destination 6 4.", 34 | "Monster": "monster\nThis command displays the text in the monster window in the output window.\nThe monster window display the info of all alive monsters.\nYou can view what number monsters are assigned in this window.", 35 | "Orbs": "event\nThis command displays the text in the orbs window in the output window.\nThis window displays the orbs the player has.\nThis is usually exclusive to the class Defect.\nYou can inspect an orb with the format:\norbs index\nExample:\norbs 1", 36 | "Player": "player\nThis command displays the text in the player window in the output window.\nThis window displays your character's info.\nOut of combat it also displays your potions.", 37 | "Relic": "relic\nThis command has two options.\nThe first option displays the text in the relic window in the output window.\nThe relic window contains all the relics you own.\nThey are ordered in reverse acquired order.\nThe second option displays a relic's info in the inspect window.\nThe format is\nrelic [relic number]\nExample:\nrelic 5" 38 | }, 39 | "tutorial": "tutorial\nThe goal of each run is complete 3 acts.\nEach act consists of 15 floors and a boss.\nThe map will mention which boss is at the end of the current act.\nYou may only proceed forward and you cannot change your path once you take it.\nEach floor consists of various rooms and each node is connected to rooms on the next floor.\nUse the map and path commands to inspect and understand the map.\nEach room has a type that is viewable from the map.\nMonster rooms contain combat against normal monsters.\nElite rooms contain combat against elite monsters.\nCampfire rooms contain a campfire which provides a list of services you can pick from.\nTreasure rooms contain a treasure chest.\nShop rooms contain a shop.\nUnknown rooms can contain any of the above and can contain an event.\nThroughout the game you will need to make choices.\nMany of these choices will appear in the Choices window.\nThese choices can appear as a numbered list or as whole words.\nTo pick a numbered choice input the number.\nWhole word choices require inputting the word.\nCombat uses card game mechanics.\nUse cards from your hand to defeat enemies.\nCards cost energy to play.\nAt the start of a new turn you draw a fresh hand and your energy is replenished.\nPLay defensive block spells to prevent incoming damage.\nBlock reduces incoming damage but wears off at the start of the next turn.\nDuring your turn you can observe the enemy's intent.\nView cards in your hand using the hand window or the hand command.\nPlaying cards requires inputting the card number and the target number.\nEnemies are all assigned a number that does not change.\nCard numbers are its position in your hand so it can change as you play cards.\nExamples:\n0 0\n1 4\nYou do not need to input a target if the card does not have a target or if there is only one enemy.\nPotions follow similar rules to cards.\nPotions have the options use, discard, and inspect.\nThe format to use them is:\npot [u,d,i] [potion number] [target number]\nAgain, target number is not needed if the potion has no target or if there is only one enemy.\nExamples:\npot u 0 1\npot d 1\npot i 2\npot u 3\nThroughout the run you will be provided with various rewards.\nCard rewards add a card to your deck.\nDo note that you always use all the cards you have and ways to remove cards are rare.\nRelics are items with passive effects.\nYou can check and inspect relics you have in the relic window.\nYou can inspect choices too with the command:\nc [number]\nUse this to check out rewards before picking them.\nThis should be enough to get you started.\nBe sure to check out the rest of the commands in the help command." 40 | } 41 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | textthespire 7 | TextTheSpire 8 | 1.22 9 | jar 10 | TextTheSpire 11 | Screen Reader Assistance. Requires CommunicationMod. 12 | 13 | 14 | UTF-8 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 01-27-2020 19 | 3.15.0 20 | 5.23.2 21 | 1.20.3 22 | 1.0.0 23 | 1.5.12 24 | 2.8.8 25 | 1.7.0 26 | 1.1.2 27 | 2.0.34 28 | 100 29 | 1.1.1 30 | C:/Program Files (x86)/Steam/steamapps 31 | 32 | 33 | 34 | 35 | swt-repo 36 | https://raw.githubusercontent.com/maven-eclipse/swt-repo/master/ 37 | 38 | 39 | 40 | 41 | 42 | com.megacrit.cardcrawl 43 | slaythespire 44 | ${SlayTheSpire.version} 45 | system 46 | ${Steam.path}/common/SlayTheSpire/desktop-1.0.jar 47 | 48 | 49 | com.evacipated.cardcrawl 50 | ModTheSpire 51 | ${ModTheSpire.version} 52 | system 53 | ${Steam.path}/workshop/content/646570/1605060445/ModTheSpire.jar 54 | 55 | 56 | com.evacipated.cardcrawl 57 | BaseMod 58 | ${BaseMod.version} 59 | system 60 | ${Steam.path}/workshop/content/646570/1605833019/BaseMod.jar 61 | 62 | 63 | com.evacipated.cardcrawl 64 | StSLib 65 | ${StSLib.version} 66 | system 67 | ${Steam.path}/workshop/content/646570/1609158507/StSLib.jar 68 | 69 | 70 | com.arbiter.cardcrawl 71 | CommunicationMod 72 | ${CommunicationMod.version} 73 | system 74 | ${Steam.path}/workshop/content/646570/2131373661/CommunicationMod.jar 75 | 76 | 77 | com.replay.cardcrawl 78 | ReplayTheSpireMod 79 | ${ReplayTheSpireMod.version} 80 | system 81 | ${Steam.path}/workshop/content/646570/1610173938/ReplayTheSpireMod.jar 82 | 83 | 84 | com.replay.cardcrawl 85 | AscensionReborn 86 | ${AscensionReborn.version} 87 | system 88 | ${Steam.path}/workshop/content/646570/1635237252/AscensionRebornMod.jar 89 | 90 | 91 | com.conspire.cardcrawl 92 | Conspire 93 | ${Conspire.version} 94 | system 95 | ${Steam.path}/workshop/content/646570/1612329757/Conspire.jar 96 | 97 | 98 | com.shop.cardcrawl 99 | ShopMod 100 | ${ShopMod.version} 101 | system 102 | ${Steam.path}/workshop/content/646570/1615802935/ShopMod.jar 103 | 104 | 105 | com.downfall.cardcrawl 106 | Downfall 107 | ${Downfall.version} 108 | system 109 | ${Steam.path}/workshop/content/646570/1610056683/downfall.jar 110 | 111 | 112 | com.thorton.cardcrawl 113 | Thorton 114 | ${Thorton.version} 115 | system 116 | ${Steam.path}/workshop/content/646570/1783016812/thorton.jar 117 | 118 | 119 | com.relicstats.cardcrawl 120 | RelicStats 121 | ${RelicStats.version} 122 | system 123 | ${Steam.path}/workshop/content/646570/2118491069/RelicStats.jar 124 | 125 | 126 | 127 | com.googlecode.json-simple 128 | json-simple 129 | 1.1.1 130 | 131 | 132 | junit 133 | junit 134 | 135 | 137 | 138 | org.hamcrest 139 | hamcrest-core 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | win64 149 | 150 | true 151 | 152 | 153 | TextTheSpire-win64 154 | 155 | 156 | org.apache.maven.plugins 157 | maven-antrun-plugin 158 | 1.8 159 | 160 | 161 | package 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | run 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | org.eclipse.swt 180 | org.eclipse.swt.win32.win32.x86_64 181 | 4.4 182 | 183 | 184 | 185 | 186 | win32 187 | 188 | TextTheSpire-win32 189 | 190 | 191 | org.apache.maven.plugins 192 | maven-antrun-plugin 193 | 1.8 194 | 195 | 196 | package 197 | 198 | 199 | 200 | 201 | 202 | 203 | run 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | org.eclipse.swt 214 | org.eclipse.swt.win32.win32.x86 215 | 4.4 216 | 217 | 218 | 219 | 220 | linux 221 | 222 | TextTheSpire-linux 223 | 224 | 225 | org.apache.maven.plugins 226 | maven-antrun-plugin 227 | 1.8 228 | 229 | 230 | package 231 | 232 | 233 | 234 | 235 | 236 | 237 | run 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | org.eclipse.swt 248 | org.eclipse.swt.gtk.linux.x86_64 249 | 4.4 250 | 251 | 252 | 253 | 254 | mac 255 | 256 | TextTheSpire-mac 257 | 258 | 259 | org.apache.maven.plugins 260 | maven-antrun-plugin 261 | 1.8 262 | 263 | 264 | package 265 | 266 | 267 | 268 | 269 | 270 | 271 | run 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | org.eclipse.swt 282 | org.eclipse.swt.cocoa.macosx.x86_64 283 | 4.4 284 | 285 | 286 | 287 | 288 | 289 | 290 | TextTheSpire 291 | 292 | 293 | org.apache.maven.plugins 294 | maven-shade-plugin 295 | 2.4.2 296 | 297 | 298 | package 299 | 300 | shade 301 | 302 | 303 | 304 | 305 | 306 | 307 | org.apache.maven.plugins 308 | maven-antrun-plugin 309 | 1.8 310 | 311 | 312 | package 313 | 314 | run 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | src/main/resources 324 | 325 | 326 | src/main/resources 327 | false 328 | 329 | ModTheSpire.json 330 | 331 | 332 | 333 | src/main/resources 334 | true 335 | 336 | ModTheSpire.json 337 | 338 | 339 | 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Inspect.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.megacrit.cardcrawl.cards.AbstractCard; 5 | import com.megacrit.cardcrawl.cards.CardGroup; 6 | import com.megacrit.cardcrawl.core.CardCrawlGame; 7 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 8 | import com.megacrit.cardcrawl.map.MapRoomNode; 9 | import com.megacrit.cardcrawl.potions.AbstractPotion; 10 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 11 | import org.eclipse.swt.widgets.Display; 12 | 13 | import java.util.ArrayList; 14 | 15 | public class Inspect { 16 | 17 | public Window inspect; 18 | 19 | public static ArrayList inspected_map; 20 | public static boolean has_inspected = false; 21 | public static MapRoomNode destination; 22 | 23 | public static String paths; 24 | 25 | public Inspect(Display display){ 26 | inspect = new Window(display,"Output",450,525); 27 | } 28 | 29 | public void setText(String s){ 30 | inspect.setText(s); 31 | } 32 | 33 | public static String inspectMap(String[] tokens){ 34 | int floor; 35 | int x; 36 | 37 | StringBuilder s = new StringBuilder(); 38 | s.append("\r\n"); 39 | 40 | ArrayList> map = AbstractDungeon.map; 41 | ArrayList> m; 42 | boolean differentSource; 43 | MapRoomNode source = null; 44 | 45 | if(tokens.length == 3){ 46 | differentSource = false; 47 | try{ 48 | floor = Integer.parseInt(tokens[1]); 49 | x = Integer.parseInt(tokens[2]); 50 | source = AbstractDungeon.currMapNode; 51 | } catch (Exception e){ 52 | return s.toString(); 53 | } 54 | }else{ 55 | differentSource = true; 56 | try{ 57 | floor = Integer.parseInt(tokens[3]); 58 | x = Integer.parseInt(tokens[4]); 59 | 60 | int source_floor = Integer.parseInt(tokens[1]); 61 | int source_x = Integer.parseInt(tokens[2]); 62 | 63 | for(MapRoomNode child : map.get(source_floor - 1)) { 64 | if(child.x == source_x){ 65 | source = child; 66 | } 67 | } 68 | 69 | } catch (Exception e){ 70 | return s.toString(); 71 | } 72 | } 73 | 74 | if(floor < 1 || floor > 15 || x < 0 || x > 6 || source == null) 75 | return ""; 76 | 77 | int current_y = source.y; 78 | if(current_y >= 15) { 79 | current_y = -1; 80 | } 81 | 82 | if(!(current_y == -1)) { 83 | 84 | m = new ArrayList>(); 85 | 86 | ArrayList current = new ArrayList(); 87 | current.add(source); 88 | m.add(current); 89 | 90 | for (int i = (current_y + 1); i < map.size(); i++) { 91 | 92 | ArrayList next_floor = new ArrayList(); 93 | 94 | for (MapRoomNode n : map.get(i)) { 95 | 96 | for (MapRoomNode child : m.get(i - current_y - 1)) { 97 | if (child.isConnectedTo(n)) { 98 | next_floor.add(n); 99 | 100 | break; 101 | } 102 | } 103 | 104 | } 105 | 106 | m.add(next_floor); 107 | 108 | } 109 | }else{ 110 | m = map; 111 | } 112 | 113 | ArrayList curr = new ArrayList(); 114 | ArrayList prev = new ArrayList(); 115 | 116 | ArrayList inspected = new ArrayList(); 117 | 118 | if(current_y == -1) 119 | current_y = 0; 120 | 121 | if(floor - current_y - 1 < 0){ 122 | return ""; 123 | } 124 | 125 | for(MapRoomNode child : m.get(floor - current_y - 1)){ 126 | if(child.x == x){ 127 | prev.add(child); 128 | inspected.add(child); 129 | if(!differentSource) 130 | destination = child; 131 | s.append("Floor ").append(floor).append("\r\n"); 132 | s.append(Map.nodeType(child)).append(x).append("\r\n"); 133 | break; 134 | } 135 | } 136 | 137 | if(prev.size() == 0) 138 | return s.toString(); 139 | 140 | for(int i = (floor - current_y - 2);i>=0;i--){ 141 | 142 | s.append("Floor ").append(i + current_y + 1).append("\r\n"); 143 | 144 | for(MapRoomNode node : m.get(i)){ 145 | 146 | for(MapRoomNode parent : prev){ 147 | if(node.isConnectedTo(parent)){ 148 | s.append(Map.nodeType(node)).append(node.x).append("\r\n"); 149 | curr.add(node); 150 | inspected.add(node); 151 | break; 152 | } 153 | } 154 | 155 | } 156 | 157 | prev.clear(); 158 | prev.addAll(curr); 159 | curr.clear(); 160 | 161 | } 162 | 163 | if(!differentSource) { 164 | inspected_map = inspected; 165 | has_inspected = true; 166 | } 167 | 168 | return s.toString(); 169 | 170 | } 171 | 172 | public static String inspectPaths(String[] tokens){ 173 | 174 | int floor; 175 | int x; 176 | 177 | ArrayList> map = AbstractDungeon.map; 178 | ArrayList> m; 179 | MapRoomNode source = null; 180 | 181 | if(tokens.length == 3){ 182 | try{ 183 | floor = Integer.parseInt(tokens[1]); 184 | x = Integer.parseInt(tokens[2]); 185 | source = AbstractDungeon.currMapNode; 186 | } catch (Exception e){ 187 | return ""; 188 | } 189 | }else{ 190 | try{ 191 | floor = Integer.parseInt(tokens[3]); 192 | x = Integer.parseInt(tokens[4]); 193 | 194 | int source_floor = Integer.parseInt(tokens[1]); 195 | int source_x = Integer.parseInt(tokens[2]); 196 | 197 | for(MapRoomNode child : map.get(source_floor - 1)) { 198 | if(child.x == source_x){ 199 | source = child; 200 | } 201 | } 202 | 203 | } catch (Exception e){ 204 | return ""; 205 | } 206 | } 207 | 208 | if(floor < 1 || floor > 15 || x < 0 || x > 6 || source == null) 209 | return ""; 210 | 211 | 212 | int current_y = source.y; 213 | if(current_y >= 15) { 214 | current_y = -1; 215 | } 216 | 217 | 218 | if(!(current_y == -1)) { 219 | 220 | m = new ArrayList>(); 221 | 222 | ArrayList current = new ArrayList(); 223 | current.add(source); 224 | m.add(current); 225 | 226 | for (int i = (current_y + 1); i < map.size(); i++) { 227 | 228 | ArrayList next_floor = new ArrayList(); 229 | 230 | for (MapRoomNode n : map.get(i)) { 231 | 232 | for (MapRoomNode child : m.get(i - current_y - 1)) { 233 | if (child.isConnectedTo(n)) { 234 | next_floor.add(n); 235 | 236 | break; 237 | } 238 | } 239 | 240 | } 241 | 242 | m.add(next_floor); 243 | 244 | } 245 | }else{ 246 | m = map; 247 | } 248 | 249 | if(current_y == -1) 250 | current_y = 0; 251 | 252 | paths = ""; 253 | 254 | if(floor - current_y - 1 < 0){ 255 | return ""; 256 | } 257 | 258 | for(MapRoomNode child : m.get(floor - current_y - 1)){ 259 | if(child.x == x){ 260 | pathRecursion(child, m, current_y, ""); 261 | 262 | int num_lines = paths.split("\r\n").length; 263 | 264 | paths = "\r\nUnique Paths " + (num_lines/2) + paths; 265 | 266 | return paths; 267 | } 268 | } 269 | 270 | return ""; 271 | 272 | } 273 | 274 | public static void pathRecursion(MapRoomNode curr, ArrayList> m, int source_y, String path){ 275 | 276 | String newPath = Map.nodeType(curr) + (curr.y+1) + " " + curr.x + ", " + path; 277 | 278 | if(curr.y - source_y - 1 >= 0) { 279 | 280 | for (MapRoomNode child : m.get(curr.y - source_y - 1)) { 281 | if (child.isConnectedTo(curr)) { 282 | pathRecursion(child, m, source_y, newPath); 283 | } 284 | } 285 | 286 | } else { 287 | 288 | String[] tokens = newPath.split("\\s+"); 289 | int unknown = 0; 290 | int monster = 0; 291 | int elite = 0; 292 | int emerald = 0; 293 | int rest = 0; 294 | int shop = 0; 295 | 296 | for (String s : tokens) { 297 | switch (s) { 298 | case "Emerald": 299 | emerald++; 300 | break; 301 | case "Elite": 302 | elite++; 303 | break; 304 | case "Monster": 305 | monster++; 306 | break; 307 | case "Rest": 308 | rest++; 309 | break; 310 | case "Shop": 311 | shop++; 312 | break; 313 | case "Unknown": 314 | unknown++; 315 | break; 316 | } 317 | } 318 | 319 | String pathEntry = ""; 320 | if (emerald > 0) { 321 | pathEntry += "Emerald, "; 322 | } 323 | if (elite > 0) { 324 | pathEntry += "Elite " + elite + ", "; 325 | } 326 | if (rest > 0) { 327 | pathEntry += "Rest " + rest + ", "; 328 | } 329 | if (shop > 0) { 330 | pathEntry += "Shop " + shop + ", "; 331 | } 332 | if (unknown > 0) { 333 | pathEntry += "Unknown " + unknown + ", "; 334 | } 335 | if (monster > 0) { 336 | pathEntry += "Monster " + monster + ", "; 337 | } 338 | pathEntry += "\r\n" + newPath; 339 | 340 | paths = paths + "\r\n" + pathEntry; 341 | 342 | } 343 | } 344 | 345 | 346 | public static String downfallInspect(String[] tokens){ 347 | 348 | int floor; 349 | int x; 350 | 351 | StringBuilder s = new StringBuilder(); 352 | s.append("\r\n"); 353 | 354 | ArrayList> map = AbstractDungeon.map; 355 | ArrayList> m; 356 | boolean differentSource; 357 | MapRoomNode source = null; 358 | 359 | if(tokens.length == 3){ 360 | differentSource = false; 361 | try{ 362 | floor = Integer.parseInt(tokens[1]); 363 | x = Integer.parseInt(tokens[2]); 364 | source = AbstractDungeon.currMapNode; 365 | } catch (Exception e){ 366 | return s.toString(); 367 | } 368 | }else{ 369 | differentSource = true; 370 | try{ 371 | floor = Integer.parseInt(tokens[3]); 372 | x = Integer.parseInt(tokens[4]); 373 | 374 | int source_floor = Integer.parseInt(tokens[1]); 375 | int source_x = Integer.parseInt(tokens[2]); 376 | 377 | for(MapRoomNode child : map.get(source_floor - 1)) { 378 | if(child.x == source_x){ 379 | source = child; 380 | } 381 | } 382 | 383 | } catch (Exception e){ 384 | return s.toString(); 385 | } 386 | } 387 | 388 | if(floor < 1 || floor > 15 || x < 0 || x > 6 || source == null) 389 | return ""; 390 | 391 | int current_y = source.y; 392 | if(current_y == -1) { 393 | current_y = 15; 394 | } 395 | 396 | if(!(current_y == 15)) { 397 | 398 | m = new ArrayList>(); 399 | 400 | ArrayList current = new ArrayList(); 401 | current.add(source); 402 | m.add(current); 403 | 404 | for (int i = (current_y - 1); i >= 0; i--) { 405 | 406 | ArrayList next_floor = new ArrayList(); 407 | 408 | for (MapRoomNode n : map.get(i)) { 409 | 410 | for (MapRoomNode child : m.get(0)) { 411 | if (child.isConnectedTo(n)) { 412 | next_floor.add(n); 413 | break; 414 | } 415 | } 416 | 417 | } 418 | 419 | m.add(0, next_floor); 420 | 421 | } 422 | }else{ 423 | m = map; 424 | } 425 | 426 | ArrayList curr = new ArrayList(); 427 | ArrayList prev = new ArrayList(); 428 | 429 | ArrayList inspected = new ArrayList(); 430 | 431 | if(floor >= current_y){ 432 | return s.toString(); 433 | } 434 | 435 | for(MapRoomNode child : m.get(floor - 1)){ 436 | if(child.x == x){ 437 | prev.add(child); 438 | inspected.add(child); 439 | if(!differentSource) 440 | destination = child; 441 | s.append("Floor ").append(floor).append("\r\n"); 442 | s.append(Map.nodeType(child)).append(x).append("\r\n"); 443 | break; 444 | } 445 | } 446 | 447 | if(prev.size() == 0) 448 | return s.toString(); 449 | 450 | for(int i = floor;i> map = AbstractDungeon.map; 488 | ArrayList> m; 489 | MapRoomNode source = null; 490 | 491 | if(tokens.length == 3){ 492 | try{ 493 | floor = Integer.parseInt(tokens[1]); 494 | x = Integer.parseInt(tokens[2]); 495 | source = AbstractDungeon.currMapNode; 496 | } catch (Exception e){ 497 | return ""; 498 | } 499 | }else{ 500 | try{ 501 | floor = Integer.parseInt(tokens[3]); 502 | x = Integer.parseInt(tokens[4]); 503 | 504 | int source_floor = Integer.parseInt(tokens[1]); 505 | int source_x = Integer.parseInt(tokens[2]); 506 | 507 | for(MapRoomNode child : map.get(source_floor - 1)) { 508 | if(child.x == source_x){ 509 | source = child; 510 | } 511 | } 512 | 513 | } catch (Exception e){ 514 | return ""; 515 | } 516 | } 517 | 518 | if(floor < 1 || floor > 15 || x < 0 || x > 6 || source == null) 519 | return ""; 520 | 521 | 522 | int current_y = source.y; 523 | if(current_y <= -1) { 524 | current_y = 15; 525 | } 526 | 527 | if(!(current_y == 15)) { 528 | 529 | m = new ArrayList>(); 530 | 531 | ArrayList current = new ArrayList(); 532 | current.add(source); 533 | m.add(current); 534 | 535 | for (int i = (current_y - 1); i >= 0; i--) { 536 | 537 | ArrayList next_floor = new ArrayList(); 538 | 539 | for (MapRoomNode n : map.get(i)) { 540 | 541 | for (MapRoomNode child : m.get(0)) { 542 | if (child.isConnectedTo(n)) { 543 | next_floor.add(n); 544 | break; 545 | } 546 | } 547 | 548 | } 549 | 550 | m.add(0, next_floor); 551 | 552 | } 553 | }else{ 554 | m = map; 555 | } 556 | 557 | if(current_y == 15) 558 | current_y = 14; 559 | 560 | paths = ""; 561 | 562 | if(floor >= current_y){ 563 | return ""; 564 | } 565 | 566 | for(MapRoomNode child : m.get(floor - 1)){ 567 | if(child.x == x){ 568 | downfallRecursion(child, m, current_y, ""); 569 | 570 | int num_lines = paths.split("\r\n").length; 571 | 572 | paths = "\r\nUnique Paths " + (num_lines/2) + paths; 573 | 574 | return paths; 575 | } 576 | } 577 | 578 | return ""; 579 | 580 | } 581 | 582 | public static void downfallRecursion(MapRoomNode curr, ArrayList> m, int source_y, String path){ 583 | 584 | String newPath = Map.nodeType(curr) + (curr.y+1) + " " + curr.x + ", " + path; 585 | 586 | if(source_y - curr.y - 1 >= 0) { 587 | 588 | for (MapRoomNode child : m.get(curr.y + 1)) { 589 | if (child.isConnectedTo(curr)) { 590 | downfallRecursion(child, m, source_y, newPath); 591 | } 592 | } 593 | 594 | } else { 595 | 596 | String[] tokens = newPath.split("\\s+"); 597 | int unknown = 0; 598 | int monster = 0; 599 | int elite = 0; 600 | int emerald = 0; 601 | int rest = 0; 602 | int shop = 0; 603 | 604 | for (String s : tokens) { 605 | switch (s) { 606 | case "Emerald": 607 | emerald++; 608 | break; 609 | case "Elite": 610 | elite++; 611 | break; 612 | case "Monster": 613 | monster++; 614 | break; 615 | case "Rest": 616 | rest++; 617 | break; 618 | case "Shop": 619 | shop++; 620 | break; 621 | case "Unknown": 622 | unknown++; 623 | break; 624 | } 625 | } 626 | 627 | String pathEntry = ""; 628 | if (emerald > 0) { 629 | pathEntry += "Emerald, "; 630 | } 631 | if (elite > 0) { 632 | pathEntry += "Elite " + elite + ", "; 633 | } 634 | if (rest > 0) { 635 | pathEntry += "Rest " + rest + ", "; 636 | } 637 | if (shop > 0) { 638 | pathEntry += "Shop " + shop + ", "; 639 | } 640 | if (unknown > 0) { 641 | pathEntry += "Unknown " + unknown + ", "; 642 | } 643 | if (monster > 0) { 644 | pathEntry += "Monster " + monster + ", "; 645 | } 646 | pathEntry += "\r\n" + newPath; 647 | 648 | paths = paths + "\r\n" + pathEntry; 649 | 650 | } 651 | } 652 | 653 | 654 | } 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | -------------------------------------------------------------------------------- /src/main/java/textTheSpire/Choices.java: -------------------------------------------------------------------------------- 1 | package textTheSpire; 2 | 3 | import ascensionMod.AscensionMod; 4 | import ascensionMod.UI.AscModScreen; 5 | import ascensionMod.UI.CharSelectScreenUI; 6 | import basemod.CustomCharacterSelectScreen; 7 | import basemod.ReflectionHacks; 8 | import com.badlogic.gdx.Gdx; 9 | import com.megacrit.cardcrawl.cards.AbstractCard; 10 | import com.megacrit.cardcrawl.cards.CardGroup; 11 | import com.megacrit.cardcrawl.characters.AbstractPlayer; 12 | import com.megacrit.cardcrawl.characters.TheSilent; 13 | import com.megacrit.cardcrawl.core.CardCrawlGame; 14 | import com.megacrit.cardcrawl.core.Settings; 15 | import com.megacrit.cardcrawl.daily.DailyScreen; 16 | import com.megacrit.cardcrawl.daily.TimeHelper; 17 | import com.megacrit.cardcrawl.dungeons.AbstractDungeon; 18 | import com.megacrit.cardcrawl.events.GenericEventDialog; 19 | import com.megacrit.cardcrawl.events.shrines.GremlinMatchGame; 20 | import com.megacrit.cardcrawl.events.shrines.GremlinWheelGame; 21 | import com.megacrit.cardcrawl.helpers.*; 22 | import com.megacrit.cardcrawl.integrations.DistributorFactory; 23 | import com.megacrit.cardcrawl.map.MapRoomNode; 24 | import com.megacrit.cardcrawl.metrics.Metrics; 25 | import com.megacrit.cardcrawl.mod.replay.monsters.replay.FadingForestBoss; 26 | import com.megacrit.cardcrawl.rewards.RewardItem; 27 | import com.megacrit.cardcrawl.rooms.AbstractRoom; 28 | import com.megacrit.cardcrawl.rooms.ShopRoom; 29 | import com.megacrit.cardcrawl.screens.charSelect.CharacterOption; 30 | import com.megacrit.cardcrawl.screens.charSelect.CharacterSelectScreen; 31 | import com.megacrit.cardcrawl.screens.leaderboards.LeaderboardEntry; 32 | import com.megacrit.cardcrawl.screens.mainMenu.*; 33 | import com.megacrit.cardcrawl.screens.runHistory.RunHistoryScreen; 34 | import com.megacrit.cardcrawl.screens.select.GridCardSelectScreen; 35 | import com.megacrit.cardcrawl.screens.stats.*; 36 | import com.megacrit.cardcrawl.shop.ShopScreen; 37 | import com.megacrit.cardcrawl.shop.StorePotion; 38 | import com.megacrit.cardcrawl.shop.StoreRelic; 39 | import com.megacrit.cardcrawl.ui.buttons.LargeDialogOptionButton; 40 | import com.megacrit.cardcrawl.ui.panels.SeedPanel; 41 | import com.megacrit.cardcrawl.unlock.UnlockTracker; 42 | import communicationmod.ChoiceScreenUtils; 43 | import communicationmod.CommandExecutor; 44 | import communicationmod.CommunicationMod; 45 | import communicationmod.patches.GremlinMatchGamePatch; 46 | import conspire.events.MimicChestEvent; 47 | import downfall.patches.EvilModeCharacterSelect; 48 | import downfall.patches.MainMenuEvilMode; 49 | import downfall.rooms.HeartShopRoom; 50 | import downfall.util.RemoveCardReward; 51 | import downfall.util.TransformCardReward; 52 | import downfall.util.UpgradeCardReward; 53 | import org.eclipse.swt.widgets.Display; 54 | import org.eclipse.swt.widgets.Text; 55 | import replayTheSpire.patches.ReplayShopInitCardsPatch; 56 | import shopmod.relics.MerchantsRug; 57 | 58 | import javax.smartcardio.Card; 59 | import java.lang.reflect.Array; 60 | import java.text.ParseException; 61 | import java.text.SimpleDateFormat; 62 | import java.util.ArrayList; 63 | import java.util.Locale; 64 | 65 | public class Choices extends AbstractWindow{ 66 | 67 | boolean disableTips; 68 | 69 | public enum HistoryScreen{ 70 | NONE, MAIN, LIST, INSPECT, DECK, RELIC, PATH; 71 | } 72 | 73 | static class Floor{ 74 | public String type; 75 | public boolean wasUnknown; 76 | public ArrayList cardChoices; 77 | public ArrayList potions; 78 | public ArrayList relics; 79 | public ArrayList purges; 80 | public ArrayList purchases; 81 | public EventStats event; 82 | public BattleStats battle; 83 | public CampfireChoice campfire; 84 | public int currentHP; 85 | public int maxHP; 86 | public BossRelicChoiceStats boss; 87 | public int gold; 88 | }; 89 | 90 | HistoryScreen screen; 91 | RunData inspectRun; 92 | String savedFilter; 93 | 94 | SimpleDateFormat dateFormat; 95 | boolean setFormat; 96 | 97 | public static int doubleIndex; 98 | 99 | public boolean includeGold; 100 | public boolean includeHealth; 101 | public boolean includeCard; 102 | public boolean includeRelics; 103 | public boolean includePotions; 104 | public boolean includePurges; 105 | public boolean includePurchases; 106 | public boolean includeEvents; 107 | public boolean includeBattles; 108 | public boolean includeCampfire; 109 | public boolean includeBosses; 110 | 111 | public Choices(Display display){ 112 | 113 | disableTips = false; 114 | screen = HistoryScreen.NONE; 115 | savedFilter = ""; 116 | setFormat = false; 117 | isVisible = true; 118 | window = new Window(display,"Choices", 300, 400); 119 | 120 | doubleIndex = -1; 121 | 122 | includeGold = true; 123 | includeHealth = true; 124 | includeCard = true; 125 | includeRelics = true; 126 | includePotions = true; 127 | includePurges = true; 128 | includePurchases = true; 129 | includeEvents = true; 130 | includeBattles = true; 131 | includeCampfire = true; 132 | includeBosses = true; 133 | } 134 | 135 | @SuppressWarnings("unchecked") 136 | public String getText(){ 137 | 138 | if(window.shell.isDisposed()){ 139 | Display.getDefault().dispose(); 140 | Gdx.app.exit(); 141 | } 142 | 143 | doubleIndex = -1; 144 | 145 | if(!setFormat && CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.runHistoryScreen != null){ 146 | if (Settings.language == Settings.GameLanguage.JPN) { 147 | dateFormat = new SimpleDateFormat(RunHistoryScreen.TEXT[34], Locale.JAPAN); 148 | } else { 149 | dateFormat = new SimpleDateFormat(RunHistoryScreen.TEXT[34]); 150 | } 151 | setFormat = true; 152 | } 153 | 154 | StringBuilder s = new StringBuilder(); 155 | s.append("\r\n"); 156 | 157 | if(screen != HistoryScreen.NONE) { 158 | 159 | 160 | switch(screen){ 161 | 162 | 163 | case MAIN: 164 | 165 | s.append("Run History\r\nMost commands are disabled when viewing run history.\r\n"); 166 | s.append("Total runs: ").append(TextTheSpire.runList.size()).append("\r\n"); 167 | s.append("Filters:\r\n"); 168 | s.append("1. Wins ").append(TextTheSpire.include_win).append("\r\n"); 169 | s.append("2. Loses ").append(TextTheSpire.include_lose).append("\r\n"); 170 | s.append("3. Ironclad ").append(TextTheSpire.include_iron).append("\r\n"); 171 | s.append("4. Silent ").append(TextTheSpire.include_silent).append("\r\n"); 172 | s.append("5. Defect ").append(TextTheSpire.include_defect).append("\r\n"); 173 | s.append("6. Watcher ").append(TextTheSpire.include_watch).append("\r\n"); 174 | s.append("7. Normal Runs ").append(TextTheSpire.include_normal).append("\r\n"); 175 | s.append("8. Ascension ").append(TextTheSpire.include_asc).append("\r\n"); 176 | s.append("9. Daily ").append(TextTheSpire.include_daily).append("\r\n"); 177 | s.append("Input a single number to toggle a filter.\r\n"); 178 | s.append("Input view to view list of runs.\r\n"); 179 | s.append("At any point input close to exit Run History and return to main menu.\r\n"); 180 | break; 181 | 182 | case LIST: 183 | 184 | if(!savedFilter.isEmpty()){ 185 | return savedFilter; 186 | } 187 | s.append("back\r\nFiltered runs: ").append(TextTheSpire.runFiltered.size()).append("\r\n"); 188 | s.append("Run are displayed with date followed by score.\r\n"); 189 | s.append("Inspect a run with its index.\r\n"); 190 | s.append("Runs:\r\n"); 191 | for(int i=0;i every = new ArrayList<>(); 280 | for(int i=0;i(); 287 | newFloor.potions = new ArrayList<>(); 288 | newFloor.cardChoices = new ArrayList<>(); 289 | newFloor.purchases = new ArrayList<>(); 290 | newFloor.purges = new ArrayList<>(); 291 | every.add(newFloor); 292 | } 293 | for(int i=0;i 0){ 346 | s.append("Cards Obtained: "); 347 | for(String obt : every.get(i).event.cards_obtained){ 348 | s.append(obt).append(", "); 349 | } 350 | s.append("\r\n"); 351 | } 352 | if(every.get(i).event.cards_removed != null && every.get(i).event.cards_removed.size() > 0){ 353 | s.append("Cards Removed: "); 354 | for(String obt : every.get(i).event.cards_removed){ 355 | s.append(obt).append(", "); 356 | } 357 | s.append("\r\n"); 358 | } 359 | if(every.get(i).event.cards_transformed != null && every.get(i).event.cards_transformed.size() > 0){ 360 | s.append("Cards Transformed: "); 361 | for(String obt : every.get(i).event.cards_transformed){ 362 | s.append(obt).append(", "); 363 | } 364 | s.append("\r\n"); 365 | } 366 | if(every.get(i).event.cards_upgraded != null && every.get(i).event.cards_upgraded.size() > 0){ 367 | s.append("Cards Upgraded: "); 368 | for(String obt : every.get(i).event.cards_upgraded){ 369 | s.append(obt).append(", "); 370 | } 371 | s.append("\r\n"); 372 | } 373 | if(every.get(i).event.relics_obtained != null && every.get(i).event.relics_obtained.size() > 0){ 374 | s.append("Relics Obtained: "); 375 | for(String obt : every.get(i).event.relics_obtained){ 376 | s.append(obt).append(", "); 377 | } 378 | s.append("\r\n"); 379 | } 380 | if(every.get(i).event.relics_lost != null && every.get(i).event.relics_lost.size() > 0){ 381 | s.append("Relics Lost: "); 382 | for(String obt : every.get(i).event.relics_lost){ 383 | s.append(obt).append(", "); 384 | } 385 | s.append("\r\n"); 386 | } 387 | if(every.get(i).event.potions_obtained != null && every.get(i).event.potions_obtained.size() > 0){ 388 | s.append("Potions Obtained: "); 389 | for(String obt : every.get(i).event.potions_obtained){ 390 | s.append(obt).append(", "); 391 | } 392 | s.append("\r\n"); 393 | } 394 | if(every.get(i).event.damage_taken > 0) 395 | s.append("Damaged Taken: ").append(every.get(i).event.damage_taken).append("\r\n"); 396 | if(every.get(i).event.damage_healed > 0) 397 | s.append("Damaged Healed: ").append(every.get(i).event.damage_healed).append("\r\n"); 398 | if(every.get(i).event.max_hp_loss > 0) 399 | s.append("Max HP Loss: ").append(every.get(i).event.max_hp_loss).append("\r\n"); 400 | if(every.get(i).event.max_hp_gain > 0) 401 | s.append("Max HP Gain: ").append(every.get(i).event.max_hp_gain).append("\r\n"); 402 | if(every.get(i).event.gold_gain > 0) 403 | s.append("Gold Gain: ").append(every.get(i).event.gold_gain).append("\r\n"); 404 | if(every.get(i).event.gold_loss > 0) 405 | s.append("Gold Loss: ").append(every.get(i).event.gold_loss).append("\r\n"); 406 | } 407 | if(every.get(i).campfire != null && includeCampfire){ 408 | s.append("Campfire: ").append(every.get(i).campfire.key); 409 | if(every.get(i).campfire.data != null) 410 | s.append(": ").append(every.get(i).campfire.data); 411 | s.append("\r\n"); 412 | } 413 | if(every.get(i).boss != null && includeBosses){ 414 | s.append("Picked: ").append(every.get(i).boss.picked).append("\r\n"); 415 | s.append("Rejected: "); 416 | for(String rej : every.get(i).boss.not_picked){ 417 | s.append(rej).append(", "); 418 | } 419 | s.append("\r\n"); 420 | } 421 | if(every.get(i).purchases.size() > 0 && includePurchases){ 422 | s.append("Purchases: "); 423 | for(String p : every.get(i).purchases){ 424 | s.append(p).append(", "); 425 | } 426 | s.append("\r\n"); 427 | } 428 | if(every.get(i).purges.size() > 0 && includePurges){ 429 | s.append("Purges: "); 430 | for(String p : every.get(i).purges){ 431 | s.append(p).append(", "); 432 | } 433 | s.append("\r\n"); 434 | } 435 | if(every.get(i).cardChoices.size() > 0 && includeCard){ 436 | s.append("Card Choices\r\n"); 437 | for(CardChoiceStats c : every.get(i).cardChoices){ 438 | s.append("Picked: ").append(c.picked).append("\r\n"); 439 | s.append("Rejected: "); 440 | for(String rej : c.not_picked){ 441 | s.append(rej).append(", "); 442 | } 443 | s.append("\r\n"); 444 | } 445 | } 446 | if(every.get(i).relics.size() > 0 && includeRelics){ 447 | s.append("Relics Obtained: "); 448 | for(String p : every.get(i).relics){ 449 | s.append(p).append(", "); 450 | } 451 | s.append("\r\n"); 452 | } 453 | if(every.get(i).potions.size() > 0 && includePotions){ 454 | s.append("Potions Obtained: "); 455 | for(String p : every.get(i).potions){ 456 | s.append(p).append(", "); 457 | } 458 | s.append("\r\n"); 459 | } 460 | } 461 | break; 462 | 463 | } 464 | 465 | return s.toString(); 466 | 467 | } else if(CommandExecutor.isInDungeon()){ 468 | 469 | ChoiceScreenUtils.ChoiceType currChoice = ChoiceScreenUtils.getCurrentChoiceType(); 470 | 471 | if(TextTheSpire.downfall && EvilModeCharacterSelect.evilMode && AbstractDungeon.getCurrRoom() instanceof HeartShopRoom && ChoiceScreenUtils.getCurrentChoiceType() == ChoiceScreenUtils.ChoiceType.SHOP_ROOM && AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 472 | return ""; 473 | } 474 | 475 | if(currChoice == ChoiceScreenUtils.ChoiceType.HAND_SELECT){ 476 | s.append("Hand Selection\r\n"); 477 | s.append(AbstractDungeon.handCardSelectScreen.selectionReason + "\r\n"); 478 | s.append("Select " + AbstractDungeon.handCardSelectScreen.numCardsToSelect + "\r\n"); 479 | s.append("Number Selected: " + AbstractDungeon.handCardSelectScreen.numSelected + "\r\n"); 480 | }else if(currChoice == ChoiceScreenUtils.ChoiceType.GRID){ 481 | s.append("Grid Selection\r\n"); 482 | s.append("Number Selected: " + AbstractDungeon.gridSelectScreen.selectedCards.size() + "\r\n"); 483 | if(AbstractDungeon.gridSelectScreen.forUpgrade && AbstractDungeon.gridSelectScreen.upgradePreviewCard != null){ 484 | AbstractCard preview = AbstractDungeon.gridSelectScreen.upgradePreviewCard; 485 | s.append("Upgrade Preview : " + TextTheSpire.inspectCard(preview)); 486 | } 487 | } 488 | 489 | //If in combat check if choices exists, otherwise remove window 490 | if(AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT){ 491 | 492 | if (ChoiceScreenUtils.isConfirmButtonAvailable()) { 493 | s.append(ChoiceScreenUtils.getConfirmButtonText()).append("\r\n"); 494 | } 495 | if (ChoiceScreenUtils.isCancelButtonAvailable()) { 496 | s.append(ChoiceScreenUtils.getCancelButtonText()).append("\r\n"); 497 | } 498 | int count = 1; 499 | 500 | if(TextTheSpire.replayTheSpire && AbstractDungeon.getCurrRoom().monsters.monsters.get(AbstractDungeon.getCurrRoom().monsters.monsters.size()-1) instanceof FadingForestBoss){ 501 | boolean show = (boolean)basemod.ReflectionHacks.getPrivateStatic(GenericEventDialog.class, "show"); 502 | if(show){ 503 | String name = (String) ReflectionHacks.getPrivate(((FadingForestBoss) AbstractDungeon.getCurrRoom().monsters.monsters.get(AbstractDungeon.getCurrRoom().monsters.monsters.size()-1)).imageEventText, GenericEventDialog.class, "title"); 504 | s.append(name).append("\r\n"); 505 | ArrayList buttons = ((FadingForestBoss) AbstractDungeon.getCurrRoom().monsters.monsters.get(AbstractDungeon.getCurrRoom().monsters.monsters.size()-1)).imageEventText.optionList; 506 | ArrayList activeButtons = new ArrayList<>(); 507 | for(LargeDialogOptionButton b : buttons){ 508 | if(!b.isDisabled){ 509 | activeButtons.add(b); 510 | } 511 | } 512 | if (activeButtons.size() > 0) { 513 | for(LargeDialogOptionButton button : activeButtons) { 514 | s.append(count).append(": ").append(stripColor(button.msg).toLowerCase()).append("\r\n"); 515 | count++; 516 | } 517 | return s.toString(); 518 | } 519 | } 520 | } 521 | 522 | ArrayList cards = ChoiceScreenUtils.getCurrentChoiceList(); 523 | 524 | if (cards.size() == 0) { 525 | return s.toString(); 526 | } 527 | 528 | for (String c : cards) { 529 | 530 | s.append(count).append(":").append(c).append("\r\n"); 531 | count++; 532 | 533 | } 534 | 535 | return s.toString(); 536 | 537 | }else{ 538 | 539 | //If not in combat, check and display choices 540 | 541 | int count = 1; 542 | 543 | if (ChoiceScreenUtils.isConfirmButtonAvailable()) { 544 | s.append(ChoiceScreenUtils.getConfirmButtonText()).append("\r\n"); 545 | } 546 | if (ChoiceScreenUtils.isCancelButtonAvailable()) { 547 | s.append(ChoiceScreenUtils.getCancelButtonText()).append("\r\n"); 548 | } 549 | 550 | //Event choices 551 | if (ChoiceScreenUtils.getCurrentChoiceType() == ChoiceScreenUtils.ChoiceType.EVENT) { 552 | 553 | if(TextTheSpire.conspire && AbstractDungeon.getCurrRoom().event instanceof MimicChestEvent) { 554 | s.append("\r\nproceed\r\n1:open\r\n"); 555 | return s.toString(); 556 | } 557 | 558 | s.append(AbstractDungeon.getCurrRoom().event.getClass().getSimpleName()).append("\r\n"); 559 | 560 | ArrayList activeButtons = ChoiceScreenUtils.getActiveEventButtons(); 561 | 562 | if (activeButtons.size() > 0) { 563 | for(LargeDialogOptionButton button : activeButtons) { 564 | s.append(count).append(": ").append(stripColor(button.msg).toLowerCase()).append("\r\n"); 565 | count++; 566 | } 567 | } else if(AbstractDungeon.getCurrRoom().event instanceof GremlinWheelGame) { 568 | s.append(count).append(": ").append("spin").append("\r\n"); 569 | } else if(AbstractDungeon.getCurrRoom().event instanceof GremlinMatchGame) { 570 | GremlinMatchGame event = (GremlinMatchGame) (AbstractDungeon.getCurrRoom().event); 571 | CardGroup gameCardGroup = (CardGroup) ReflectionHacks.getPrivate(event, GremlinMatchGame.class, "cards"); 572 | for (AbstractCard c : gameCardGroup.group) { 573 | if (c.isFlipped) { 574 | s.append(count).append(": ").append(String.format("card%d", GremlinMatchGamePatch.cardPositions.get(c.uuid))).append("\r\n"); 575 | count++; 576 | } 577 | } 578 | } 579 | 580 | } else if (ChoiceScreenUtils.getCurrentChoiceType() == ChoiceScreenUtils.ChoiceType.SHOP_SCREEN) { 581 | 582 | for (String c : priceShopScreenChoices()) { 583 | s.append(count).append(":").append(c).append("\r\n"); 584 | count++; 585 | } 586 | if(TextTheSpire.shopMod && MerchantsRug.forSale && AbstractDungeon.player.gold >= MerchantsRug.price){ 587 | s.append("rug:MerchantsRug.price"); 588 | } 589 | 590 | } else if (ChoiceScreenUtils.getCurrentChoiceType() == ChoiceScreenUtils.ChoiceType.MAP){ 591 | 592 | //Also shows current position 593 | if (AbstractDungeon.firstRoomChosen) { 594 | s.append("Floor:").append(AbstractDungeon.currMapNode.y + 1).append(", X:").append(AbstractDungeon.currMapNode.x).append("\r\n"); 595 | }else { 596 | if(TextTheSpire.downfall && EvilModeCharacterSelect.evilMode) 597 | s.append("Floor 16\r\n"); 598 | else 599 | s.append("Floor:0\r\n"); 600 | } 601 | 602 | ArrayList choices; 603 | 604 | if(TextTheSpire.downfall && EvilModeCharacterSelect.evilMode) 605 | choices = Map.getMapScreenNodeChoices(); 606 | else 607 | choices = ChoiceScreenUtils.getMapScreenNodeChoices(); 608 | 609 | if ((ChoiceScreenUtils.bossNodeAvailable() && !TextTheSpire.downfall) || (TextTheSpire.downfall && AbstractDungeon.getCurrMapNode().y == 0)) { 610 | 611 | s.append(count).append(":"); 612 | s.append("boss").append("\r\n"); 613 | 614 | } else if(!Inspect.has_inspected) { 615 | 616 | //Displays node type and xPos for each choice 617 | for (MapRoomNode n : choices) { 618 | s.append(count).append(":"); 619 | if(AbstractDungeon.player.hasRelic("WingedGreaves") && (AbstractDungeon.player.getRelic("WingedGreaves")).counter > 0 && !AbstractDungeon.getCurrMapNode().isConnectedTo(n)) { 620 | s.append(Map.nodeType(n)).append("Winged ").append(n.x).append("\r\n"); 621 | } else { 622 | s.append(Map.nodeType(n)).append(n.x).append("\r\n"); 623 | } 624 | count++; 625 | } 626 | 627 | }else{ 628 | 629 | s.append("Inspected ").append(Map.nodeType(Inspect.destination)).append(Inspect.destination.y + 1).append(" ").append(Inspect.destination.x).append("\r\n"); 630 | 631 | for (MapRoomNode n : choices) { 632 | s.append(count).append(":"); 633 | s.append(Map.nodeType(n)); 634 | if (Inspect.inspected_map.contains(n)) { 635 | s.append("On Track ").append(n.x).append("\r\n"); 636 | }else if(AbstractDungeon.player.hasRelic("WingedGreaves") && (AbstractDungeon.player.getRelic("WingedGreaves")).counter > 0 && !AbstractDungeon.getCurrMapNode().isConnectedTo(n)){ 637 | s.append("Winged ").append(n.x).append("\r\n"); 638 | }else{ 639 | s.append("Diverge ").append(n.x).append("\r\n"); 640 | } 641 | 642 | count++; 643 | } 644 | 645 | } 646 | 647 | } else if(ChoiceScreenUtils.getCurrentChoiceType() == ChoiceScreenUtils.ChoiceType.COMBAT_REWARD) { 648 | for(RewardItem reward : AbstractDungeon.combatRewardScreen.rewards) { 649 | if(TextTheSpire.downfall){ 650 | if(reward instanceof RemoveCardReward){ 651 | s.append(count).append(":").append("remove\r\n"); 652 | count++; 653 | continue; 654 | } else if(reward instanceof UpgradeCardReward){ 655 | s.append(count).append(":").append("upgrade\r\n"); 656 | count++; 657 | continue; 658 | } else if(reward instanceof TransformCardReward){ 659 | s.append(count).append(":").append("transform\r\n"); 660 | count++; 661 | continue; 662 | } 663 | } 664 | if(reward.type == RewardItem.RewardType.POTION) 665 | s.append(count).append(":").append(reward.potion.name).append("\r\n"); 666 | else if(reward.type == RewardItem.RewardType.RELIC) 667 | s.append(count).append(":").append(reward.relic.name).append("\r\n"); 668 | else 669 | s.append(count).append(":").append(reward.type.name().toLowerCase()).append("\r\n"); 670 | count++; 671 | } 672 | } else { 673 | //Catch all for all remaining choices. They are usually displayed in a list with numbers a simple name 674 | for (String c : ChoiceScreenUtils.getCurrentChoiceList()) { 675 | s.append(count).append(":").append(c).append("\r\n"); 676 | count++; 677 | } 678 | } 679 | 680 | return s.toString(); 681 | 682 | } 683 | 684 | }else { 685 | 686 | //Not in dungeon. Check if save exists. checkedSave so we don't check each time. 687 | if (CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.screen == MainMenuScreen.CurScreen.MAIN_MENU) { 688 | 689 | if (!disableTips) { 690 | TipTracker.disableAllFtues(); 691 | disableTips = true; 692 | } 693 | 694 | s.append("Text The Spire v" + TextTheSpire.VERSION + "\r\ntts : patch notes\r\n"); 695 | 696 | s.append("Slot ").append(CardCrawlGame.saveSlot).append(" ").append(CardCrawlGame.playerName).append("\r\n"); 697 | 698 | for (AbstractPlayer.PlayerClass p : AbstractPlayer.PlayerClass.values()) { 699 | 700 | s.append(p.name().toLowerCase()).append(" "); 701 | 702 | if (TextTheSpire.characterUnlocked(p.name().toLowerCase())) { 703 | s.append(TextTheSpire.ascensionLevel(p)).append("\r\n"); 704 | } else 705 | s.append("locked\r\n"); 706 | 707 | } 708 | 709 | s.append("Commands\r\n"); 710 | 711 | if (CardCrawlGame.mainMenuScreen.buttons.get(CardCrawlGame.mainMenuScreen.buttons.size() - 2).result == MenuButton.ClickResult.ABANDON_RUN) { 712 | s.append("abandon\r\n"); 713 | s.append("continue\r\n"); 714 | } else { 715 | s.append("play\r\n"); 716 | if (DistributorFactory.isLeaderboardEnabled()) { 717 | s.append("leader\r\n"); 718 | } 719 | } 720 | 721 | s.append("history\r\nslot\r\npatch\r\nquit"); 722 | 723 | }else if(CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.screen == MainMenuScreen.CurScreen.PANEL_MENU){ 724 | MenuPanelScreen.PanelScreen ps = (MenuPanelScreen.PanelScreen) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.panelScreen, MenuPanelScreen.class, "screen"); 725 | if(TextTheSpire.downfall && ps == MainMenuEvilMode.Enums.EVIL){ 726 | s.append("standard\r\ndownfall\r\n"); 727 | } else { 728 | s.append("standard\r\n"); 729 | if (CardCrawlGame.mainMenuScreen.statsScreen.statScreenUnlocked()) { 730 | s.append("daily\r\n"); 731 | } 732 | if (StatsScreen.all.highestDaily > 0) { 733 | s.append("custom\r\n"); 734 | } 735 | s.append("back\r\n"); 736 | } 737 | }else if(CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.screen == MainMenuScreen.CurScreen.CHAR_SELECT){ 738 | 739 | if(CardCrawlGame.mainMenuScreen.charSelectScreen instanceof CustomCharacterSelectScreen) { 740 | ArrayList allOptions = ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.charSelectScreen, CustomCharacterSelectScreen.class, "allOptions"); 741 | if (CardCrawlGame.mainMenuScreen.charSelectScreen.options.size() != allOptions.size()) { 742 | CardCrawlGame.mainMenuScreen.charSelectScreen.options = allOptions; 743 | } 744 | } 745 | 746 | s.append("Input character name to select.\r\nasc to toggle ascension.\r\nasc [number] to set ascension level.\r\nIf that fails you can use + and - to manually change ascension level.\r\n"); 747 | s.append("back\r\n"); 748 | ArrayList options = CardCrawlGame.mainMenuScreen.charSelectScreen.options; 749 | for(CharacterOption co : options){ 750 | s.append(co.c.getClass().getSimpleName().toLowerCase()); 751 | if(co.selected) { 752 | s.append(" Selected"); 753 | } 754 | s.append("\r\n"); 755 | } 756 | SeedPanel sp = (SeedPanel) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.charSelectScreen, CharacterSelectScreen.class, "seedPanel"); 757 | if(sp.shown){ 758 | s.append("seed\r\n"); 759 | } 760 | boolean ready = (boolean) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.charSelectScreen, CharacterSelectScreen.class, "anySelected"); 761 | boolean asc = (boolean) basemod.ReflectionHacks.getPrivate(CardCrawlGame.mainMenuScreen.charSelectScreen, CharacterSelectScreen.class, "isAscensionModeUnlocked"); 762 | if(asc && ready){ 763 | s.append("asc "); 764 | if(CardCrawlGame.mainMenuScreen.charSelectScreen.isAscensionMode) 765 | s.append(CardCrawlGame.mainMenuScreen.charSelectScreen.ascensionLevel).append("\r\n"); 766 | else 767 | s.append("off\r\n"); 768 | if(TextTheSpire.ascensionReborn){ 769 | s.append("c_asc ").append(AscensionMod.customAscensionRun).append("\r\n"); 770 | if(AscensionMod.customAscensionRun){ 771 | s.append("open\r\n"); 772 | } 773 | } 774 | } 775 | if(ready) 776 | s.append("embark\r\n"); 777 | }else if(TextTheSpire.ascensionReborn && CardCrawlGame.mainMenuScreen != null && CardCrawlGame.mainMenuScreen.screen == AscModScreen.Enum.ASC_MOD){ 778 | s.append("Custom Ascension Screen\r\nback\r\nInput number to toggle ascension.\r\nUse ascension command to check what the modifiers do.\r\n"); 779 | for(int i=CharSelectScreenUI.ascScreen.posAscButtons.size()-1; i>=0; i--){ 780 | s.append((i+1)).append(" : ").append(CharSelectScreenUI.ascScreen.posAscButtons.get(i).toggledOn).append("\r\n"); 781 | } 782 | for(int i=0; i priceShopScreenChoices(){ 871 | ArrayList choices = new ArrayList<>(); 872 | ArrayList shopItems = getAvailableShopItems(); 873 | for (Object item : shopItems) { 874 | if (item instanceof String) { 875 | choices.add((String) item); 876 | } else if (item instanceof AbstractCard) { 877 | if(TextTheSpire.replayTheSpire && ((AbstractCard) item).equals(ReplayShopInitCardsPatch.doubleCard)) { 878 | choices.add(((AbstractCard) item).name.toLowerCase() + "-" + ((AbstractCard) item).price + " Two for One"); 879 | doubleIndex = choices.size() - 1; 880 | }else { 881 | choices.add(((AbstractCard) item).name.toLowerCase() + "-" + ((AbstractCard) item).price); 882 | } 883 | } else if (item instanceof StoreRelic) { 884 | choices.add(((StoreRelic)item).relic.name + "-" + ((StoreRelic) item).price); 885 | } else if (item instanceof StorePotion) { 886 | choices.add(((StorePotion)item).potion.name + "-" + ((StorePotion) item).price); 887 | } 888 | } 889 | return choices; 890 | } 891 | 892 | /* 893 | Gets a list of all shop items. 894 | Copied from CommunicationMod 895 | */ 896 | public static ArrayList getAvailableShopItems() { 897 | ArrayList choices = new ArrayList<>(); 898 | ShopScreen screen = AbstractDungeon.shopScreen; 899 | if(screen.purgeAvailable && AbstractDungeon.player.gold >= ShopScreen.actualPurgeCost) { 900 | choices.add("purge-" + ShopScreen.actualPurgeCost); 901 | } 902 | for(AbstractCard card : ChoiceScreenUtils.getShopScreenCards()) { 903 | if(card.price <= AbstractDungeon.player.gold) { 904 | choices.add(card); 905 | } 906 | } 907 | for(StoreRelic relic : ChoiceScreenUtils.getShopScreenRelics()) { 908 | if(relic.price <= AbstractDungeon.player.gold) { 909 | choices.add(relic); 910 | } 911 | } 912 | for(StorePotion potion : ChoiceScreenUtils.getShopScreenPotions()) { 913 | if(potion.price <= AbstractDungeon.player.gold) { 914 | choices.add(potion); 915 | } 916 | } 917 | return choices; 918 | } 919 | 920 | /* 921 | Params: 922 | input - an Event choice 923 | Returns: 924 | A String with color mods removed from input 925 | */ 926 | public static String stripColor(String input) { 927 | input = input.replace("#r", ""); 928 | input = input.replace("#g", ""); 929 | input = input.replace("#b", ""); 930 | input = input.replace("#y", ""); 931 | input = input.replace("#p", ""); 932 | input = input.replace("~", ""); 933 | input = input.replace("@", ""); 934 | input = input.replace("[#2aecd7]", ""); 935 | input = input.replace("NL", "\r\n"); 936 | return input; 937 | } 938 | 939 | public static String mapType(String input){ 940 | if(input == null){ 941 | return "Boss Chest"; 942 | } 943 | switch(input){ 944 | case "M": 945 | return "Monster"; 946 | case "?": 947 | return "Event"; 948 | case "E": 949 | return "Elite"; 950 | case "$": 951 | return "Shop"; 952 | case "R": 953 | return "Rest"; 954 | case "T": 955 | return "Treasure"; 956 | case "B": 957 | return "Boss"; 958 | } 959 | return "Boss Chest"; 960 | } 961 | 962 | } 963 | --------------------------------------------------------------------------------