Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
* New art for Double (thanks Newigeg)
* New art for Exhale (thanks Zyalin)

#### CULL new cards
* Shrieking Hat (thanks wang429)

#### CULL balance/design changes

* Blasphemer: Smites added when drawn 5->4, Blasphemer+ now adds 4 upgraded Smites. (thanks LankSSBM)
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/stsjorbsmod/cards/DeathPreventionCard.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package stsjorbsmod.cards;

import org.apache.commons.lang3.mutable.MutableInt;

public interface DeathPreventionCard {
MutableInt currentPriority = new MutableInt(0);

int getPriority();
}
5 changes: 5 additions & 0 deletions src/main/java/stsjorbsmod/cards/WasHPLostCardSubscriber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package stsjorbsmod.cards;

public interface WasHPLostCardSubscriber {
void wasHPLost(int damageAmount);
}
55 changes: 51 additions & 4 deletions src/main/java/stsjorbsmod/cards/cull/OldBook.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package stsjorbsmod.cards.cull;

import basemod.abstracts.CustomSavable;
import com.megacrit.cardcrawl.actions.common.ApplyPowerAction;
import com.megacrit.cardcrawl.actions.common.ReducePowerAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.monsters.AbstractMonster;
import stsjorbsmod.JorbsMod;
import stsjorbsmod.cards.CustomJorbsModCard;
import stsjorbsmod.cards.DeathPreventionCard;
import stsjorbsmod.cards.OnCardExhumedSubscriber;
import stsjorbsmod.cards.OnEntombedSubscriber;
import stsjorbsmod.characters.Cull;
Expand All @@ -15,15 +18,16 @@

import static stsjorbsmod.JorbsMod.JorbsCardTags.LEGENDARY;

public class OldBook extends CustomJorbsModCard implements OnCardExhumedSubscriber, OnEntombedSubscriber {
public class OldBook extends CustomJorbsModCard implements OnCardExhumedSubscriber, OnEntombedSubscriber, DeathPreventionCard, CustomSavable<Integer> {
public static final String ID = JorbsMod.makeID(OldBook.class);

private static final CardRarity RARITY = CardRarity.RARE;
private static final CardTarget TARGET = CardTarget.SELF;
private static final CardType TYPE = CardType.SKILL;
public static final CardColor COLOR = Cull.Enums.CULL_CARD_COLOR;

private AbstractPlayer p = AbstractDungeon.player;
private final AbstractPlayer p = AbstractDungeon.player;
private int priority;

private static final int COST = COST_UNPLAYABLE;
private static final int HEAL_PERCENT = 0;
Expand All @@ -38,13 +42,34 @@ public OldBook() {
tags.add(LEGENDARY);
}

/**
* used in ShowCardAndAddToHandEffect::new which gets used in Discovery, Card Potions, and MakeTempCardInHandAction (Dead Branch and console command HandAdd)
*/
@Override
public void triggerWhenCopied() {
super.triggerWhenCopied();
priority = currentPriority.incrementAndGet();
}

/**
* used in FastCardObtainEffect::update (combat reward cards) and ShowCardAndObtainEffect::update (just about every other card acquisition method events/transforms/etc).
* overloading the meaning of shrink() because lazy.
*/
@Override
public void shrink() {
super.shrink();
priority = currentPriority.incrementAndGet();
}

@Override
public void onCardEntombed() {
addToTop(new ApplyPowerAction(p, p, new OldBookPower(AbstractDungeon.player, this, 1)));
}

@Override
public boolean canUse(AbstractPlayer abstractPlayer, AbstractMonster abstractMonster) { return false; }
public boolean canUse(AbstractPlayer abstractPlayer, AbstractMonster abstractMonster) {
return false;
}

@Override
public void use(AbstractPlayer abstractPlayer, AbstractMonster abstractMonster) {
Expand All @@ -55,12 +80,34 @@ public void onCardExhumed() {
addToBot(new ReducePowerAction(p, p, OldBookPower.POWER_ID, 1));
}

@Override
public int getPriority() {
return priority;
}

@Override
public void upgrade() {
if(!upgraded) {
if (!upgraded) {
upgradeName();
upgradeMagicNumber(UPGRADE_HEAL_PERCENT);
upgradeDescription();
}
}

@Override
public AbstractCard makeCopy() {
OldBook copy = (OldBook) super.makeCopy();
copy.priority = this.priority;
return copy;
}

@Override
public Integer onSave() {
return priority;
}

@Override
public void onLoad(Integer integer) {
this.priority = integer;
}
}
134 changes: 134 additions & 0 deletions src/main/java/stsjorbsmod/cards/cull/ShriekingHat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package stsjorbsmod.cards.cull;

import basemod.abstracts.CustomSavable;
import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.actions.animations.VFXAction;
import com.megacrit.cardcrawl.actions.common.DamageAllEnemiesAction;
import com.megacrit.cardcrawl.actions.utility.SFXAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.DamageInfo;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.monsters.AbstractMonster;
import com.megacrit.cardcrawl.vfx.cardManip.ShowCardBrieflyEffect;
import com.megacrit.cardcrawl.vfx.combat.ShockWaveEffect;
import stsjorbsmod.JorbsMod;
import stsjorbsmod.actions.ConsumerGameAction;
import stsjorbsmod.actions.PermanentlyModifyDamageAction;
import stsjorbsmod.cards.CustomJorbsModCard;
import stsjorbsmod.cards.DeathPreventionCard;
import stsjorbsmod.cards.WasHPLostCardSubscriber;
import stsjorbsmod.characters.Cull;
import stsjorbsmod.util.CardMetaUtils;
import stsjorbsmod.util.EffectUtils;

import static stsjorbsmod.JorbsMod.JorbsCardTags.LEGENDARY;

/**
* Unplayable. NL Retain. NL When you die instead deal (3 +) all damage taken while this was in your hand to all enemies. NL stsjorbsmod:Destroy.
*/
public class ShriekingHat extends CustomJorbsModCard implements DeathPreventionCard, WasHPLostCardSubscriber, CustomSavable<Integer> {
public static final String ID = JorbsMod.makeID(ShriekingHat.class);

private static final CardRarity RARITY = CardRarity.RARE;
private static final CardTarget TARGET = CardTarget.SELF;
private static final CardType TYPE = CardType.SKILL;
public static final CardColor COLOR = Cull.Enums.CULL_CARD_COLOR;

private AbstractPlayer p = AbstractDungeon.player;
private int priority;

private static final int COST = COST_UNPLAYABLE;
private static final int UPGRADE_DAMAGE = 3;

public ShriekingHat() {
super(ID, COST, TYPE, COLOR, RARITY, TARGET);

damage = baseDamage = misc = magicNumber = 0;
selfRetain = true;

tags.add(LEGENDARY);
}

@Override
public int getPriority() {
return priority;
}

/**
* used in ShowCardAndAddToHandEffect::new which gets used in Discovery, Card Potions, and MakeTempCardInHandAction leading to Dead Branch
*/
@Override
public void triggerWhenCopied() {
super.triggerWhenCopied();
priority = currentPriority.incrementAndGet();
}

/**
* used in ShowCardAndObtainEffect::update. Appears to be the way cards are added to the deck.
* overloading the meaning of shrink() because lazy.
*/
@Override
public void shrink() {
super.shrink();
priority = currentPriority.incrementAndGet();
}

@Override
public void wasHPLost(int damageAmount) {
addToBot(new PermanentlyModifyDamageAction(uuid, damageAmount));
}

@Override
public boolean canUse(AbstractPlayer abstractPlayer, AbstractMonster abstractMonster) {
this.cantUseMessage = cardStrings.EXTENDED_DESCRIPTION[1];
return false;
}

@Override
public void use(AbstractPlayer abstractPlayer, AbstractMonster abstractMonster) {
addToBot(new VFXAction(new ShowCardBrieflyEffect(this)));
addToBot(new SFXAction("ATTACK_PIERCING_WAIL", -1, true));
if (Settings.FAST_MODE) {
addToBot(new VFXAction(p, new ShockWaveEffect(p.hb.cX, p.hb.cY, Settings.RED_TEXT_COLOR, ShockWaveEffect.ShockWaveType.CHAOTIC), 0.3F));
} else {
addToBot(new VFXAction(p, new ShockWaveEffect(p.hb.cX, p.hb.cY, Settings.RED_TEXT_COLOR, ShockWaveEffect.ShockWaveType.CHAOTIC), 1.5F));
}
addToBot(new DamageAllEnemiesAction(p, baseDamage, DamageInfo.DamageType.THORNS, AbstractGameAction.AttackEffect.SLASH_HORIZONTAL));
addToBot(new ConsumerGameAction<>(EffectUtils::showDestroyEffect, this));
CardMetaUtils.destroyCardPermanently(this);
}

@Override
public String getRawDynamicDescriptionSuffix() {
return EXTENDED_DESCRIPTION[0];
}

@Override
public void upgrade() {
if (!upgraded) {
upgradeName();
upgradeMagicNumber(UPGRADE_DAMAGE);
upgradeDamage(UPGRADE_DAMAGE);
upgradeDescription();
}
}

@Override
public AbstractCard makeCopy() {
ShriekingHat copy = (ShriekingHat) super.makeCopy();
copy.priority = this.priority;
return copy;
}

@Override
public Integer onSave() {
return priority;
}

@Override
public void onLoad(Integer integer) {
this.priority = integer;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package stsjorbsmod.patches;

import com.evacipated.cardcrawl.modthespire.lib.SpirePatch;
import com.evacipated.cardcrawl.modthespire.lib.SpirePrefixPatch;
import com.megacrit.cardcrawl.actions.common.RemoveSpecificPowerAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.DamageInfo;
Expand All @@ -13,28 +12,63 @@
import javassist.CannotCompileException;
import javassist.expr.ExprEditor;
import javassist.expr.FieldAccess;
import stsjorbsmod.cards.DeathPreventionCard;
import stsjorbsmod.cards.cull.OldBook;
import stsjorbsmod.cards.cull.ShriekingHat;
import stsjorbsmod.powers.OldBookPower;
import stsjorbsmod.util.CardMetaUtils;

import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;

@SpirePatch(clz = DamageInfo.class, method = SpirePatch.CLASS)
public class OldBookPatch {
public static boolean triggerOldBook(AbstractPlayer p, int damageAmount) {
public class DeathPreventionPatch {
public static boolean triggerDeathPrevention(AbstractPlayer p, int damageAmount) {
if (damageAmount < p.currentHealth)
return false;
if (!p.hasPower(OldBookPower.POWER_ID + OldBookPower.UPGRADED) &&
!p.hasPower(OldBookPower.POWER_ID + OldBookPower.NORMAL))
!p.hasPower(OldBookPower.POWER_ID + OldBookPower.NORMAL) &&
p.hand.group.stream().noneMatch(c -> c instanceof ShriekingHat))
return false;
if (p.hasPotion(FairyPotion.POTION_ID))
return false;
if (p.hasRelic(LizardTail.ID) && ((LizardTail) p.getRelic(LizardTail.ID)).counter == -1)
if (p.hasRelic(LizardTail.ID) && p.getRelic(LizardTail.ID).counter == -1)
return false;

OldBookPower po = null;
// requested that death preventing cards trigger in order of pickup.
SortedSet<DeathPreventionCard> deathPreventionCards = new TreeSet<>(Comparator.comparingInt(DeathPreventionCard::getPriority));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the change suggested above, we should be able to loop the masterDeck object first to determine "permanent" cards that were added to the deck that need to be consumed, and then pursue the "temporary" cards using your priority implemented.

Copy link
Collaborator Author

@wang429 wang429 Dec 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It added a little bit more complexity to the the logic, but I think it should work as expected.

for (AbstractCard c : p.hand.group) {
if (c instanceof ShriekingHat) {
deathPreventionCards.add((DeathPreventionCard) c);
}
}
for (AbstractCard c : p.exhaustPile.group) {
if (c instanceof OldBook) {
deathPreventionCards.add((DeathPreventionCard) c);
}
}

if (deathPreventionCards.isEmpty()) {
return false;
}
AbstractCard firstDeathPreventionCard = (AbstractCard) deathPreventionCards.first();

if (OldBook.ID.equals(firstDeathPreventionCard.cardID)) {
handleOldBook(p);
} else if (ShriekingHat.ID.equals(firstDeathPreventionCard.cardID)) {
handleShriekingHat(p, (ShriekingHat) firstDeathPreventionCard);
}

return true;
}

private static void handleOldBook(AbstractPlayer p) {
OldBookPower po;
if (p.hasPower(OldBookPower.POWER_ID + OldBookPower.NORMAL))
po = (OldBookPower)p.getPower(OldBookPower.POWER_ID + OldBookPower.NORMAL);
po = (OldBookPower) p.getPower(OldBookPower.POWER_ID + OldBookPower.NORMAL);
else
po = (OldBookPower)p.getPower(OldBookPower.POWER_ID + OldBookPower.UPGRADED);
po = (OldBookPower) p.getPower(OldBookPower.POWER_ID + OldBookPower.UPGRADED);

AbstractCard c = po.getCard();
if (c.upgraded) {
Expand All @@ -46,9 +80,8 @@ public static boolean triggerOldBook(AbstractPlayer p, int damageAmount) {
}

p.heal(healAmt, true);
}
else {
((MarkOfTheBloom) p.getRelic(MarkOfTheBloom.ID)).flash();
} else {
p.getRelic(MarkOfTheBloom.ID).flash();
}
}

Expand All @@ -57,8 +90,10 @@ public static boolean triggerOldBook(AbstractPlayer p, int damageAmount) {
AbstractDungeon.actionManager.addToBottom(new RemoveSpecificPowerAction(p, p, po));

CardMetaUtils.destroyCardPermanently(c);
}

return true;
private static void handleShriekingHat(AbstractPlayer p, ShriekingHat shriekingHatCard) {
shriekingHatCard.use(p, null);
}

@SpirePatch(clz = AbstractPlayer.class, method = "damage")
Expand All @@ -69,9 +104,9 @@ public static ExprEditor Instrument() {
public void edit(FieldAccess fieldAccess) throws CannotCompileException {
if (fieldAccess.getClassName().equals(AbstractPlayer.class.getName()) &&
fieldAccess.getFieldName().equals("lastDamageTaken")) {
fieldAccess.replace(String.format("{ if (%1$s.triggerOldBook($0, damageAmount)) { damageAmount = 0; lastDamageTaken = 0; }" +
"else { $proceed($$); }; } ",
OldBookPatch.class.getName()));
fieldAccess.replace(String.format("{ if (%1$s.triggerDeathPrevention($0, damageAmount)) { damageAmount = 0; lastDamageTaken = 0; }" +
"else { $proceed($$); }; } ",
DeathPreventionPatch.class.getName()));
}
}
};
Expand Down
Loading