- Initial code to Combine Combat and pwCombat into a unified combat front.

- Human can now attack more than one Planeswalker.
This commit is contained in:
jendave
2011-08-06 14:15:37 +00:00
parent eea8f37930
commit 9cf0ec99ae
19 changed files with 441 additions and 710 deletions

2
.gitattributes vendored
View File

@@ -6367,9 +6367,7 @@ src/forge/ImagePreviewPanel.java -text svneol=native#text/plain
src/forge/Input.java svneol=native#text/plain src/forge/Input.java svneol=native#text/plain
src/forge/InputControl.java svneol=native#text/plain src/forge/InputControl.java svneol=native#text/plain
src/forge/Input_Attack.java svneol=native#text/plain src/forge/Input_Attack.java svneol=native#text/plain
src/forge/Input_Attack_Planeswalker.java svneol=native#text/plain
src/forge/Input_Block.java svneol=native#text/plain src/forge/Input_Block.java svneol=native#text/plain
src/forge/Input_Block_Planeswalker.java svneol=native#text/plain
src/forge/Input_Cleanup.java svneol=native#text/plain src/forge/Input_Cleanup.java svneol=native#text/plain
src/forge/Input_Mulligan.java svneol=native#text/plain src/forge/Input_Mulligan.java svneol=native#text/plain
src/forge/Input_PassPriority.java -text svneol=native#text/plain src/forge/Input_PassPriority.java -text svneol=native#text/plain

View File

@@ -346,9 +346,6 @@ public class AbilityFactory_GainControl {
CardList list = new CardList(AllZone.Combat.getAttackers()); CardList list = new CardList(AllZone.Combat.getAttackers());
if(list.contains(c)) AllZone.Combat.removeFromCombat(c); if(list.contains(c)) AllZone.Combat.removeFromCombat(c);
CardList pwlist = new CardList(AllZone.pwCombat.getAttackers());
if(pwlist.contains(c)) AllZone.pwCombat.removeFromCombat(c);
PlayerZone to = AllZone.getZone(Constant.Zone.Battlefield, c.getOwner()); PlayerZone to = AllZone.getZone(Constant.Zone.Battlefield, c.getOwner());
to.add(c); to.add(c);

View File

@@ -42,7 +42,6 @@ public class AllZone implements NewConstants {
//shared between Input_Attack, Input_Block, Input_CombatDamage , InputState_Computer //shared between Input_Attack, Input_Block, Input_CombatDamage , InputState_Computer
public static Combat Combat = new Combat(); public static Combat Combat = new Combat();
public static Combat pwCombat = new Combat();//for Planeswalker combat
//Human_Play, Computer_Play is different because Card.comesIntoPlay() is called when a card is added by PlayerZone.add(Card) //Human_Play, Computer_Play is different because Card.comesIntoPlay() is called when a card is added by PlayerZone.add(Card)
public final static PlayerZone Human_Battlefield = new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, AllZone.HumanPlayer); public final static PlayerZone Human_Battlefield = new PlayerZone_ComesIntoPlay(Constant.Zone.Battlefield, AllZone.HumanPlayer);

View File

@@ -2710,14 +2710,11 @@ public class Card extends MyObservable {
} }
public boolean isAttacking() { public boolean isAttacking() {
CardList attackers = new CardList(AllZone.Combat.getAttackers()); return AllZone.Combat.isAttacking(this);
attackers.addAll(AllZone.pwCombat.getAttackers());
return attackers.contains(this);
} }
public boolean isBlocking() { public boolean isBlocking() {
CardList blockers = AllZone.Combat.getAllBlockers(); CardList blockers = AllZone.Combat.getAllBlockers();
blockers.add(AllZone.pwCombat.getAllBlockers());
return blockers.contains(this); return blockers.contains(this);
} }

View File

@@ -5802,9 +5802,6 @@ public class CardFactory_Creatures {
CardList list = new CardList(AllZone.Combat.getAttackers()); CardList list = new CardList(AllZone.Combat.getAttackers());
if(list.contains(c)) AllZone.Combat.removeFromCombat(c); if(list.contains(c)) AllZone.Combat.removeFromCombat(c);
CardList pwlist = new CardList(AllZone.pwCombat.getAttackers());
if(pwlist.contains(c)) AllZone.pwCombat.removeFromCombat(c);
PlayerZone to = AllZone.getZone(Constant.Zone.Battlefield, c.getOwner()); PlayerZone to = AllZone.getZone(Constant.Zone.Battlefield, c.getOwner());
to.add(c); to.add(c);

View File

@@ -2902,7 +2902,7 @@ class CardFactory_Planeswalkers {
{ {
public boolean addCard(Card crd) public boolean addCard(Card crd)
{ {
return crd.isCreature() && CombatUtil.canAttack(crd); return CombatUtil.canAttack(crd);
} }
}); });

View File

@@ -13,31 +13,28 @@ public class Combat {
private HashMap<Card, Integer> defendingFirstStrikeDamageMap = new HashMap<Card, Integer>(); private HashMap<Card, Integer> defendingFirstStrikeDamageMap = new HashMap<Card, Integer>();
private HashMap<Card, Integer> defendingDamageMap = new HashMap<Card, Integer>(); private HashMap<Card, Integer> defendingDamageMap = new HashMap<Card, Integer>();
// Defenders are the Defending Player + Each Planeswalker that player controls
private ArrayList<Object> defenders = new ArrayList<Object>();
private int currentDefender = 0;
private int nextDefender = 0;
// This Hash keeps track of
private HashMap<Card, Object> attackerToDefender = new HashMap<Card, Object>();
private int attackingDamage; private int attackingDamage;
// private int defendingDamage;
// private int defendingFirstStrikeDamage; private Player attackingPlayer = null;
// private int trampleDamage; private Player defendingPlayer = null;
// private int trampleFirstStrikeDamage;
private Player attackingPlayer;
private Player defendingPlayer;
private int declaredAttackers;
private Card planeswalker;
private CardList attackersWithLure = new CardList(); private CardList attackersWithLure = new CardList();
private CardList canBlockAttackerWithLure = new CardList(); private CardList canBlockAttackerWithLure = new CardList();
public Combat() { public Combat() {
reset(); // Let the Begin Turn/Untap Phase Reset Combat properly
} }
public void reset() { public void reset() {
planeswalker = null; resetAttackers();
map.clear();
blocked.clear(); blocked.clear();
unblockedMap.clear(); unblockedMap.clear();
@@ -46,24 +43,70 @@ public class Combat {
defendingDamageMap.clear(); defendingDamageMap.clear();
defendingFirstStrikeDamageMap.clear(); defendingFirstStrikeDamageMap.clear();
declaredAttackers = 0;
attackingPlayer = null; attackingPlayer = null;
defendingPlayer = null; defendingPlayer = null;
attackersWithLure = new CardList(); attackersWithLure.clear();
canBlockAttackerWithLure = new CardList(); canBlockAttackerWithLure.clear();
defenders.clear();
currentDefender = 0;
nextDefender = 0;
initiatePossibleDefenders(AllZone.Phase.getPlayerTurn().getOpponent());
} }
public void setPlaneswalker(Card c) { public void initiatePossibleDefenders(Player defender){
planeswalker = c; defenders.add(defender);
CardList planeswalkers = AllZoneUtil.getPlayerCardsInPlay(defender);
planeswalkers = planeswalkers.getType("Planeswalker");
for(Card pw : planeswalkers)
defenders.add(pw);
} }
public Card getPlaneswalker() { public Object nextDefender(){
return planeswalker; if (nextDefender >= defenders.size())
return null;
currentDefender = nextDefender;
nextDefender++;
return defenders.get(currentDefender);
}
public void setCurrentDefender(int def){
currentDefender = def;
}
public int getRemainingDefenders(){
return defenders.size() - nextDefender;
}
public ArrayList<Object> getDefenders(){
return defenders;
}
public void setDefenders(ArrayList<Object> newDef){
defenders = newDef;
}
public Card[] getDefendingPlaneswalkers(){
Card[] pwDefending = new Card[defenders.size()-1];
int i = 0;
for(Object o : defenders){
if (o instanceof Card){
pwDefending[i] = (Card)o;
i++;
}
}
return pwDefending;
} }
public int getDeclaredAttackers() { public int getDeclaredAttackers() {
return declaredAttackers; return attackerToDefender.size();
} }
public void setAttackingPlayer(Player player) { public void setAttackingPlayer(Player player) {
@@ -162,12 +205,9 @@ public class Combat {
damageDealt = att.get(i).getNetDefense(); damageDealt = att.get(i).getNetDefense();
if (damageDealt > 0) { if (damageDealt > 0) {
// if the creature has first strike do not do damage in the // if the creature has first strike do not do damage in the normal combat phase
// normal combat phase
// if(att.get(i).hasSecondStrike())
if (!att.get(i).hasFirstStrike() if (!att.get(i).hasFirstStrike()
|| (att.get(i).hasFirstStrike() && att.get(i) || (att.get(i).hasFirstStrike() && att.get(i).hasDoubleStrike()))
.hasDoubleStrike()))
addDefendingDamage(damageDealt, att.get(i)); addDefendingDamage(damageDealt, att.get(i));
} }
} // ! isBlocked... } // ! isBlocked...
@@ -185,8 +225,7 @@ public class Combat {
damageDealt = att.get(i).getNetDefense(); damageDealt = att.get(i).getNetDefense();
if (damageDealt > 0) { if (damageDealt > 0) {
// if the creature has first strike or double strike do // if the creature has first strike or double strike do damage in the first strike combat phase
// damage in the first strike combat phase
if (att.get(i).hasFirstStrike() if (att.get(i).hasFirstStrike()
|| att.get(i).hasDoubleStrike()) { || att.get(i).hasDoubleStrike()) {
addDefendingFirstStrikeDamage(damageDealt, att.get(i)); addDefendingFirstStrikeDamage(damageDealt, att.get(i));
@@ -197,6 +236,16 @@ public class Combat {
} }
public void addDefendingDamage(int n, Card source) { public void addDefendingDamage(int n, Card source) {
String slot = getDefenderByAttacker(source).toString();
Object o = defenders.get(Integer.parseInt(slot));
if (o instanceof Card){
Card pw = (Card)o;
pw.addAssignedDamage(n, source);
return;
}
if (!defendingDamageMap.containsKey(source)) if (!defendingDamageMap.containsKey(source))
defendingDamageMap.put(source, n); defendingDamageMap.put(source, n);
else { else {
@@ -205,6 +254,16 @@ public class Combat {
} }
public void addDefendingFirstStrikeDamage(int n, Card source) { public void addDefendingFirstStrikeDamage(int n, Card source) {
String slot = getDefenderByAttacker(source).toString();
Object o = defenders.get(Integer.parseInt(slot));
if (o instanceof Card){
Card pw = (Card)o;
pw.addAssignedDamage(n, source);
return;
}
if (!defendingFirstStrikeDamageMap.containsKey(source)) if (!defendingFirstStrikeDamageMap.containsKey(source))
defendingFirstStrikeDamageMap.put(source, n); defendingFirstStrikeDamageMap.put(source, n);
else { else {
@@ -221,19 +280,41 @@ public class Combat {
return attackingDamage; return attackingDamage;
} }
public CardList[] sortAttackerByDefender(){
CardList attackers[] = new CardList[defenders.size()];
for(int i = 0; i < attackers.length; i++)
attackers[i] = new CardList();
for(Card atk : attackerToDefender.keySet()){
Object o = attackerToDefender.get(atk);
int i = Integer.parseInt(o.toString());
attackers[i].add(atk);
}
return attackers;
}
public boolean isAttacking(Card c) {
return map.get(c) != null;
}
public void addAttacker(Card c) { public void addAttacker(Card c) {
map.put(c, new CardList()); map.put(c, new CardList());
declaredAttackers++; attackerToDefender.put(c, currentDefender);
}
public Object getDefenderByAttacker(Card c) {
return attackerToDefender.get(c);
} }
public void resetAttackers() { public void resetAttackers() {
map.clear(); map.clear();
attackerToDefender.clear();
} }
public Card[] getAttackers() { public Card[] getAttackers() {
CardList out = new CardList(); CardList out = new CardList();
Iterator<Card> it = map.keySet().iterator(); Iterator<Card> it = map.keySet().iterator();
// int i = 0; //unused
while (it.hasNext()) { while (it.hasNext()) {
out.add((Card) it.next()); out.add((Card) it.next());
@@ -284,8 +365,10 @@ public class Combat {
public void removeFromCombat(Card c) { public void removeFromCombat(Card c) {
// is card an attacker? // is card an attacker?
CardList att = new CardList(getAttackers()); CardList att = new CardList(getAttackers());
if (att.contains(c)) if (att.contains(c)){
map.remove(c); map.remove(c);
attackerToDefender.remove(c);
}
else// card is a blocker else// card is a blocker
{ {
for (int i = 0; i < att.size(); i++) for (int i = 0; i < att.size(); i++)
@@ -312,8 +395,6 @@ public class Combat {
CardList block; CardList block;
CardList attacking = new CardList(getAttackers()); CardList attacking = new CardList(getAttackers());
for (int i = 0; i < attacking.size(); i++) { for (int i = 0; i < attacking.size(); i++) {
// if(attacking.get(i).hasFirstStrike() ||
// (attacking.get(i).hasDoubleStrike() )){
block = getBlockers(attacking.get(i)); block = getBlockers(attacking.get(i));
// attacker always gets all blockers' attack // attacker always gets all blockers' attack
@@ -327,16 +408,12 @@ public class Combat {
} }
} }
if (block.size() == 0)// this damage is assigned to a player by if (block.size() == 0){
// setPlayerDamage() // this damage is assigned to a player by setPlayerDamage()
{
// GameActionUtil.executePlayerCombatDamageEffects(attacking.get(i));
addUnblockedAttacker(attacking.get(i)); addUnblockedAttacker(attacking.get(i));
} }
else if (attacking.get(i).hasFirstStrike() else if (attacking.get(i).hasFirstStrike() || (attacking.get(i).hasDoubleStrike())) {
|| (attacking.get(i).hasDoubleStrike())) {
if (block.size() == 1) { if (block.size() == 1) {
if (attacking.get(i).hasFirstStrike() if (attacking.get(i).hasFirstStrike()
|| attacking.get(i).hasDoubleStrike()) { || attacking.get(i).hasDoubleStrike()) {
@@ -371,49 +448,20 @@ public class Combat {
addAssignedFirstStrikeDamage(attacking.get(i), block, addAssignedFirstStrikeDamage(attacking.get(i), block,
damageDealt); damageDealt);
} }
} else// human }
{ else{
if (attacking.get(i).hasFirstStrike() // human
|| attacking.get(i).hasDoubleStrike()) { if (attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) {
// GuiDisplay2 gui = (GuiDisplay2) AllZone.Display;
int damageDealt = attacking.get(i).getNetAttack(); int damageDealt = attacking.get(i).getNetAttack();
if (CombatUtil.isDoranInPlay()) if (CombatUtil.isDoranInPlay())
damageDealt = attacking.get(i).getNetDefense(); damageDealt = attacking.get(i).getNetDefense();
AllZone.Display.assignDamage(attacking.get(i), block, AllZone.Display.assignDamage(attacking.get(i), block, damageDealt);
damageDealt);
/*
* for (Card b : block) {
* AllZone.Display.assignDamage(attacking.get(i), b,
* damageDealt);//System.out.println(
* "setAssignedFirstStrikeDmg called for:" + damageDealt
* + " damage."); }
* AllZone.Display.addAssignDamage(attacking
* .get(i),damageDealt);
*/
} }
} }
}// if(hasFirstStrike || doubleStrike) }// if(hasFirstStrike || doubleStrike)
}// for }// for
// should first strike affect the following?
if (getPlaneswalker() != null) {
// System.out.println("defendingDmg (setAssignedFirstStrikeDamage) :"
// +defendingFirstStrikeDamage);
//
Iterator<Card> iter = defendingFirstStrikeDamageMap.keySet()
.iterator();
while (iter.hasNext()) {
Card crd = iter.next();
planeswalker.addAssignedDamage(defendingFirstStrikeDamageMap
.get(crd), crd);
}
defendingFirstStrikeDamageMap.clear();
}
}// setAssignedFirstStrikeDamage() }// setAssignedFirstStrikeDamage()
private void addAssignedFirstStrikeDamage(Card attacker, CardList block, private void addAssignedFirstStrikeDamage(Card attacker, CardList block,
@@ -449,16 +497,9 @@ public class Combat {
CardList block; CardList block;
CardList attacking = new CardList(getAttackers()); CardList attacking = new CardList(getAttackers());
for (int i = 0; i < attacking.size(); i++) { for (int i = 0; i < attacking.size(); i++) {
// if(!attacking.get(i).hasSecondStrike() ){
// if(!attacking.get(i).hasFirstStrike() ||
// (attacking.get(i).hasFirstStrike() &&
// attacking.get(i).hasDoubleStrike() )){
block = getBlockers(attacking.get(i)); block = getBlockers(attacking.get(i));
// attacker always gets all blockers' attack // attacker always gets all blockers' attack
// attacking.get(i).setAssignedDamage(CardListUtil.sumAttack(block));
// AllZone.GameAction.setAssignedDamage(attacking.get(i), block,
// CardListUtil.sumAttack(block));
for (Card b : block) { for (Card b : block) {
if (!b.hasFirstStrike() if (!b.hasFirstStrike()
@@ -470,17 +511,12 @@ public class Combat {
} }
} }
if (block.size() == 0)// this damage is assigned to a player by if (block.size() == 0){
// setPlayerDamage() // this damage is assigned to a player by setPlayerDamage()
{
// GameActionUtil.executePlayerCombatDamageEffects(attacking.get(i));
addUnblockedAttacker(attacking.get(i)); addUnblockedAttacker(attacking.get(i));
} }
else if (!attacking.get(i).hasFirstStrike() else if (!attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) {
|| (attacking.get(i).hasFirstStrike() && attacking.get(i)
.hasDoubleStrike())) {
if (block.size() == 1) { if (block.size() == 1) {
int damageDealt = attacking.get(i).getNetAttack(); int damageDealt = attacking.get(i).getNetAttack();
if (CombatUtil.isDoranInPlay()) if (CombatUtil.isDoranInPlay())
@@ -503,70 +539,22 @@ public class Combat {
damageDealt = attacking.get(i).getNetDefense(); damageDealt = attacking.get(i).getNetDefense();
addAssignedDamage(attacking.get(i), block, damageDealt); addAssignedDamage(attacking.get(i), block, damageDealt);
} else// human attacks }
{ else{ // human attacks
// GuiDisplay2 gui = (GuiDisplay2) AllZone.Display;
int damageDealt = attacking.get(i).getNetAttack(); int damageDealt = attacking.get(i).getNetAttack();
if (CombatUtil.isDoranInPlay()) if (CombatUtil.isDoranInPlay())
damageDealt = attacking.get(i).getNetDefense(); damageDealt = attacking.get(i).getNetDefense();
AllZone.Display.assignDamage(attacking.get(i), block, AllZone.Display.assignDamage(attacking.get(i), block, damageDealt);
damageDealt);
/*
*
*
* for (Card b :block)
* AllZone.Display.addAssignDamage(attacking.get(i), b,
* damageDealt);
* //System.out.println("setAssignedDmg called for:" +
* damageDealt + " damage.");
*/
} }
}// if !hasFirstStrike ... }// if !hasFirstStrike ...
// hacky code, to ensure surviving non-first-strike blockers will
// hit first strike attackers:
/*
* else { block = getBlockers(attacking.get(i));
* //System.out.println("block size: " + block.size()); if(
* (attacking.get(i).hasFirstStrike() ||
* attacking.get(i).hasDoubleStrike()) ) { for(int j=0; j <
* block.size(); j++) { //blockerDamage +=
* block.get(j).getNetAttack(); int damage =
* block.get(j).getNetAttack(); if (CombatUtil.isDoranInPlay())
* damage = block.get(j).getNetDefense();
* AllZone.GameAction.addAssignedDamage(attacking.get(i),
* block.get(j), damage); }
* //attacking.get(i).setAssignedDamage(blockerDamage);
* //AllZone.GameAction.setAssignedDamage(attacking.get(i), block ,
* blockerDamage); } }
*/
}// for }// for
// should first strike affect the following? // should first strike affect the following?
if (getPlaneswalker() != null) {
// System.out.println("defendingDmg (setAssignedDamage): " +
// defendingDamage);
Iterator<Card> iter = defendingDamageMap.keySet().iterator();
while (iter.hasNext()) {
Card crd = iter.next();
planeswalker
.addAssignedDamage(defendingDamageMap.get(crd), crd);
}
defendingDamageMap.clear();
}
}// assignDamage()
/* }// assignDamage()
* private void setAssignedDamage(Card attacker, CardList list, int damage)
* { CardListUtil.sortAttack(list); Card c; for(int i = 0; i < list.size();
* i++) { c = list.get(i); //if(!c.hasFirstStrike() || (c.hasFirstStrike()
* && c.hasDoubleStrike()) ){ if(c.getKillDamage() <= damage) { damage -=
* c.getKillDamage(); CardList cl = new CardList(); cl.add(attacker);
* AllZone.GameAction.addAssignedDamage(c, cl, c.getKillDamage());
* //c.setAssignedDamage(c.getKillDamage()); } //} }//for }//assignDamage()
*/
private void addAssignedDamage(Card attacker, CardList block, int damage) { private void addAssignedDamage(Card attacker, CardList block, int damage) {
Card c = attacker; Card c = attacker;
@@ -617,72 +605,21 @@ public class Combat {
} }
} }
/* // this can be much better below here...
if (bFirstStrike){
CardList pwAttackers = new CardList(AllZone.pwCombat.getAttackers());
CardList pwBlockers = new CardList(AllZone.pwCombat.getAllBlockers().toArray());
for(int i = 0; i < pwAttackers.size(); i++) {
if((pwAttackers.getCard(i).hasFirstStrike() || pwAttackers.getCard(i).hasDoubleStrike())) {
CombatUtil.executeCombatDamageEffects(pwAttackers.getCard(i));
}
}
for(int i = 0; i < pwBlockers.size(); i++) {
if((pwBlockers.getCard(i).hasFirstStrike() || pwBlockers.getCard(i).hasDoubleStrike())) {
CombatUtil.executeCombatDamageEffects(pwBlockers.getCard(i));
}
}
}*/
//get all attackers and blockers
CardList check = new CardList();
check.addAll(AllZone.Human_Battlefield.getCards());
check.addAll(AllZone.Computer_Battlefield.getCards());
CardList all = check.getType("Creature");
if(AllZone.pwCombat.getPlaneswalker() != null) all.add(AllZone.pwCombat.getPlaneswalker());
CardList pwAttackers = new CardList(AllZone.pwCombat.getAttackers());
CardList pwBlockers = new CardList(AllZone.pwCombat.getAllBlockers().toArray());
if (!bFirstStrike){
/*
for(int i = 0; i < pwAttackers.size(); i++) {
//System.out.println("attacker #" + i + ": " + attackers.getCard(i).getName() +" " + attackers.getCard(i).getAttack());
if((!pwAttackers.getCard(i).hasFirstStrike() || (pwAttackers.getCard(i).hasFirstStrike() && pwAttackers.getCard(
i).hasDoubleStrike()))) {
CombatUtil.executeCombatDamageEffects(pwAttackers.getCard(i));
}
}
for(int i = 0; i < pwBlockers.size(); i++) {
if((!pwBlockers.getCard(i).hasFirstStrike() || (pwBlockers.getCard(i).hasFirstStrike() && pwBlockers.getCard(
i).hasDoubleStrike()))) {
CombatUtil.executeCombatDamageEffects(pwBlockers.getCard(i));
}
}
*/
//hacky stuff, hope it won't cause any bugs:
for(int i = 0; i < pwAttackers.size(); i++) {
AllZone.pwCombat.removeFromCombat(pwAttackers.get(i));
}
for(int i = 0; i < pwBlockers.size(); i++) {
AllZone.pwCombat.removeFromCombat(pwBlockers.get(i));
}
}
CardList combatants = new CardList();
combatants.addAll(AllZone.Combat.getAttackers());
combatants.add(AllZone.Combat.getAllBlockers());
combatants.addAll(AllZone.Combat.getDefendingPlaneswalkers());
Card c; Card c;
for(int i = 0; i < all.size(); i++) { for(int i = 0; i < combatants.size(); i++) {
c = all.get(i); c = combatants.get(i);
//because this sets off Jackal Pup, and Filthly Cur damage ability
//and the stack says "Jack Pup causes 0 damage to the Computer" // if no assigned damage to resolve, move to next
if(c.getTotalAssignedDamage() != 0) { if(c.getTotalAssignedDamage() == 0)
continue;
HashMap<Card, Integer> assignedDamageMap = c.getAssignedDamageHashMap(); HashMap<Card, Integer> assignedDamageMap = c.getAssignedDamageHashMap();
HashMap<Card, Integer> damageMap = new HashMap<Card, Integer>(); HashMap<Card, Integer> damageMap = new HashMap<Card, Integer>();
@@ -697,7 +634,6 @@ public class Combat {
c.clearAssignedDamage(); c.clearAssignedDamage();
} }
} }
}
public Card[] getUnblockedAttackers() { public Card[] getUnblockedAttackers() {

View File

@@ -350,6 +350,7 @@ public class CombatUtil {
//can a creature attack att all? //can a creature attack att all?
public static boolean canAttack(Card c) { public static boolean canAttack(Card c) {
if (!c.isCreature()) return false;
if(AllZoneUtil.isCardInPlay("Peacekeeper")) return false; if(AllZoneUtil.isCardInPlay("Peacekeeper")) return false;
@@ -412,7 +413,7 @@ public class CombatUtil {
if(allislands.size() < 5) return false; if(allislands.size() < 5) return false;
} }
if(c.isTapped() || c.hasSickness() if(c.isTapped() || c.isSick()
|| AllZoneUtil.isCardInPlay("Blazing Archon", c.getController().getOpponent()) || AllZoneUtil.isCardInPlay("Blazing Archon", c.getController().getOpponent())
|| c.getKeyword().contains("CARDNAME can't attack.") || c.getKeyword().contains("CARDNAME can't attack.")
|| c.getKeyword().contains("CARDNAME can't attack or block.") || c.getKeyword().contains("CARDNAME can't attack or block.")
@@ -459,7 +460,7 @@ public class CombatUtil {
return false; return false;
} }
} }
//if Card has Haste, Card.hasSickness() will return false
return true; return true;
}//canAttack() }//canAttack()
@@ -522,10 +523,12 @@ public class CombatUtil {
//Checks if the life of the attacked Player/Planeswalker is in danger //Checks if the life of the attacked Player/Planeswalker is in danger
public static boolean lifeInDanger(Combat combat) { public static boolean lifeInDanger(Combat combat) {
// life in danger only cares about the player's life. Not about a Planeswalkers life
int damage = 0; int damage = 0;
int poison = 0; int poison = 0;
CardList attackers = new CardList(combat.getAttackers());
CardList attackers = combat.sortAttackerByDefender()[0];
CardList unblocked = new CardList(); CardList unblocked = new CardList();
CardList blockers = new CardList(); CardList blockers = new CardList();
Card attacker = new Card(); Card attacker = new Card();
@@ -549,14 +552,7 @@ public class CombatUtil {
damage += sumAttack(unblocked, AllZone.ComputerPlayer); damage += sumAttack(unblocked, AllZone.ComputerPlayer);
poison += sumPoison(unblocked, AllZone.ComputerPlayer); poison += sumPoison(unblocked, AllZone.ComputerPlayer);
if (combat.getPlaneswalker() == null) { return (damage + 3 > AllZone.ComputerPlayer.getLife() || poison + 2 > 10 - AllZone.ComputerPlayer.getPoisonCounters());
if (damage + 3 > AllZone.ComputerPlayer.getLife() || poison + 2 > 10 - AllZone.ComputerPlayer.getPoisonCounters())
return true;
} else {
if (damage + 1 > combat.getPlaneswalker().getCounters(Counters.LOYALTY))
return true;
}
return false;
} }
// This calculates the amount of damage a blockgang can deal to the attacker (first strike not supported) // This calculates the amount of damage a blockgang can deal to the attacker (first strike not supported)
@@ -816,104 +812,59 @@ public class CombatUtil {
} }
public static void showCombat() { public static void showCombat() {
//clear
AllZone.Display.showCombat(""); AllZone.Display.showCombat("");
Card attack[] = AllZone.Combat.getAttackers(); Card attack[] = AllZone.Combat.getAttackers();
Card defend[] = null; Card defend[] = null;
StringBuilder display = new StringBuilder(); StringBuilder display = new StringBuilder();
String attackerName = "";
String blockerName = "";
// Loop through Defenders
// Append Defending Player/Planeswalker
ArrayList<Object> defenders = AllZone.Combat.getDefenders();
CardList attackers[] = AllZone.Combat.sortAttackerByDefender();
// Not a big fan of the triple nested loop here
for(int def = 0; def < defenders.size(); def++){
if (attackers[def] == null || attackers[def].size() == 0)
continue;
if (def > 0)
display.append("\n");
display.append("Defender - ");
display.append(defenders.get(def).toString());
display.append("\n");
int len = attackers[def].size();
//loop through attackers //loop through attackers
for(int i = 0; i < attack.length; i++) { for(int i = 0; i < len; i++) {
//GameActionUtil.executeExaltedEffects2(attack[i], AllZone.Combat); display.append("-> ");
//checkDeclareAttackers(attack[i]); display.append(combatantToString(attack[i])).append("\n");
attackerName = attack[i].getName();
if(attack[i].isFaceDown()) attackerName = "Morph";
display.append(attackerName);
display.append(" (");
display.append(attack[i].getUniqueNumber());
display.append(") ");
display.append(attack[i].getNetAttack());
display.append("/");
display.append(attack[i].getNetDefense());
display.append(" is attacking \n");
defend = AllZone.Combat.getBlockers(attack[i]).toArray(); defend = AllZone.Combat.getBlockers(attack[i]).toArray();
//loop through blockers //loop through blockers
for(int inner = 0; inner < defend.length; inner++) { for(int inner = 0; inner < defend.length; inner++) {
//checkDeclareBlockers(defend[inner]); display.append("---< ");
blockerName = defend[inner].getName(); display.append(combatantToString(defend[inner])).append("\n");
if(defend[inner].isFaceDown()) blockerName = "Morph";
display.append(" ");
display.append(blockerName);
display.append(" (");
display.append(defend[inner].getUniqueNumber());
display.append(") ");
display.append(defend[inner].getNetAttack());
display.append("/");
display.append(defend[inner].getNetDefense());
display.append(" is blocking \n");
} }
}//while - loop through attackers }//loop through attackers
String s = display.toString() + getPlaneswalkerBlockers(); }
AllZone.Display.showCombat(s.trim()); AllZone.Display.showCombat(display.toString().trim());
}//showBlockers() }//showBlockers()
private static String getPlaneswalkerBlockers() { private static String combatantToString(Card c){
Card attack[] = AllZone.pwCombat.getAttackers(); StringBuilder sb = new StringBuilder();
Card defend[] = null;
StringBuilder display = new StringBuilder();
if(attack.length != 0) display.append("Planeswalker Combat\r\n"); String name = (c.isFaceDown()) ? "Morph" : c.getName();
String attackerName = ""; sb.append(name);
String blockerName = ""; sb.append(" (").append(c.getUniqueNumber()).append(") ");
//loop through attackers sb.append(c.getNetAttack()).append("/").append(c.getNetDefense());
for(int i = 0; i < attack.length; i++) {
//GameActionUtil.executeExaltedEffects2(attack[i], AllZone.pwCombat);
//checkDeclareAttackers(attack[i]); return sb.toString();
attackerName = attack[i].getName();
if(attack[i].isFaceDown()) attackerName = "Morph";
display.append(attackerName);
display.append(" (");
display.append(attack[i].getUniqueNumber());
display.append(") ");
display.append(attack[i].getNetAttack());
display.append("/");
display.append(attack[i].getNetDefense());
display.append(" is attacking \n");
defend = AllZone.pwCombat.getBlockers(attack[i]).toArray();
//loop through blockers
for(int inner = 0; inner < defend.length; inner++) {
//checkDeclareBlockers(defend[inner]);
blockerName = defend[inner].getName();
if(defend[inner].isFaceDown()) blockerName = "Morph";
display.append(" ");
display.append(blockerName);
display.append(" (");
display.append(defend[inner].getUniqueNumber());
display.append(") ");
display.append(defend[inner].getNetAttack());
display.append("/");
display.append(defend[inner].getNetDefense());
display.append(" is blocking \n");
} }
}//while - loop through attackers
return display.toString();
}//getPlaneswalkerBlockers()
public static boolean isDoranInPlay() { public static boolean isDoranInPlay() {
return AllZoneUtil.isCardInPlay("Doran, the Siege Tower"); return AllZoneUtil.isCardInPlay("Doran, the Siege Tower");
@@ -921,14 +872,19 @@ public class CombatUtil {
public static boolean checkPropagandaEffects(Card c) { public static boolean checkPropagandaEffects(Card c) {
String cost = CardFactoryUtil.getPropagandaCost(c); String cost = CardFactoryUtil.getPropagandaCost(c);
if(cost.equals("0")) if(cost.equals("0")){
if(!c.getKeyword().contains("Vigilance"))
c.tap();
return true; return true;
}
final Card crd = c; final Card crd = c;
final boolean[] canAttack = new boolean[1]; final boolean[] canAttack = new boolean[1];
canAttack[0] = false; canAttack[0] = false;
if( AllZone.Phase.getPhase().equals(Constant.Phase.Combat_Declare_Attackers)) { String phase = AllZone.Phase.getPhase();
if(phase.equals(Constant.Phase.Combat_Declare_Attackers) || phase.equals(Constant.Phase.Combat_Declare_Attackers)) {
if(!cost.equals("0")) { if(!cost.equals("0")) {
final Ability ability = new Ability(c, cost) { final Ability ability = new Ability(c, cost) {
@Override @Override
@@ -943,8 +899,8 @@ public class CombatUtil {
public void execute() { public void execute() {
canAttack[0] = false; canAttack[0] = false;
// TODO: remove the below line after Propaganda occurs during Declare_Attackers
AllZone.Combat.removeFromCombat(crd); AllZone.Combat.removeFromCombat(crd);
crd.untap();
} }
}; };
@@ -952,6 +908,9 @@ public class CombatUtil {
private static final long serialVersionUID = -8303368287601871955L; private static final long serialVersionUID = -8303368287601871955L;
public void execute() { public void execute() {
// if Propaganda is paid, tap this card
if(!crd.getKeyword().contains("Vigilance"))
crd.tap();
canAttack[0] = true; canAttack[0] = true;
} }
}; };
@@ -959,13 +918,18 @@ public class CombatUtil {
if(c.getController().isHuman()) { if(c.getController().isHuman()) {
AllZone.InputControl.setInput(new Input_PayManaCost_Ability(c + " - Pay to Attack\r\n", AllZone.InputControl.setInput(new Input_PayManaCost_Ability(c + " - Pay to Attack\r\n",
ability.getManaCost(), paidCommand, unpaidCommand)); ability.getManaCost(), paidCommand, unpaidCommand));
} else //computer }
{ else{ //computer
if(ComputerUtil.canPayCost(ability)) ComputerUtil.playNoStack(ability); if(ComputerUtil.canPayCost(ability)){
ComputerUtil.playNoStack(ability);
if(!crd.getKeyword().contains("Vigilance"))
crd.tap();
}
else { else {
canAttack[0] = false; canAttack[0] = false;
// TODO: remove the below two lines after Propaganda occurs during Declare_Attackers
AllZone.Combat.removeFromCombat(crd); AllZone.Combat.removeFromCombat(crd);
crd.untap(); //crd.untap();
} }
} }
} }
@@ -1105,7 +1069,7 @@ public class CombatUtil {
} }
}//Raging Ravine }//Raging Ravine
if ((AllZone.Combat.getAttackers().length + AllZone.pwCombat.getAttackers().length) == 1) if (AllZone.Combat.getAttackers().length == 1)
{ {
if (c.getKeyword().contains("Whenever this creature attacks alone, it gets +2/+0 until end of turn.") || if (c.getKeyword().contains("Whenever this creature attacks alone, it gets +2/+0 until end of turn.") ||
c.getKeyword().contains("Whenever CARDNAME attacks alone, it gets +2/+0 until end of turn.")) c.getKeyword().contains("Whenever CARDNAME attacks alone, it gets +2/+0 until end of turn."))
@@ -1568,13 +1532,9 @@ public class CombatUtil {
public void resolve() { public void resolve() {
CardList list = new CardList(); CardList list = new CardList();
list.addAll(AllZone.Combat.getAttackers()); list.addAll(AllZone.Combat.getAttackers());
list.addAll(AllZone.pwCombat.getAttackers()); list = list.getType("Goblin");
list = list.filter(new CardListFilter() { list.remove(piledriver);
public boolean addCard(Card card) {
return (!card.equals(piledriver) && card.isCreature() && (card.getType().contains(
"Goblin") || card.getKeyword().contains("Changeling")));
}
});
final int otherGoblins = list.size(); final int otherGoblins = list.size();
final Command untilEOT = new Command() { final Command untilEOT = new Command() {

View File

@@ -183,25 +183,17 @@ public class ComputerAI_General implements Computer {
} }
public void declare_attackers() { public void declare_attackers() {
final Combat c = ComputerUtil.getAttackers(); // 12/2/10(sol) the decision making here has moved to getAttackers()
c.setAttackingPlayer(AllZone.Combat.getAttackingPlayer());
c.setDefendingPlayer(AllZone.Combat.getDefendingPlayer());
//check for planeswalker AllZone.Combat = ComputerUtil.getAttackers();
Card walker = AllZone.HumanPlayer.getPlaneswalker();
if(walker != null && MyRandom.random.nextBoolean()) { Card[] att = AllZone.Combat.getAttackers();
c.setPlaneswalker(walker);
AllZone.pwCombat = c;
} else AllZone.Combat = c;
Card[] att = c.getAttackers();
if (att.length > 0) if (att.length > 0)
AllZone.Phase.setCombat(true); AllZone.Phase.setCombat(true);
for(int i = 0; i < att.length; i++) { for(int i = 0; i < att.length; i++) {
if(!att[i].getKeyword().contains("Vigilance")) att[i].tap(); // tapping of attackers happens after Propaganda is paid for
//if(!att[i].getKeyword().contains("Vigilance")) att[i].tap();
Log.debug("Computer just assigned " + att[i].getName() + " as an attacker."); Log.debug("Computer just assigned " + att[i].getName() + " as an attacker.");
} }
@@ -219,23 +211,7 @@ public class ComputerAI_General implements Computer {
public void declare_blockers() { public void declare_blockers() {
CardList blockers = AllZoneUtil.getCreaturesInPlay(AllZone.ComputerPlayer); CardList blockers = AllZoneUtil.getCreaturesInPlay(AllZone.ComputerPlayer);
//If Player life is in danger protect it first
if(CombatUtil.lifeInDanger(AllZone.Combat)) {
AllZone.Combat = ComputerUtil_Block2.getBlockers(AllZone.Combat, blockers); AllZone.Combat = ComputerUtil_Block2.getBlockers(AllZone.Combat, blockers);
CardList remove = AllZone.Combat.getAllBlockers();
for(int i = 0; i < remove.size(); i++)
blockers.remove(remove.get(i));
AllZone.pwCombat = ComputerUtil_Block2.getBlockers(AllZone.pwCombat, blockers);
} else { // Otherwise protect Planeswalkers first
AllZone.pwCombat = ComputerUtil_Block2.getBlockers(AllZone.pwCombat, blockers);
CardList remove = AllZone.pwCombat.getAllBlockers();
for(int i = 0; i < remove.size(); i++)
blockers.remove(remove.get(i));
AllZone.Combat = ComputerUtil_Block2.getBlockers(AllZone.Combat, blockers);
}
CombatUtil.showCombat(); CombatUtil.showCombat();
@@ -246,26 +222,6 @@ public class ComputerAI_General implements Computer {
stackResponse(); stackResponse();
} }
/*
private Combat getCombat(Card[] attackers, CardList availableBlockers) {
ComputerUtil_Block2 com = new ComputerUtil_Block2(attackers, availableBlockers.toArray(),
AllZone.ComputerPlayer.getLife());
Combat c = com.getBlockers();
c.setAttackingPlayer(AllZone.Combat.getAttackingPlayer());
c.setDefendingPlayer(AllZone.Combat.getDefendingPlayer());
CardList attacks = new CardList(attackers);
Combat c = ComputerUtil_Block2.getBlockers(attacks,availableBlockers);
return c;
}
*/
public void end_of_combat(){ public void end_of_combat(){
stackResponse(); stackResponse();
} }

View File

@@ -743,7 +743,7 @@ public class ComputerUtil
list = list.filter(new CardListFilter() list = list.filter(new CardListFilter()
{ {
public boolean addCard(Card c) { public boolean addCard(Card c) {
return c.isCreature() && CombatUtil.canAttack(c); return CombatUtil.canAttack(c);
} }
}); });
return list; return list;

View File

@@ -32,6 +32,7 @@ public class ComputerUtil_Attack2 {
blockers = getPossibleBlockers(possibleBlockers); blockers = getPossibleBlockers(possibleBlockers);
this.blockerLife = blockerLife; this.blockerLife = blockerLife;
// todo: get rid of valuable
final ArrayList<String> valuable = new ArrayList<String>(); final ArrayList<String> valuable = new ArrayList<String>();
valuable.add("Kamahl, Pit Fighter"); valuable.add("Kamahl, Pit Fighter");
valuable.add("Elvish Piper"); valuable.add("Elvish Piper");
@@ -50,7 +51,7 @@ public class ComputerUtil_Attack2 {
CardList list = new CardList(in.toArray()); CardList list = new CardList(in.toArray());
list = list.filter(new CardListFilter() list = list.filter(new CardListFilter()
{ {
public boolean addCard(Card c) { return c.isCreature() && CombatUtil.canAttack(c); } public boolean addCard(Card c) { return CombatUtil.canAttack(c); }
}); });
return list; return list;
}//getUntappedCreatures() }//getUntappedCreatures()
@@ -159,6 +160,24 @@ public class ComputerUtil_Attack2 {
return blockerLife <= totalAttack; return blockerLife <= totalAttack;
}//doAssault() }//doAssault()
public void chooseDefender(Combat c, boolean bAssault){
// TODO: split attackers to different planeswalker/human
// AI will only attack one Defender per combat for now
ArrayList<Object> defs = c.getDefenders();
if (defs.size() == 1 || bAssault){
c.setCurrentDefender(0);
return;
}
// Randomnly determine who EVERYONE is attacking
// would be better to determine more individually
int n = MyRandom.random.nextInt(defs.size());
c.setCurrentDefender(n);
return;
}
public Combat getAttackers() public Combat getAttackers()
{ {
//if this method is called multiple times during a turn, //if this method is called multiple times during a turn,
@@ -169,11 +188,19 @@ public class ComputerUtil_Attack2 {
random.setSeed(AllZone.Phase.getTurn() + randomInt); random.setSeed(AllZone.Phase.getTurn() + randomInt);
Combat combat = new Combat(); Combat combat = new Combat();
combat.setAttackingPlayer(AllZone.Combat.getAttackingPlayer());
combat.setDefendingPlayer(AllZone.Combat.getDefendingPlayer());
combat.setDefenders(AllZone.Combat.getDefenders());
boolean bAssault = doAssault();
// Determine who will be attacked
chooseDefender(combat, bAssault);
CardList attackersLeft = new CardList(attackers.toArray()); CardList attackersLeft = new CardList(attackers.toArray());
//Atackers that don't really have a choice //Atackers that don't really have a choice
for (int i=0; i<attackersLeft.size();i++) for (int i=0; i < attackersLeft.size(); i++)
{ {
Card attacker = attackersLeft.get(i); Card attacker = attackersLeft.get(i);
if ( (attacker.getKeyword().contains("CARDNAME attacks each turn if able.") if ( (attacker.getKeyword().contains("CARDNAME attacks each turn if able.")
@@ -192,8 +219,9 @@ public class ComputerUtil_Attack2 {
if (combat.getAttackers().length == 0 && (countExaltedBonus(AllZone.ComputerPlayer) >= 3 || if (combat.getAttackers().length == 0 && (countExaltedBonus(AllZone.ComputerPlayer) >= 3 ||
AllZoneUtil.isCardInPlay("Rafiq of the Many", AllZone.ComputerPlayer) || AllZoneUtil.isCardInPlay("Rafiq of the Many", AllZone.ComputerPlayer) ||
AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Battlegrace Angel").size() >= 2 || AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Battlegrace Angel").size() >= 2 ||
(AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Finest Hour").size()>=1) && AllZone.Phase.isFirstCombat()) (AllZoneUtil.getPlayerCardsInPlay(AllZone.ComputerPlayer, "Finest Hour").size()>=1) &&
&& !doAssault()) AllZone.Phase.isFirstCombat())
&& !bAssault)
{ {
int biggest = 0; int biggest = 0;
Card att = null; Card att = null;
@@ -209,7 +237,7 @@ public class ComputerUtil_Attack2 {
//do assault (all creatures attack) if the computer would win the game //do assault (all creatures attack) if the computer would win the game
//or if the computer has 4 creatures and the player has 1 //or if the computer has 4 creatures and the player has 1
else if(doAssault() || (humanList.size() == 1 && 3 < attackers.size())) else if(bAssault || (humanList.size() == 1 && 3 < attackers.size()))
{ {
CardListUtil.sortAttack(attackersLeft); CardListUtil.sortAttack(attackersLeft);
for(int i = 0; i < attackersLeft.size(); i++) for(int i = 0; i < attackersLeft.size(); i++)
@@ -254,32 +282,11 @@ public class ComputerUtil_Attack2 {
} }
}//getAttackers() }//getAttackers()
return combat; return combat;
}//getAttackers() }//getAttackers()
/*
//returns null if no blockers found
public Card getBiggestAttack(Card attack)
{
CardListUtil.sortAttack(blockers);
for(int i = 0; i < blockers.size(); i++)
if(CombatUtil.canBlock(attack, blockers.get(i)))
return blockers.get(i);
return null;
}
//returns null if no blockers found
public Card getBiggestDefense(Card attack)
{
CardListUtil.sortDefense(blockers);
for(int i = 0; i < blockers.size(); i++)
if(CombatUtil.canBlock(attack, blockers.get(i)))
return blockers.get(i);
return null;
}*/
public int countExaltedBonus(Player player) public int countExaltedBonus(Player player)
{ {
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, player); PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, player);
@@ -349,8 +356,6 @@ public class ComputerUtil_Attack2 {
else if(CombatUtil.canBlock(c)) plannedBlockers.add(c); else if(CombatUtil.canBlock(c)) plannedBlockers.add(c);
} }
return combat; return combat;
} }
} }

View File

@@ -1,6 +1,8 @@
package forge; package forge;
import java.util.ArrayList;
public class ComputerUtil_Block2 public class ComputerUtil_Block2
{ {
@@ -508,11 +510,46 @@ public class ComputerUtil_Block2
return blockers; return blockers;
} }
public static CardList sortPotentialAttackers(Combat combat){
CardList[] attackerLists = combat.sortAttackerByDefender();
CardList sortedAttackers = new CardList();
ArrayList<Object> defenders = combat.getDefenders();
// If I don't have any planeswalkers than sorting doesn't really matter
if (defenders.size() == 1)
return attackerLists[0];
boolean bLifeInDanger = CombatUtil.lifeInDanger(combat);
// todo: Add creatures attacking Planeswalkers in order of which we want to protect
// defend planeswalkers with more loyalty before planeswalkers with less loyalty
// if planeswalker will be too difficult to defend don't even bother
for(int i = 1; i < attackerLists.length; i++){
for(Card c : attackerLists[i])
sortedAttackers.add(c);
}
if(bLifeInDanger) {
// add creatures attacking the Player to the front of the list
for(Card c : attackerLists[0])
sortedAttackers.add(0, c);
}
else{
// add creatures attacking the Player to the back of the list
for(Card c : attackerLists[0])
sortedAttackers.add(c);
}
return sortedAttackers;
}
public static Combat getBlockers(Combat originalCombat, CardList possibleBlockers) { public static Combat getBlockers(Combat originalCombat, CardList possibleBlockers) {
Combat combat = originalCombat; Combat combat = originalCombat;
CardList attackers = new CardList(combat.getAttackers()); CardList attackers = sortPotentialAttackers(combat);
if (attackers.size() == 0) if (attackers.size() == 0)
return combat; return combat;
@@ -564,8 +601,10 @@ public class ComputerUtil_Block2
if(!CombatUtil.canBlock(b, combat)) blockersLeft.remove(b); if(!CombatUtil.canBlock(b, combat)) blockersLeft.remove(b);
} }
boolean bLifeInDanger = CombatUtil.lifeInDanger(combat);
//These creatures won't prevent any damage //These creatures won't prevent any damage
if (CombatUtil.lifeInDanger(combat)) if (bLifeInDanger)
blockersLeft = blockersLeft.getNotKeyword("Whenever CARDNAME is dealt damage, you lose that much life."); blockersLeft = blockersLeft.getNotKeyword("Whenever CARDNAME is dealt damage, you lose that much life.");
if (blockersLeft.size() == 0) if (blockersLeft.size() == 0)
@@ -624,7 +663,7 @@ public class ComputerUtil_Block2
if(blockersLeft.size() == 0) return combat; if(blockersLeft.size() == 0) return combat;
//choose necessary trade blocks if life is in danger //choose necessary trade blocks if life is in danger
if (CombatUtil.lifeInDanger(combat)) if (bLifeInDanger)
for(int i = 0; i < attackersLeft.size(); i++) { for(int i = 0; i < attackersLeft.size(); i++) {
attacker = attackersLeft.get(i); attacker = attackersLeft.get(i);
killingBlockers = killingBlockers =
@@ -640,7 +679,7 @@ public class ComputerUtil_Block2
attackersLeft = new CardList(currentAttackers.toArray()); attackersLeft = new CardList(currentAttackers.toArray());
//choose necessary chump blocks if life is still in danger //choose necessary chump blocks if life is still in danger
if (CombatUtil.lifeInDanger(combat)) if (bLifeInDanger)
for(int i = 0; i < attackersLeft.size(); i++) { for(int i = 0; i < attackersLeft.size(); i++) {
attacker = attackersLeft.get(i); attacker = attackersLeft.get(i);
chumpBlockers = getPossibleBlockers(attacker, blockersLeft, combat); chumpBlockers = getPossibleBlockers(attacker, blockersLeft, combat);
@@ -656,7 +695,7 @@ public class ComputerUtil_Block2
attackersLeft = new CardList(currentAttackers.toArray()); attackersLeft = new CardList(currentAttackers.toArray());
//Reinforce blockers blocking attackers with trample if life is still in danger //Reinforce blockers blocking attackers with trample if life is still in danger
if (CombatUtil.lifeInDanger(combat)) { if (bLifeInDanger) {
tramplingAttackers = attackers.getKeyword("Trample"); tramplingAttackers = attackers.getKeyword("Trample");
tramplingAttackers = tramplingAttackers.getKeywordsDontContain("Rampage"); //Don't make it worse tramplingAttackers = tramplingAttackers.getKeywordsDontContain("Rampage"); //Don't make it worse
tramplingAttackers = tramplingAttackers. tramplingAttackers = tramplingAttackers.

View File

@@ -98,6 +98,7 @@ public class InputControl extends MyObservable implements java.io.Serializable {
// Special Inputs needed for the following phases: // Special Inputs needed for the following phases:
if(phase.equals(Constant.Phase.Combat_Declare_Attackers)) { if(phase.equals(Constant.Phase.Combat_Declare_Attackers)) {
AllZone.Stack.freezeStack(); AllZone.Stack.freezeStack();
if (playerTurn.isHuman()) if (playerTurn.isHuman())
return new Input_Attack(); return new Input_Attack();
} }
@@ -109,11 +110,7 @@ public class InputControl extends MyObservable implements java.io.Serializable {
return null; return null;
} }
else{ else{
// test this. probably should just call Input_Block and let block pass along?
if(AllZone.Combat.getAttackers().length == 0){ if(AllZone.Combat.getAttackers().length == 0){
if (AllZone.pwCombat.getAttackers().length != 0)
return new Input_Block_Planeswalker();
// no active attackers, skip the Blocking phase // no active attackers, skip the Blocking phase
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
return null; return null;

View File

@@ -7,20 +7,31 @@ public class Input_Attack extends Input {
@Override @Override
public void showMessage() { public void showMessage() {
// TODO: still seems to have some issues with multiple planeswalkers
ButtonUtil.enableOnlyOK(); ButtonUtil.enableOnlyOK();
AllZone.Display.showMessage("Declare Attackers: Select creatures that you want to attack with");
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, AllZone.HumanPlayer); Object o = AllZone.Combat.nextDefender();
CardList creats = new CardList(play.getCards()); if (o == null){
creats = creats.getType("Creature"); return;
}
if(getPlaneswalker() == null) { StringBuilder sb = new StringBuilder();
for(int i = 0; i < creats.size(); i++) { sb.append("Declare Attackers: Select Creatures to Attack ");
Card c = creats.get(i); sb.append(o.toString());
if(CombatUtil.canAttack(c) && c.getKeyword().contains("CARDNAME attacks each turn if able.")) {
AllZone.Display.showMessage(sb.toString());
if(AllZone.Combat.getRemainingDefenders() == 0) {
// Nothing left to attack, has to attack this defender
CardList possibleAttackers = AllZoneUtil.getPlayerCardsInPlay(AllZone.HumanPlayer);
possibleAttackers = possibleAttackers.getType("Creature");
for(int i = 0; i < possibleAttackers.size(); i++) {
Card c = possibleAttackers.get(i);
if(c.getKeyword().contains("CARDNAME attacks each turn if able.") && CombatUtil.canAttack(c) && !c.isAttacking()) {
AllZone.Combat.addAttacker(c); AllZone.Combat.addAttacker(c);
if(!c.getKeyword().contains("Vigilance")) c.tap(); //if(!c.getKeyword().contains("Vigilance"))
// c.tap();
} }
} }
} }
@@ -31,37 +42,23 @@ public class Input_Attack extends Input {
if (AllZone.Combat.getAttackers().length > 0) if (AllZone.Combat.getAttackers().length > 0)
AllZone.Phase.setCombat(true); AllZone.Phase.setCombat(true);
Card check = getPlaneswalker(); if (AllZone.Combat.getRemainingDefenders() != 0)
if(check == null) { AllZone.Phase.repeatPhase();
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
} else { AllZone.InputControl.resetInput();
AllZone.pwCombat.setPlaneswalker(check);
AllZone.InputControl.setInput(new Input_Attack_Planeswalker());
}
}
//return Computer's planeswalker if there is one
//just returns 1, does not return multiple planeswalkers
private Card getPlaneswalker() {
CardList c = new CardList(AllZone.Computer_Battlefield.getCards());
c = c.getType("Planeswalker");
if(c.isEmpty()) return null;
return c.get(0);
} }
@Override @Override
public void selectCard(Card card, PlayerZone zone) { public void selectCard(Card card, PlayerZone zone) {
if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && card.isCreature() && card.isUntapped() if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && CombatUtil.canAttack(card) && !card.isAttacking()) {
&& CombatUtil.canAttack(card)) {
// todo add the propaganda code here and remove it in Phase.nextPhase()
// if (!CombatUtil.checkPropagandaEffects(card))
// return;
if(!card.getKeyword().contains("Vigilance")) {
card.tap();
//otherwise cards stay untapped, not sure why this is needed but it works
AllZone.Human_Battlefield.updateObservers();
}
AllZone.Combat.addAttacker(card); AllZone.Combat.addAttacker(card);
AllZone.Human_Battlefield.updateObservers(); // just to make sure the attack symbol is marked
//for Castle Raptors, since it gets a bonus if untapped //for Castle Raptors, since it gets a bonus if untapped
for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) { for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) {

View File

@@ -1,60 +0,0 @@
package forge;
public class Input_Attack_Planeswalker extends Input {
private static final long serialVersionUID = 5738375759147611797L;
@Override
public void showMessage() {
ButtonUtil.enableOnlyOK();
AllZone.Display.showMessage("Planeswalker Declare Attackers:\r\nSelect creatures that you want to attack "
+ AllZone.pwCombat.getPlaneswalker());
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, AllZone.HumanPlayer);
CardList creats = new CardList(play.getCards());
creats = creats.getType("Creature");
CardList attackers = new CardList(AllZone.Combat.getAttackers());
for(int i = 0; i < creats.size(); i++) {
Card c = creats.get(i);
if(CombatUtil.canAttack(c) && c.getKeyword().contains("CARDNAME attacks each turn if able.")
&& !attackers.contains(c)) {
AllZone.pwCombat.addAttacker(c);
if(!c.getKeyword().contains("Vigilance")) c.tap();
}
}
}
@Override
public void selectButtonOK() {
if (AllZone.pwCombat.getAttackers().length > 0)
AllZone.Phase.setCombat(true);
AllZone.Phase.setNeedToNextPhase(true);
this.stop();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && card.isCreature() && card.isUntapped()
&& 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_Battlefield.updateObservers();
}
AllZone.pwCombat.addAttacker(card);
//for Castle Raptors, since it gets a bonus if untapped
for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) {
Command com = GameActionUtil.commands.get(effect);
com.execute();
}
GameActionUtil.executeCardStateEffects();
CombatUtil.showCombat();
}
}//selectCard()
}

View File

@@ -52,15 +52,10 @@ public class Input_Block extends Input {
@Override @Override
public void selectButtonOK() { public void selectButtonOK() {
// Done blocking
ButtonUtil.reset(); ButtonUtil.reset();
if(AllZone.pwCombat.getAttackers().length == 0) {
//AllZone.Phase.nextPhase();
//for debugging: System.out.println("need to nextPhase(Input_Cleanup.showMessage(), n<=7) = true");
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
} else {
AllZone.InputControl.setInput(new Input_Block_Planeswalker());
}
} }
@Override @Override

View File

@@ -1,78 +0,0 @@
package forge;
import java.util.ArrayList;
public class Input_Block_Planeswalker extends Input {
private static final long serialVersionUID = 8504632360578751473L;
private Card currentAttacker = null;
private ArrayList<Card> allBlocking = new ArrayList<Card>();
@Override
public void showMessage() {
//for Castle Raptors, since it gets a bonus if untapped
for(String effect:AllZone.StaticEffects.getStateBasedMap().keySet()) {
Command com = GameActionUtil.commands.get(effect);
com.execute();
}
GameActionUtil.executeCardStateEffects();
//could add "Reset Blockers" button
ButtonUtil.enableOnlyOK();
if(currentAttacker == null) {
//Lure
CardList attackers = new CardList(AllZone.Combat.getAttackers());
for(Card attacker:attackers) {
if(attacker.hasKeyword("All creatures able to block CARDNAME do so.")) {
CardList bls = AllZoneUtil.getCreaturesInPlay(AllZone.HumanPlayer);
for(Card bl:bls) {
if(CombatUtil.canBlock(attacker, bl, AllZone.Combat)) {
allBlocking.add(bl);
AllZone.Combat.addBlocker(attacker, bl);
}
}
}
}
AllZone.Display.showMessage("Planeswalker Combat\r\nTo Block, click on your Opponents attacker first , then your blocker(s)");
}
else {
String attackerName = currentAttacker.isFaceDown() ? "Morph" : currentAttacker.getName();
AllZone.Display.showMessage("Select a creature to block " + attackerName + " ("
+ currentAttacker.getUniqueNumber() + ") ");
}
CombatUtil.showCombat();
}
@Override
public void selectButtonOK() {
if (AllZone.Combat.getAttackers().length > 0)
AllZone.Phase.setCombat(true);
ButtonUtil.reset();
//AllZone.Phase.nextPhase();
//for debugging: System.out.println("need to nextPhase(Input_Block_Planeswalker.selectButtonOK) = true; Note, this has not been tested, did it work?");
AllZone.Phase.setNeedToNextPhase(true);
this.stop();
}
@Override
public void selectCard(Card card, PlayerZone zone) {
//is attacking?
if(CardUtil.toList(AllZone.pwCombat.getAttackers()).contains(card)) {
currentAttacker = card;
} else if(zone.is(Constant.Zone.Battlefield, AllZone.HumanPlayer) && card.isCreature()
&& CombatUtil.canBlock(currentAttacker, card, AllZone.Combat)) {
if(currentAttacker != null && (!allBlocking.contains(card))) {
allBlocking.add(card);
AllZone.pwCombat.addBlocker(currentAttacker, card);
}
}
showMessage();
}//selectCard()
}

View File

@@ -191,8 +191,7 @@ public class Phase extends MyObservable
else if(phase.equals(Constant.Phase.Combat_Begin)){ else if(phase.equals(Constant.Phase.Combat_Begin)){
if (AllZone.Display.stopAtPhase(turn, phase)){ if (AllZone.Display.stopAtPhase(turn, phase)){
AllZone.Combat.verifyCreaturesInPlay(); PhaseUtil.verifyCombat();
CombatUtil.showCombat();
} }
else { else {
this.setNeedToNextPhase(true); this.setNeedToNextPhase(true);
@@ -201,8 +200,7 @@ public class Phase extends MyObservable
else if (phase.equals(Constant.Phase.Combat_Declare_Attackers_InstantAbility)){ else if (phase.equals(Constant.Phase.Combat_Declare_Attackers_InstantAbility)){
if(inCombat()) { if(inCombat()) {
AllZone.Combat.verifyCreaturesInPlay(); PhaseUtil.handleDeclareAttackers();
CombatUtil.showCombat();
} }
else else
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
@@ -211,8 +209,7 @@ public class Phase extends MyObservable
// we can skip AfterBlockers and AfterAttackers if necessary // we can skip AfterBlockers and AfterAttackers if necessary
else if(phase.equals(Constant.Phase.Combat_Declare_Blockers)){ else if(phase.equals(Constant.Phase.Combat_Declare_Blockers)){
if(inCombat()) { if(inCombat()) {
AllZone.Combat.verifyCreaturesInPlay(); PhaseUtil.verifyCombat();
CombatUtil.showCombat();
} }
else else
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
@@ -223,40 +220,7 @@ public class Phase extends MyObservable
if(!inCombat()) if(!inCombat())
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
else{ else{
AllZone.Combat.verifyCreaturesInPlay(); PhaseUtil.handleDeclareBlockers();
AllZone.Stack.freezeStack();
CardList list = new CardList();
list.addAll(AllZone.Combat.getAllBlockers().toArray());
list.addAll(AllZone.pwCombat.getAllBlockers().toArray());
list = list.filter(new CardListFilter(){
public boolean addCard(Card c)
{
return !c.getCreatureBlockedThisCombat();
}
});
CardList attList = new CardList();
attList.addAll(AllZone.Combat.getAttackers());
CardList pwAttList = new CardList();
pwAttList.addAll(AllZone.pwCombat.getAttackers());
CombatUtil.checkDeclareBlockers(list);
for (Card a:attList){
CardList blockList = AllZone.Combat.getBlockers(a);
for (Card b:blockList)
CombatUtil.checkBlockedAttackers(a, b);
}
for (Card a:pwAttList){
CardList blockList = AllZone.pwCombat.getBlockers(a);
for (Card b:blockList)
CombatUtil.checkBlockedAttackers(a, b);
}
AllZone.Stack.unfreezeStack();
CombatUtil.showCombat();
} }
} }
@@ -265,10 +229,8 @@ public class Phase extends MyObservable
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
else{ else{
AllZone.Combat.verifyCreaturesInPlay(); AllZone.Combat.verifyCreaturesInPlay();
AllZone.pwCombat.verifyCreaturesInPlay();
AllZone.Combat.setAssignedFirstStrikeDamage(); AllZone.Combat.setAssignedFirstStrikeDamage();
AllZone.pwCombat.setAssignedFirstStrikeDamage();
if (!AllZone.GameInfo.isPreventCombatDamageThisTurn()) if (!AllZone.GameInfo.isPreventCombatDamageThisTurn())
Combat.dealAssignedDamage(); Combat.dealAssignedDamage();
@@ -283,10 +245,8 @@ public class Phase extends MyObservable
AllZone.Phase.setNeedToNextPhase(true); AllZone.Phase.setNeedToNextPhase(true);
else{ else{
AllZone.Combat.verifyCreaturesInPlay(); AllZone.Combat.verifyCreaturesInPlay();
AllZone.pwCombat.verifyCreaturesInPlay();
AllZone.Combat.setAssignedDamage(); AllZone.Combat.setAssignedDamage();
AllZone.pwCombat.setAssignedDamage();
if (!AllZone.GameInfo.isPreventCombatDamageThisTurn()) if (!AllZone.GameInfo.isPreventCombatDamageThisTurn())
Combat.dealAssignedDamage(); Combat.dealAssignedDamage();
@@ -350,33 +310,6 @@ public class Phase extends MyObservable
if (getPhase().equals(Constant.Phase.Combat_Declare_Attackers)) { if (getPhase().equals(Constant.Phase.Combat_Declare_Attackers)) {
AllZone.Stack.unfreezeStack(); AllZone.Stack.unfreezeStack();
nCombatsThisTurn++; nCombatsThisTurn++;
CardList list = new CardList();
list.addAll(AllZone.Combat.getAttackers());
// Remove illegal Propaganda attacks first only for attacking the Player
for(Card c:list)
CombatUtil.checkPropagandaEffects(c);
list.addAll(AllZone.pwCombat.getAttackers());
// Then run other Attacker bonuses
//check for exalted:
if (list.size() == 1){
AllZone.GameAction.checkWheneverKeyword(list.get(0), "Attack - Alone", null);
Player attackingPlayer = AllZone.Combat.getAttackingPlayer();
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, attackingPlayer);
CardList exalted = new CardList(play.getCards());
exalted = exalted.filter(new CardListFilter() {
public boolean addCard(Card c) {
return c.getKeyword().contains("Exalted");
}
});
if(exalted.size() > 0) CombatUtil.executeExaltedAbility(list.get(0), exalted.size());
// Make sure exalted effects get applied only once per combat
}
for(Card c:list)
CombatUtil.checkDeclareAttackers(c);
} }
else if (getPhase().equals(Constant.Phase.Untap)) { else if (getPhase().equals(Constant.Phase.Untap)) {
nCombatsThisTurn = 0; nCombatsThisTurn = 0;
@@ -384,7 +317,6 @@ public class Phase extends MyObservable
if (getPhase().equals(Constant.Phase.Combat_End)) { if (getPhase().equals(Constant.Phase.Combat_End)) {
AllZone.Combat.reset(); AllZone.Combat.reset();
AllZone.pwCombat.reset();
AllZone.Display.showCombat(""); AllZone.Display.showCombat("");
resetAttackedThisCombat(getPlayerTurn()); resetAttackedThisCombat(getPlayerTurn());
this.bCombat = false; this.bCombat = false;
@@ -410,9 +342,6 @@ public class Phase extends MyObservable
AllZone.Combat.reset(); AllZone.Combat.reset();
AllZone.Combat.setAttackingPlayer(player); AllZone.Combat.setAttackingPlayer(player);
AllZone.Combat.setDefendingPlayer(opp); AllZone.Combat.setDefendingPlayer(opp);
AllZone.pwCombat.reset();
AllZone.Combat.setAttackingPlayer(player);
AllZone.Combat.setDefendingPlayer(opp);
phaseIndex = findIndex(Constant.Phase.Combat_Declare_Attackers); phaseIndex = findIndex(Constant.Phase.Combat_Declare_Attackers);
} }
else { else {

View File

@@ -30,10 +30,6 @@ public class PhaseUtil {
AllZone.Combat.setAttackingPlayer(turn); AllZone.Combat.setAttackingPlayer(turn);
AllZone.Combat.setDefendingPlayer(turn.getOpponent()); AllZone.Combat.setDefendingPlayer(turn.getOpponent());
AllZone.pwCombat.reset();
AllZone.pwCombat.setAttackingPlayer(turn);
AllZone.pwCombat.setDefendingPlayer(turn.getOpponent());
// For tokens a player starts the game with they don't recover from Sum. Sickness on first turn // For tokens a player starts the game with they don't recover from Sum. Sickness on first turn
if (turn.getTurn() > 0){ if (turn.getTurn() > 0){
for(int i = 0; i < c.length; i++) for(int i = 0; i < c.length; i++)
@@ -349,6 +345,77 @@ public class PhaseUtil {
return false; return false;
} }
// ********* Declare Attackers ***********
public static void verifyCombat(){
AllZone.Combat.verifyCreaturesInPlay();
CombatUtil.showCombat();
}
public static void handleDeclareAttackers(){
verifyCombat();
CardList list = new CardList();
list.addAll(AllZone.Combat.getAttackers());
// TODO move propaganda to happen as the Attacker is Declared
// Remove illegal Propaganda attacks first only for attacking the Player
for(Card c:list)
CombatUtil.checkPropagandaEffects(c);
AllZone.Stack.freezeStack();
// Then run other Attacker bonuses
//check for exalted:
if (list.size() == 1){
AllZone.GameAction.checkWheneverKeyword(list.get(0), "Attack - Alone", null);
Player attackingPlayer = AllZone.Combat.getAttackingPlayer();
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, attackingPlayer);
CardList exalted = new CardList(play.getCards());
exalted = exalted.filter(new CardListFilter() {
public boolean addCard(Card c) {
return c.getKeyword().contains("Exalted");
}
});
if(exalted.size() > 0) CombatUtil.executeExaltedAbility(list.get(0), exalted.size());
// Make sure exalted effects get applied only once per combat
}
for(Card c:list)
CombatUtil.checkDeclareAttackers(c);
AllZone.Stack.unfreezeStack();
}
public static void handleDeclareBlockers(){
verifyCombat();
AllZone.Stack.freezeStack();
CardList list = new CardList();
list.addAll(AllZone.Combat.getAllBlockers().toArray());
list = list.filter(new CardListFilter(){
public boolean addCard(Card c)
{
return !c.getCreatureBlockedThisCombat();
}
});
CardList attList = new CardList();
attList.addAll(AllZone.Combat.getAttackers());
CombatUtil.checkDeclareBlockers(list);
for (Card a:attList){
CardList blockList = AllZone.Combat.getBlockers(a);
for (Card b:blockList)
CombatUtil.checkBlockedAttackers(a, b);
}
AllZone.Stack.unfreezeStack();
CombatUtil.showCombat();
}
// ***** Combat Utility **********
// todo: the below functions should be removed and the code blocks that use them should instead use SA_Restriction
public static boolean isBeforeAttackersAreDeclared() { public static boolean isBeforeAttackersAreDeclared() {
String phase = AllZone.Phase.getPhase(); String phase = AllZone.Phase.getPhase();
return phase.equals(Constant.Phase.Untap) || phase.equals(Constant.Phase.Upkeep) return phase.equals(Constant.Phase.Untap) || phase.equals(Constant.Phase.Upkeep)