mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
add an AF_MustBlock (for things like Target creature blocks CARDNAME this turn if able.)
-also fixes an issue with Card.ChosenColor property
This commit is contained in:
@@ -96,6 +96,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
private boolean dealtDmgToHumanThisTurn = false;
|
private boolean dealtDmgToHumanThisTurn = false;
|
||||||
private boolean dealtDmgToComputerThisTurn = false;
|
private boolean dealtDmgToComputerThisTurn = false;
|
||||||
private boolean sirenAttackOrDestroy = false;
|
private boolean sirenAttackOrDestroy = false;
|
||||||
|
private ArrayList<Card> mustBlockCards = new ArrayList<Card>();
|
||||||
|
|
||||||
private boolean canMorph = false;
|
private boolean canMorph = false;
|
||||||
private boolean faceDown = false;
|
private boolean faceDown = false;
|
||||||
@@ -650,6 +651,38 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
public final boolean getSirenAttackOrDestroy() {
|
public final boolean getSirenAttackOrDestroy() {
|
||||||
return sirenAttackOrDestroy;
|
return sirenAttackOrDestroy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a Card that this Card must block if able in an upcoming combat.
|
||||||
|
* This is cleared at the end of each turn.
|
||||||
|
*
|
||||||
|
* @param o Card to block
|
||||||
|
*
|
||||||
|
* @since 1.1.6
|
||||||
|
*/
|
||||||
|
public void addMustBlockCard(Card c) {
|
||||||
|
mustBlockCards.add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the Card that this Card must block this combat
|
||||||
|
*
|
||||||
|
* @return the Cards to block (if able)
|
||||||
|
*
|
||||||
|
* @since 1.1.6
|
||||||
|
*/
|
||||||
|
public ArrayList<Card> getMustBlockCards() {
|
||||||
|
return mustBlockCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear the list of Cards that this Card must block this combat
|
||||||
|
*
|
||||||
|
* @since 1.1.6
|
||||||
|
*/
|
||||||
|
public void clearMustBlockCards() {
|
||||||
|
mustBlockCards.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Getter for the field <code>clones</code>.</p>
|
* <p>Getter for the field <code>clones</code>.</p>
|
||||||
@@ -5058,7 +5091,8 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
if (Property.startsWith("non") && (CardUtil.getColors(this).size() == 1 && !isColorless())) return false;
|
if (Property.startsWith("non") && (CardUtil.getColors(this).size() == 1 && !isColorless())) return false;
|
||||||
if (!Property.startsWith("non") && (CardUtil.getColors(this).size() > 1 || isColorless())) return false;
|
if (!Property.startsWith("non") && (CardUtil.getColors(this).size() > 1 || isColorless())) return false;
|
||||||
} else if (Property.equals("ChosenColor")) {
|
} else if (Property.equals("ChosenColor")) {
|
||||||
if (!CardUtil.getColors(this).contains(source.getChosenColor())) return false;
|
//Should this match All chosen colors, or any? Default to first chosen for now until it matters.
|
||||||
|
if (!CardUtil.getColors(this).contains(source.getChosenColor().get(0))) return false;
|
||||||
} else if (Property.startsWith("YouCtrl")) {
|
} else if (Property.startsWith("YouCtrl")) {
|
||||||
if (!getController().isPlayer(sourceController)) return false;
|
if (!getController().isPlayer(sourceController)) return false;
|
||||||
} else if (Property.startsWith("YouDontCtrl")) {
|
} else if (Property.startsWith("YouDontCtrl")) {
|
||||||
|
|||||||
@@ -560,6 +560,8 @@ public class ComputerUtil_Block2 {
|
|||||||
setBlockedButUnkilled(new CardList()); //keeps track of all blocked attackers that currently wouldn't be destroyed
|
setBlockedButUnkilled(new CardList()); //keeps track of all blocked attackers that currently wouldn't be destroyed
|
||||||
CardList blockers;
|
CardList blockers;
|
||||||
CardList chumpBlockers;
|
CardList chumpBlockers;
|
||||||
|
|
||||||
|
setupForcedBlocks(combat);
|
||||||
|
|
||||||
setDiff(AllZone.getComputerPlayer().getLife() * 2 - 5); //This is the minimal gain for an unnecessary trade
|
setDiff(AllZone.getComputerPlayer().getLife() * 2 - 5); //This is the minimal gain for an unnecessary trade
|
||||||
|
|
||||||
@@ -642,4 +644,19 @@ public class ComputerUtil_Block2 {
|
|||||||
|
|
||||||
return combat;
|
return combat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setupForcedBlocks(Combat combat) {
|
||||||
|
CardList blockers = AllZoneUtil.getCreaturesInPlay(combat.getDefendingPlayer());
|
||||||
|
for (Card blocker : blockers) {
|
||||||
|
if (!blocker.getMustBlockCards().isEmpty()) {
|
||||||
|
ArrayList<Card> blocks = blocker.getMustBlockCards();
|
||||||
|
for (Card attacker : blocks) {
|
||||||
|
if (attacker.isAttacking() && CombatUtil.canBlock(attacker, blocker)) {
|
||||||
|
combat.addBlocker(attacker, blocker);
|
||||||
|
getBlockersLeft().remove(blocker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ public class EndOfTurn implements java.io.Serializable {
|
|||||||
|
|
||||||
CardList all2 = AllZoneUtil.getCardsIn(Zone.Battlefield);
|
CardList all2 = AllZoneUtil.getCardsIn(Zone.Battlefield);
|
||||||
for (Card c : all2) {
|
for (Card c : all2) {
|
||||||
|
c.clearMustBlockCards();
|
||||||
if (c.getCreatureAttackedThisTurn()) {
|
if (c.getCreatureAttackedThisTurn()) {
|
||||||
c.setCreatureAttackedThisTurn(false);
|
c.setCreatureAttackedThisTurn(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1050,6 +1050,16 @@ public class AbilityFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (API.equals("MustBlock")) {
|
||||||
|
if (isAb) {
|
||||||
|
SA = AbilityFactory_Combat.createAbilityMustBlock(this);
|
||||||
|
} else if (isSp) {
|
||||||
|
SA = AbilityFactory_Combat.createSpellMustBlock(this);
|
||||||
|
} else if (isDb) {
|
||||||
|
SA = AbilityFactory_Combat.createDrawbackMustBlock(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (API.equals("Charm")) {
|
else if (API.equals("Charm")) {
|
||||||
if (isAb) {
|
if (isAb) {
|
||||||
SA = AbilityFactory_Charm.createAbilityCharm(this);
|
SA = AbilityFactory_Charm.createAbilityCharm(this);
|
||||||
|
|||||||
@@ -665,5 +665,227 @@ public final class AbilityFactory_Combat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} //mustAttackResolve()
|
} //mustAttackResolve()
|
||||||
|
|
||||||
|
//**************************************************************
|
||||||
|
//*********************** MustBlock ****************************
|
||||||
|
//**************************************************************
|
||||||
|
|
||||||
|
//AB$ MustBlock | Cost$ R T | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature defending player controls | DefinedAttacker$ Self | SpellDescription$ ...
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>createAbilityMustBlock.</p>
|
||||||
|
*
|
||||||
|
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
|
||||||
|
* @return a {@link forge.card.spellability.SpellAbility} object.
|
||||||
|
*
|
||||||
|
* @since 1.1.6
|
||||||
|
*/
|
||||||
|
public static SpellAbility createAbilityMustBlock(final AbilityFactory af) {
|
||||||
|
final SpellAbility abMustBlock = new Ability_Activated(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
|
||||||
|
private static final long serialVersionUID = 4237190949098526123L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription() {
|
||||||
|
return mustBlockStackDescription(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlayAI() {
|
||||||
|
return mustBlockCanPlayAI(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
mustBlockResolve(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doTrigger(final boolean mandatory) {
|
||||||
|
return mustBlockDoTriggerAI(af, this, mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return abMustBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>createSpellMustBlock.</p>
|
||||||
|
*
|
||||||
|
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
|
||||||
|
* @return a {@link forge.card.spellability.SpellAbility} object.
|
||||||
|
*
|
||||||
|
* @since 1.1.6
|
||||||
|
*/
|
||||||
|
public static SpellAbility createSpellMustBlock(final AbilityFactory af) {
|
||||||
|
final SpellAbility spMustBlock = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
|
||||||
|
private static final long serialVersionUID = 6758785067306305860L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStackDescription() {
|
||||||
|
return mustBlockStackDescription(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlayAI() {
|
||||||
|
return mustBlockCanPlayAI(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
mustBlockResolve(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return spMustBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>createDrawbackMustBlock.</p>
|
||||||
|
*
|
||||||
|
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
|
||||||
|
* @return a {@link forge.card.spellability.SpellAbility} object.
|
||||||
|
*
|
||||||
|
* @since 1.1.6
|
||||||
|
*/
|
||||||
|
public static SpellAbility createDrawbackMustBlock(final AbilityFactory af) {
|
||||||
|
final SpellAbility dbMustBlock = new Ability_Sub(af.getHostCard(), af.getAbTgt()) {
|
||||||
|
private static final long serialVersionUID = -815813765448972775L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve() {
|
||||||
|
mustBlockResolve(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean chkAI_Drawback() {
|
||||||
|
return mustBlockPlayDrawbackAI(af, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doTrigger(final boolean mandatory) {
|
||||||
|
return mustBlockDoTriggerAI(af, this, mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return dbMustBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String mustBlockStackDescription(final AbilityFactory af, final SpellAbility sa) {
|
||||||
|
HashMap<String, String> params = af.getMapParams();
|
||||||
|
Card host = af.getHostCard();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (sa instanceof Ability_Sub) {
|
||||||
|
sb.append(" ");
|
||||||
|
} else {
|
||||||
|
sb.append(sa.getSourceCard()).append(" - ");
|
||||||
|
}
|
||||||
|
|
||||||
|
//end standard pre-
|
||||||
|
|
||||||
|
ArrayList<Card> tgtCards;
|
||||||
|
|
||||||
|
Target tgt = af.getAbTgt();
|
||||||
|
if (tgt != null) {
|
||||||
|
tgtCards = tgt.getTargetCards();
|
||||||
|
} else {
|
||||||
|
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
String attacker = null;
|
||||||
|
if (params.containsKey("DefinedAttacker")) {
|
||||||
|
ArrayList<Card> cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("DefinedAttacker"), sa);
|
||||||
|
attacker = cards.get(0).toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
attacker = host.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Card c : tgtCards) {
|
||||||
|
sb.append(c).append(" must block ").append(attacker).append(" if able.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//begin standard post-
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null) {
|
||||||
|
sb.append(abSub.getStackDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean mustBlockCanPlayAI(final AbilityFactory af, final SpellAbility sa) {
|
||||||
|
//disabled for the AI until he/she can make decisions about who to make block
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean mustBlockPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa) {
|
||||||
|
// AI should only activate this during Human's turn
|
||||||
|
boolean chance;
|
||||||
|
|
||||||
|
//TODO - implement AI
|
||||||
|
chance = false;
|
||||||
|
|
||||||
|
Ability_Sub subAb = sa.getSubAbility();
|
||||||
|
if (subAb != null) {
|
||||||
|
chance &= subAb.chkAI_Drawback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean mustBlockDoTriggerAI(final AbilityFactory af, final SpellAbility sa,
|
||||||
|
final boolean mandatory)
|
||||||
|
{
|
||||||
|
// If there is a cost payment it's usually not mandatory
|
||||||
|
if (!ComputerUtil.canPayCost(sa) && !mandatory) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean chance;
|
||||||
|
|
||||||
|
//TODO - implement AI
|
||||||
|
chance = false;
|
||||||
|
|
||||||
|
// check SubAbilities DoTrigger?
|
||||||
|
Ability_Sub abSub = sa.getSubAbility();
|
||||||
|
if (abSub != null) {
|
||||||
|
return chance && abSub.doTrigger(mandatory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mustBlockResolve(final AbilityFactory af, final SpellAbility sa) {
|
||||||
|
HashMap<String, String> params = af.getMapParams();
|
||||||
|
Card host = af.getHostCard();
|
||||||
|
|
||||||
|
ArrayList<Card> tgtCards;
|
||||||
|
|
||||||
|
Target tgt = af.getAbTgt();
|
||||||
|
if (tgt != null) {
|
||||||
|
tgtCards = tgt.getTargetCards();
|
||||||
|
} else {
|
||||||
|
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Card> cards;
|
||||||
|
if (params.containsKey("DefinedAttacker")) {
|
||||||
|
cards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("DefinedAttacker"), sa);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cards = new ArrayList<Card>();
|
||||||
|
cards.add(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Card c : tgtCards) {
|
||||||
|
if (tgt == null || CardFactoryUtil.canTarget(sa, c)) {
|
||||||
|
Card attacker = cards.get(0);
|
||||||
|
c.addMustBlockCard(attacker);
|
||||||
|
System.out.println(c+ " is adding "+attacker+" to mustBlockCards: "+c.getMustBlockCards());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} //mustBlockResolve()
|
||||||
|
|
||||||
} //end class AbilityFactory_Combat
|
} //end class AbilityFactory_Combat
|
||||||
|
|||||||
Reference in New Issue
Block a user