diff --git a/res/cards.txt b/res/cards.txt
index 6c3addc26ac..858abaa43e3 100644
--- a/res/cards.txt
+++ b/res/cards.txt
@@ -1,3 +1,41 @@
+Windborn Muse
+3 W
+Creature Spirit
+Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
+2/3
+Flying
+
+Ghostly Prison
+2 W
+Enchantment
+Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
+
+Propaganda
+2 U
+Enchantment
+Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
+
+Peacekeeper
+2 W
+Creature Human
+Creatures can't attack
+1/1
+Upkeep:1 W
+
+Arctic Nishoba
+5 G
+Creature Cat
+When Arctic Nishoba is put into a graveyard from the battlefield, you gain 2 life for each age counter on it.
+6/6
+Trample
+Cumulative upkeep:GW
+
+Marsh Viper
+3 G
+Creature Snake
+Whenever Marsh Viper deals damage to an opponent, that player gets two poison counters.
+1/2
+
Force of Will
3 U U
Instant
@@ -705,8 +743,9 @@ no text
Pit Scorpion
2 B
Creature Scorpion
-Whenever this creature deals damage to a player, that player gets a poison counter.
+no text
1/1
+Whenever this creature deals damage to a player, that player gets a poison counter.
Bridge from Below
B B B
diff --git a/res/gui/display_layout.xml b/res/gui/display_layout.xml
index bccfaa3c994..d837cee299c 100644
--- a/res/gui/display_layout.xml
+++ b/res/gui/display_layout.xml
@@ -339,7 +339,7 @@
255533901
- 145
+ 146
@@ -358,7 +358,7 @@
@@ -373,9 +373,9 @@
diff --git a/src/forge/CardFactory.java b/src/forge/CardFactory.java
index aeaa640402b..9f831baa4cd 100644
--- a/src/forge/CardFactory.java
+++ b/src/forge/CardFactory.java
@@ -17904,7 +17904,8 @@ return land.size() > 1 && CardFactoryUtil.AI_isMainPhase();
public void selectButtonCancel() {stop();}
public void selectCard(Card c, PlayerZone zone)
{
- if(CardUtil.getColors(c).contains(Constant.Color.Blue) && zone.is(Constant.Zone.Hand))
+ if(CardUtil.getColors(c).contains(Constant.Color.Blue) && zone.is(Constant.Zone.Hand) &&
+ !c.equals(card))
{
AllZone.GameAction.removeFromGame(c);
String player = card.getController();
diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java
index 7e477deded6..8d69169a0d1 100644
--- a/src/forge/CardFactoryUtil.java
+++ b/src/forge/CardFactoryUtil.java
@@ -505,8 +505,8 @@ public class CardFactoryUtil
{
if(choices.contains(card))
{
- AllZone.getZone(card).remove(card);
- AllZone.GameAction.moveToGraveyard(card);
+ //AllZone.getZone(card).remove(card);
+ AllZone.GameAction.sacrifice(card);
stop();
}
}
@@ -3025,7 +3025,6 @@ public class CardFactoryUtil
return count;
}
-
public static CardList getFastbonds(String player)
{
CardList list = new CardList(AllZone.getZone(Constant.Zone.Play, player).getCards());
@@ -3033,6 +3032,28 @@ public class CardFactoryUtil
return list;
}
+ //total cost to pay for an attacker c, cards like Propaganda, Ghostly Prison, Collective Restraint, ...
+ public static String getPropagandaCost(Card c)
+ {
+ String s = "";
+
+ PlayerZone play = AllZone.getZone(Constant.Zone.Play, AllZone.GameAction.getOpponent(c.getController()));
+ CardList list = new CardList(play.getCards());
+ list = list.filter(new CardListFilter()
+ {
+ public boolean addCard(Card c)
+ {
+ return c.getName().equals("Propaganda") || c.getName().equals("Windborn Muse") || c.getName().equals("Ghostly Prison");
+ }
+ });
+ int cost = list.size() * 2;
+
+ s = Integer.toString(cost);
+
+ return s;
+ }
+
+
//do card1 and card2 share any colors?
public static boolean sharesColorWith(Card card1, Card card2)
{
diff --git a/src/forge/CardFactory_Creatures.java b/src/forge/CardFactory_Creatures.java
index bae30351a00..521df7e2fdb 100644
--- a/src/forge/CardFactory_Creatures.java
+++ b/src/forge/CardFactory_Creatures.java
@@ -19368,7 +19368,7 @@ public class CardFactory_Creatures {
}//*************** END ************ END **************************
- //*************** END ************ END **************************
+ //*************** START *********** START **************************
else if (cardName.equals("Lockjaw Snapper"))
{
@@ -19408,8 +19408,34 @@ public class CardFactory_Creatures {
}
};//command
card.addDestroyCommand(destroy);
- }//*************** START *********** START **************************
+ }//*************** END ************ END **************************
+ //*************** START *********** START **************************
+ else if (cardName.equals("Arctic Nishoba"))
+ {
+ final Ability ability = new Ability(card, "0")
+ {
+ public void resolve()
+ {
+ int lifeGain = card.getCounters(Counters.AGE) * 2;
+ AllZone.GameAction.getPlayerLife(card.getController()).addLife(lifeGain);
+
+ }
+ };
+
+ Command destroy = new Command()
+ {
+ private static final long serialVersionUID = 1863551466234257411L;
+
+ public void execute()
+ {
+ ability.setStackDescription(card.getName()+ " - gain 2 life for each age counter on it.");
+ AllZone.Stack.add(ability);
+ }
+ };//command
+
+ card.addDestroyCommand(destroy);
+ }//*************** END ************ END **************************
// Cards with Cycling abilities
// -1 means keyword "Cycling" not found
if (shouldCycle(card) != -1)
diff --git a/src/forge/Combat.java b/src/forge/Combat.java
index 17784ac46b5..1127044583f 100644
--- a/src/forge/Combat.java
+++ b/src/forge/Combat.java
@@ -145,7 +145,7 @@ public class Combat
public void addAttackingDamage(int n) {attackingDamage += n;}
public int getAttackingDamage() {return attackingDamage;}
- public void addAttacker(Card c) {map.put(c, new CardList()); declaredAttackers++;}
+ public void addAttacker(Card c) {map.put(c, new CardList()); declaredAttackers++; }
public void resetAttackers() {map.clear();}
public Card[] getAttackers()
{
diff --git a/src/forge/CombatUtil.java b/src/forge/CombatUtil.java
index 7b593de5b5e..b8888b7dcad 100644
--- a/src/forge/CombatUtil.java
+++ b/src/forge/CombatUtil.java
@@ -17,11 +17,6 @@ public class CombatUtil
&& blocker.getKeyword().contains("This creature can block creatures with shadow as though they didn't have shadow."))
return false;
- /*
- if(attacker.getKeyword().contains("Shadow"))
- return blocker.getKeyword().contains("Shadow") ||
- blocker.getKeyword().contains("This creature can block creatures with shadow as though they didn't have shadow.");
- */
if (attacker.getKeyword().contains("Shadow") && !blocker.getKeyword().contains("Shadow")
&& !blocker.getKeyword().contains("This creature can block creatures with shadow as though they didn't have shadow.") )
return false;
@@ -194,13 +189,14 @@ public class CombatUtil
public static boolean canAttack(Card c)
{
+ if (isPeaceKeeperInPlay())
+ return false;
+
boolean moatPrevented = false;
if (isMoatInPlay() || isMagusMoatInPlay())
{
if (!c.getKeyword().contains("Flying"))
- {
moatPrevented = true;
- }
}
PlayerZone play = AllZone.getZone(Constant.Zone.Play,AllZone.GameAction.getOpponent(c.getController()));
@@ -661,6 +657,16 @@ public class CombatUtil
return false;
}
+ public static boolean isPeaceKeeperInPlay()
+ {
+ CardList all = new CardList();
+ all.addAll(AllZone.Human_Play.getCards());
+ all.addAll(AllZone.Computer_Play.getCards());
+
+ all = all.getName("Peacekeeper");
+ return all.size() > 0;
+ }
+
public static boolean isMoatInPlay()
{
CardList all = new CardList();
@@ -687,6 +693,68 @@ public class CombatUtil
return false;
}
+ public static boolean checkPropagandaEffects(Card c)
+ {
+ if (CardFactoryUtil.getPropagandaCost(c).equals("0"))
+ return true;
+
+ final Card crd = c;
+ final boolean[] canAttack = new boolean[1];
+ canAttack[0] = false;
+ //if (AllZone.Phase.getPhase().equals(Constant.Phase.Combat_Declare_Attackers))
+ if (AllZone.Phase.getPhase().equals("Declare Blockers") ||
+ AllZone.Phase.getPhase().equals(Constant.Phase.Combat_Declare_Attackers_InstantAbility))
+ {
+ //if (!c.getCreatureAttackedThisTurn())
+ //{
+ String cost = CardFactoryUtil.getPropagandaCost(c);
+ if (!cost.equals("0"))
+ {
+ final Ability ability = new Ability(c, cost)
+ {
+ public void resolve()
+ {
+ canAttack[0] = true;
+ }
+ };
+
+ final Command unpaidCommand = new Command() {
+
+ private static final long serialVersionUID = -6483405139208343935L;
+
+ public void execute() {
+ //AllZone.GameAction.sacrifice(c);
+ canAttack[0] = false;
+ AllZone.Combat.removeFromCombat(crd);
+ crd.untap();
+ }
+ };
+
+ final Command paidCommand = new Command() {
+ private static final long serialVersionUID = -8303368287601871955L;
+
+ public void execute() {
+ canAttack[0] = true;
+ }
+ };
+
+ if (c.getController().equals(Constant.Player.Human)) {
+ AllZone.InputControl.setInput(new Input_PayManaCost_Ability("Propaganda "+ c +"\r\n", ability.getManaCost(), paidCommand, unpaidCommand));
+ }
+ else //computer
+ {
+ if (ComputerUtil.canPayCost(ability))
+ ComputerUtil.playNoStack(ability);
+ else
+ canAttack[0] = false;
+ }
+ }
+ }
+ //c.setCreatureAttackedThisTurn(true);
+ //}
+ return canAttack[0];
+ }
+
public static void checkDeclareAttackers(Card c) //this method checks triggered effects of attacking creatures, right before defending player declares blockers
{
//human does not have an "attackers_instantAbility" phase during his turn (yet), so triggers will happen at the beginning of declare blockers
diff --git a/src/forge/GameActionUtil.java b/src/forge/GameActionUtil.java
index 8b4f7e8a2f0..a4a0f55934e 100644
--- a/src/forge/GameActionUtil.java
+++ b/src/forge/GameActionUtil.java
@@ -4108,9 +4108,11 @@ public class GameActionUtil
{
if (c.getKeyword().contains("Whenever this creature deals damage to a player, that player gets a poison counter."))
- playerCombatDamage_PoisonCounter(c);
+ playerCombatDamage_PoisonCounter(c, 1);
- if (c.getName().equals("Hypnotic Specter"))
+ if (c.getName().equals("Marsh Viper"))
+ playerCombatDamage_PoisonCounter(c, 2);
+ else if (c.getName().equals("Hypnotic Specter"))
playerCombatDamage_Hypnotic_Specter(c);
else if (c.getName().equals("Dimir Cutpurse"))
playerCombatDamage_Dimir_Cutpurse(c);
@@ -4207,15 +4209,15 @@ public class GameActionUtil
}
*/
- private static void playerCombatDamage_PoisonCounter(Card c)
+ private static void playerCombatDamage_PoisonCounter(Card c, int n)
{
final String player = c.getController();
final String opponent = AllZone.GameAction.getOpponent(player);
if (opponent.equals(Constant.Player.Human))
- AllZone.Human_PoisonCounter.addPoisonCounters(1);
+ AllZone.Human_PoisonCounter.addPoisonCounters(n);
else
- AllZone.Computer_PoisonCounter.addPoisonCounters(1);
+ AllZone.Computer_PoisonCounter.addPoisonCounters(n);
}
private static void playerCombatDamage_Oros(Card c)
@@ -5134,6 +5136,7 @@ public class GameActionUtil
+
private static void upkeep_AEther_Vial()
{
final String player = AllZone.Phase.getActivePlayer();
diff --git a/src/forge/InputControl.java b/src/forge/InputControl.java
index 3c568fb5df8..0a77118cb1f 100644
--- a/src/forge/InputControl.java
+++ b/src/forge/InputControl.java
@@ -89,10 +89,12 @@ import java.util.*;
CardList list = new CardList();
list.addAll(AllZone.Combat.getAttackers());
list.addAll(AllZone.pwCombat.getAttackers());
+
+ for (Card c : list)
+ CombatUtil.checkPropagandaEffects(c);
+
for (Card c : list)
- {
CombatUtil.checkDeclareAttackers(c);
- }
return new Input_Attack_Instant();
}
@@ -296,6 +298,10 @@ import java.util.*;
CardList list = new CardList();
list.addAll(AllZone.Combat.getAttackers());
list.addAll(AllZone.pwCombat.getAttackers());
+ for (Card c : list)
+ {
+ CombatUtil.checkPropagandaEffects(c);
+ }
for (Card c : list)
{
CombatUtil.checkDeclareAttackers(c);
diff --git a/src/forge/Input_Attack.java b/src/forge/Input_Attack.java
index 212bc422c50..de16bc7ecf7 100644
--- a/src/forge/Input_Attack.java
+++ b/src/forge/Input_Attack.java
@@ -17,6 +17,7 @@ public void showMessage()
Card c = creats.get(i);
if (CombatUtil.canAttack(c) && c.getKeyword().contains("This card attacks each turn if able."))
{
+
AllZone.Combat.addAttacker(c);
if (!c.getKeyword().contains("Vigilance"))
c.tap();
@@ -62,15 +63,15 @@ public void showMessage()
CombatUtil.canAttack(card)
)
{
+
if(! card.getKeyword().contains("Vigilance"))
{
card.tap();
-
//otherwise cards stay untapped, not sure why this is needed but it works
AllZone.Human_Play.updateObservers();
}
AllZone.Combat.addAttacker(card);
-
+
//for Castle Raptors, since it gets a bonus if untapped
for (String effect : AllZone.StateBasedEffects.getStateBasedMap().keySet() ) {
Command com = GameActionUtil.commands.get(effect);
diff --git a/src/forge/Input_PayManaCost_Ability.java b/src/forge/Input_PayManaCost_Ability.java
index b541bc76ed5..ebdaf781085 100644
--- a/src/forge/Input_PayManaCost_Ability.java
+++ b/src/forge/Input_PayManaCost_Ability.java
@@ -65,9 +65,11 @@ public class Input_PayManaCost_Ability extends Input
//tappedLand.clear();
AllZone.ManaPool.paid();
- //Command MUST BE AFTER, for Urborg Syphon-Mage - tap, mana, discard abilit
- stopSetNext(new ComputerAI_StackNotEmpty());
+ //Command MUST BE AFTER, for Urborg Syphon-Mage - tap, mana, discard ability
+ //does it really have to be after?
paidCommand.execute();
+ stopSetNext(new ComputerAI_StackNotEmpty());
+ //paidCommand.execute();
}
}