Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions mod/src/main/java/basemod/AtlasLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package basemod;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePrefixPatch;

import java.util.HashMap;

public class AtlasLoader {
private static HashMap<String, TextureAtlas> atlases = new HashMap<>();

public static TextureAtlas getAtlas(final String atlasString) {
if (atlases.get(atlasString) == null) {
try {
loadAtlas(atlasString);
} catch (GdxRuntimeException e) {

}
}
return atlases.get(atlasString);
}

private static void loadAtlas(final String atlasString) throws GdxRuntimeException {
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal(atlasString));
atlases.put(atlasString, atlas);
}

public static boolean testAtlas(String filePath) {
return Gdx.files.internal(filePath).exists();
}

@SpirePatch(clz = TextureAtlas.class, method = "dispose")
public static class DisposeListener {
@SpirePrefixPatch
public static void DisposeListenerPatch(final TextureAtlas __instance) {
atlases.entrySet().removeIf(entry -> {
return entry.getValue().equals(__instance);
});
}
}
}
80 changes: 78 additions & 2 deletions mod/src/main/java/basemod/BaseMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import basemod.patches.whatmod.WhatMod;
import basemod.screens.ModalChoiceScreen;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Version;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
Expand Down Expand Up @@ -68,6 +67,7 @@
import com.megacrit.cardcrawl.screens.charSelect.CharacterOption;
import com.megacrit.cardcrawl.screens.custom.CustomMod;
import com.megacrit.cardcrawl.screens.custom.CustomModeCharacterButton;
import com.megacrit.cardcrawl.screens.stats.StatsScreen;
import com.megacrit.cardcrawl.shop.ShopScreen;
import com.megacrit.cardcrawl.shop.StorePotion;
import com.megacrit.cardcrawl.shop.StoreRelic;
Expand Down Expand Up @@ -143,6 +143,7 @@ public class BaseMod {
private static ArrayList<EditStringsSubscriber> editStringsSubscribers;
private static ArrayList<AddAudioSubscriber> addAudioSubscribers;
private static ArrayList<EditKeywordsSubscriber> editKeywordsSubscribers;
private static ArrayList<EditAchievementsSubscriber> editAchievementsSubscribers;
private static ArrayList<PostBattleSubscriber> postBattleSubscribers;
private static ArrayList<SetUnlocksSubscriber> setUnlocksSubscribers;
private static ArrayList<PostPotionUseSubscriber> postPotionUseSubscribers;
Expand Down Expand Up @@ -246,7 +247,8 @@ public class BaseMod {
private static HashMap<AbstractPlayer.PlayerClass, HashMap<Integer, CustomUnlockBundle>> unlockBundles;
private static HashMap<AbstractPlayer.PlayerClass, ArrayList<String>> unlockCards;
private static HashMap<AbstractPlayer.PlayerClass, Integer> maxUnlockLevel;

public static Map<String, List<ModAchievement>> modAchievements = new HashMap<>();
public static Map<String, ModAchievementGrid> modAchievementGrids = new HashMap<>();
private static HashMap<String, CustomSavableRaw> customSaveFields = new HashMap<>();
private static HashMap<AbstractDungeon.CurrentScreen, CustomScreen> customScreens = new HashMap<>();

Expand All @@ -256,6 +258,9 @@ public class BaseMod {
private static FrameBuffer animationBuffer;
private static Texture animationTexture;
private static TextureRegion animationTextureRegion;
private static String achievementModID;
private static String achievementMakeID;
private static TextureAtlas achievementAtlas;

public static boolean fixesEnabled = true;

Expand Down Expand Up @@ -484,6 +489,7 @@ private static void initializeSubscriptions() {
editStringsSubscribers = new ArrayList<>();
addAudioSubscribers = new ArrayList<>();
editKeywordsSubscribers = new ArrayList<>();
editAchievementsSubscribers = new ArrayList<>();
postBattleSubscribers = new ArrayList<>();
setUnlocksSubscribers = new ArrayList<>();
postPotionUseSubscribers = new ArrayList<>();
Expand Down Expand Up @@ -1705,6 +1711,7 @@ public static List<AbstractPlayer> getModdedCharacters() {
return CardCrawlGame.characterManager.getAllCharacters().subList(lastBaseCharacterIndex+1, CardCrawlGame.characterManager.getAllCharacters().size());
}


// add character - the String characterID *must* be the exact same as what
// you put in the PlayerClass enum
public static void addCharacter(AbstractPlayer character,
Expand Down Expand Up @@ -2100,6 +2107,54 @@ public static void saveEnergyOrbPortraitTexture(AbstractCard.CardColor color, co
colorEnergyOrbPortraitTextureMap.put(color, tex);
}

//
// Achievements
//

public static String getAchievementModID() {
return achievementModID;
}

public static void registerAchievementGrid(String modID, TextureAtlas atlas, String headerText) {
achievementModID = modID;
achievementAtlas = atlas;
ModAchievementGrid grid = new ModAchievementGrid(modID, headerText);
modAchievementGrids.put(modID, grid);
}

public static void registerAchievement(String id) {
if (achievementModID == null || achievementAtlas == null) {
throw new IllegalStateException("You must call registerAchievementGrid before registering achievements.");
}

String fullID = achievementModID + ":" + id;
UIStrings uiStrings = CardCrawlGame.languagePack.getUIString(fullID);
String name = uiStrings.TEXT[0];
String description = uiStrings.TEXT[1];
TextureAtlas.AtlasRegion achievementImageUnlocked = achievementAtlas.findRegion("unlocked/" + id);
TextureAtlas.AtlasRegion achievementImageLocked = achievementAtlas.findRegion("locked/" + id);

if (achievementImageUnlocked == null || achievementImageLocked == null) {
BaseMod.logger.info("Failed to find achievement images for: " + fullID);
return; // Skip adding this achievement
}

ModAchievement newAchievement = new ModAchievement(name, description, fullID, achievementImageUnlocked, achievementImageLocked, achievementAtlas);

ModAchievementGrid grid = modAchievementGrids.get(achievementModID);
if (grid == null) {
throw new IllegalStateException("Achievement grid for " + achievementModID + " not found. Make sure to call registerAchievementGrid first.");
}

for (ModAchievement achievement : grid.items) {
if (achievement.key.equals(fullID)) {
return; // Achievement already exists, skip adding
}
}

grid.items.add(newAchievement);
}

//
// Potions
//
Expand Down Expand Up @@ -2694,6 +2749,21 @@ public static void publishEditKeywords() {
}
unsubscribeLaterHelper(EditKeywordsSubscriber.class);
}
public static void publishEditAchievements(StatsScreen statsScreen) {
logger.info("editing achievements");
for (EditAchievementsSubscriber sub : editAchievementsSubscribers) {
sub.receiveEditAchievements();
}
try {
Method calculateScrollBoundsMethod = StatsScreen.class.getDeclaredMethod("calculateScrollBounds");
calculateScrollBoundsMethod.setAccessible(true);
calculateScrollBoundsMethod.invoke(statsScreen);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
logger.error("Failed to invoke calculateScrollBounds method: " + e.getMessage());
e.printStackTrace();
}
unsubscribeLaterHelper(EditAchievementsSubscriber.class);
}

// publishOnPowersModified
public static void publishOnPowersModified() {
Expand Down Expand Up @@ -2897,6 +2967,7 @@ public static void subscribe(ISubscriber sub) {
subscribeIfInstance(editCharactersSubscribers, sub, EditCharactersSubscriber.class);
subscribeIfInstance(editStringsSubscribers, sub, EditStringsSubscriber.class);
subscribeIfInstance(editKeywordsSubscribers, sub, EditKeywordsSubscriber.class);
subscribeIfInstance(editAchievementsSubscribers, sub, EditAchievementsSubscriber.class);
subscribeIfInstance(postBattleSubscribers, sub, PostBattleSubscriber.class);
subscribeIfInstance(setUnlocksSubscribers, sub, SetUnlocksSubscriber.class);
subscribeIfInstance(postPotionUseSubscribers, sub, PostPotionUseSubscriber.class);
Expand Down Expand Up @@ -2981,6 +3052,8 @@ public static void subscribe(ISubscriber sub, Class<? extends ISubscriber> addit
editStringsSubscribers.add((EditStringsSubscriber) sub);
} else if (additionClass.equals(EditKeywordsSubscriber.class)) {
editKeywordsSubscribers.add((EditKeywordsSubscriber) sub);
} else if (additionClass.equals(EditAchievementsSubscriber.class)) {
editAchievementsSubscribers.add((EditAchievementsSubscriber) sub);
} else if (additionClass.equals(PostBattleSubscriber.class)) {
postBattleSubscribers.add((PostBattleSubscriber) sub);
} else if (additionClass.equals(SetUnlocksSubscriber.class)) {
Expand Down Expand Up @@ -3055,6 +3128,7 @@ public static void unsubscribe(ISubscriber sub) {
unsubscribeIfInstance(editCharactersSubscribers, sub, EditCharactersSubscriber.class);
unsubscribeIfInstance(editStringsSubscribers, sub, EditStringsSubscriber.class);
unsubscribeIfInstance(editKeywordsSubscribers, sub, EditKeywordsSubscriber.class);
unsubscribeIfInstance(editAchievementsSubscribers, sub, EditAchievementsSubscriber.class);
unsubscribeIfInstance(postBattleSubscribers, sub, PostBattleSubscriber.class);
unsubscribeIfInstance(setUnlocksSubscribers, sub, SetUnlocksSubscriber.class);
unsubscribeIfInstance(postPotionUseSubscribers, sub, PostPotionUseSubscriber.class);
Expand Down Expand Up @@ -3139,6 +3213,8 @@ public static void unsubscribe(ISubscriber sub, Class<? extends ISubscriber> rem
editStringsSubscribers.remove(sub);
} else if (removalClass.equals(EditKeywordsSubscriber.class)) {
editKeywordsSubscribers.remove(sub);
} else if (removalClass.equals(EditAchievementsSubscriber.class)) {
editAchievementsSubscribers.remove(sub);
} else if (removalClass.equals(AddAudioSubscriber.class)) {
addAudioSubscribers.remove(sub);
} else if (removalClass.equals(PostBattleSubscriber.class)) {
Expand Down
91 changes: 91 additions & 0 deletions mod/src/main/java/basemod/ModAchievement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package basemod;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.helpers.Hitbox;
import com.megacrit.cardcrawl.helpers.TipHelper;
import com.megacrit.cardcrawl.helpers.input.InputHelper;
import com.megacrit.cardcrawl.unlock.UnlockTracker;

public class ModAchievement {
private TextureAtlas.AtlasRegion unlockedImg;
private TextureAtlas.AtlasRegion lockedImg;
public TextureAtlas.AtlasRegion currentImg;
private static final Color LOCKED_COLOR = new Color(1.0F, 1.0F, 1.0F, 0.8F);
private TextureAtlas atlas;
private String title;
private String desc;
public String key;
public boolean isUnlocked;
public Hitbox hb;

public ModAchievement(String title, String desc, String key, TextureAtlas.AtlasRegion unlockedImage, TextureAtlas.AtlasRegion lockedImage, TextureAtlas atlas) {
this.hb = new Hitbox(160.0F * Settings.scale, 160.0F * Settings.scale);
this.isUnlocked = UnlockTracker.isAchievementUnlocked(key);
this.key = key;
this.title = title;
this.desc = desc;
this.unlockedImg = unlockedImage;
this.lockedImg = lockedImage;
this.currentImg = lockedImage;
this.atlas = atlas;
if (this.unlockedImg == null || this.lockedImg == null) {
BaseMod.logger.info("Failed to load images for achievement: " + key);
}
}



public String getKey() {
return key;
}

public void reloadImg() {
if (this.isUnlocked) {
this.unlockedImg = atlas.findRegion(this.unlockedImg.name);
} else {
this.lockedImg = atlas.findRegion(this.lockedImg.name);
}
}

public void render(SpriteBatch sb, float x, float y) {
if (sb == null) {
BaseMod.logger.info("SpriteBatch is null in ModAchievement.render");
return;
}

TextureAtlas.AtlasRegion currentImg = this.isUnlocked ? this.unlockedImg : this.lockedImg;
if (currentImg == null) {
BaseMod.logger.info("Current image is null for achievement: " + this.key);
return;
}

this.currentImg = currentImg;
Color currentColor = this.isUnlocked ? Color.WHITE : LOCKED_COLOR;
sb.setColor(currentColor);

if (this.hb == null) {
this.hb = new Hitbox(160.0F * Settings.scale, 160.0F * Settings.scale);
}

if (this.hb.hovered) {
sb.draw(currentImg, x - (float)currentImg.packedWidth / 2.0F, y - (float)currentImg.packedHeight / 2.0F, (float)currentImg.packedWidth / 2.0F, (float)currentImg.packedHeight / 2.0F, (float)currentImg.packedWidth, (float)currentImg.packedHeight, Settings.scale * 1.1F, Settings.scale * 1.1F, 0.0F);
} else {
sb.draw(currentImg, x - (float)currentImg.packedWidth / 2.0F, y - (float)currentImg.packedHeight / 2.0F, (float)currentImg.packedWidth / 2.0F, (float)currentImg.packedHeight / 2.0F, (float)currentImg.packedWidth, (float)currentImg.packedHeight, Settings.scale, Settings.scale, 0.0F);
}

this.hb.move(x, y);
this.hb.render(sb);
}

public void update() {
if (this.hb != null) {
this.hb.update();
if (this.hb.hovered) {
TipHelper.renderGenericTip((float) InputHelper.mX + 100.0F * Settings.scale, (float)InputHelper.mY, this.title, this.desc);
}
}
}
}
57 changes: 57 additions & 0 deletions mod/src/main/java/basemod/ModAchievementGrid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package basemod;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.unlock.UnlockTracker;

import java.util.ArrayList;

public class ModAchievementGrid {
public ArrayList<ModAchievement> items = new ArrayList<>();
private static final float SPACING = 200.0F * Settings.scale;
private static final int ITEMS_PER_ROW = 5;
public String modID;
public String headerText;

public ModAchievementGrid(String modID, String headerText) {
this.modID = modID;
this.headerText = headerText;
}

public void updateAchievementStatus() {
for (ModAchievement item : items) {
String achievementKey = item.getKey();
boolean isUnlocked = UnlockTracker.isAchievementUnlocked(achievementKey);
item.isUnlocked = isUnlocked;
item.reloadImg();
}
}

public void render(SpriteBatch sb, float renderY) {
if (items == null) {
BaseMod.logger.info("Items list is null in ModAchievementGrid for mod: " + modID);
return;
}
for (int i = 0; i < items.size(); ++i) {
ModAchievement achievement = items.get(i);
if (achievement != null) {
achievement.render(sb, 560.0F * Settings.scale + (i % ITEMS_PER_ROW) * SPACING, renderY - (i / ITEMS_PER_ROW) * SPACING + 680.0F * Settings.yScale);
} else {
BaseMod.logger.info("Null achievement found in ModAchievementGrid for mod: " + modID);
}
}
}

public float calculateHeight() {
int numRows = (items.size() + ITEMS_PER_ROW - 1) / ITEMS_PER_ROW;
float height = numRows * SPACING + 50.0F * Settings.scale;
return height;
}

public void update() {
updateAchievementStatus();
for (ModAchievement item : items) {
item.update();
}
}
}
24 changes: 24 additions & 0 deletions mod/src/main/java/basemod/ModAchievementUnlocker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package basemod;

import com.megacrit.cardcrawl.core.Settings;
import static com.megacrit.cardcrawl.unlock.UnlockTracker.achievementPref;

public class ModAchievementUnlocker {
public static void unlockAchievement(String id) {
String currentModID = BaseMod.getAchievementModID();
if (currentModID == null) {
BaseMod.logger.error("Attempted to unlock achievement without a registered mod ID: " + id);
return;
}

String fullKey = currentModID + ":" + id;

if (!Settings.isShowBuild && Settings.isStandardRun()) {
if (!achievementPref.getBoolean(fullKey, false)) {
achievementPref.putBoolean(fullKey, true);
achievementPref.flush();
BaseMod.logger.info("Unlocked achievement: " + fullKey);
}
}
}
}
Loading