mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
- Lots of Combat simplification. Including maps of Attackers Block By a Blocker, and Attackers attacking a Defender for simpler access.
- Adding support for Block Any Creatures and Block Additional Creatures
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -3431,6 +3431,7 @@ res/cardsfolder/f/forget.txt -text
|
||||
res/cardsfolder/f/forgotten_ancient.txt svneol=native#text/plain
|
||||
res/cardsfolder/f/forgotten_cave.txt svneol=native#text/plain
|
||||
res/cardsfolder/f/forgotten_harvest.txt svneol=native#text/plain
|
||||
res/cardsfolder/f/foriysian_brigade.txt -text
|
||||
res/cardsfolder/f/fork.txt svneol=native#text/plain
|
||||
res/cardsfolder/f/forked_bolt.txt svneol=native#text/plain
|
||||
res/cardsfolder/f/forked_branch_garami.txt svneol=native#text/plain
|
||||
@@ -10612,6 +10613,7 @@ res/cardsfolder/w/wall_of_essence.txt svneol=native#text/plain
|
||||
res/cardsfolder/w/wall_of_faith.txt svneol=native#text/plain
|
||||
res/cardsfolder/w/wall_of_fire.txt svneol=native#text/plain
|
||||
res/cardsfolder/w/wall_of_frost.txt svneol=native#text/plain
|
||||
res/cardsfolder/w/wall_of_glare.txt -text
|
||||
res/cardsfolder/w/wall_of_granite.txt svneol=native#text/plain
|
||||
res/cardsfolder/w/wall_of_heat.txt svneol=native#text/plain
|
||||
res/cardsfolder/w/wall_of_hope.txt svneol=native#text/plain
|
||||
|
||||
11
res/cardsfolder/f/foriysian_brigade.txt
Normal file
11
res/cardsfolder/f/foriysian_brigade.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Foriysian Brigade
|
||||
ManaCost:3 W
|
||||
Types:Creature Human Soldier
|
||||
Text:no text
|
||||
PT:2/4
|
||||
K:CARDNAME can block an additional creature.
|
||||
SVar:Rarity:Uncommon
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/foriysian_brigade.jpg
|
||||
SetInfo:WTH|Uncommon|http://magiccards.info/scans/en/wl/130.jpg
|
||||
Oracle:Foriysian Brigade can block an additional creature.
|
||||
End
|
||||
12
res/cardsfolder/w/wall_of_glare.txt
Normal file
12
res/cardsfolder/w/wall_of_glare.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name:Wall of Glare
|
||||
ManaCost:1 W
|
||||
Types:Creature Wall
|
||||
Text:no text
|
||||
PT:0/5
|
||||
K:Defender
|
||||
K:CARDNAME can block any number of creatures.
|
||||
SVar:Rarity:Common
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/wall_of_glare.jpg
|
||||
SetInfo:UDS|Common|http://magiccards.info/scans/en/ud/25.jpg
|
||||
Oracle:Defender (This creature can't attack.)\nWall of Glare can block any number of creatures.
|
||||
End
|
||||
@@ -7526,7 +7526,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isBlocking(final Card attacker) {
|
||||
return attacker.equals(AllZone.getCombat().getAttackerBlockedBy(this));
|
||||
return AllZone.getCombat().getAttackersBlockedBy(this).contains(attacker);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7539,7 +7539,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isBlockedBy(final Card blocker) {
|
||||
return this.equals(AllZone.getCombat().getAttackerBlockedBy(blocker));
|
||||
return AllZone.getCombat().getAttackersBlockedBy(blocker).contains(this);
|
||||
}
|
||||
|
||||
// /////////////////////////
|
||||
|
||||
@@ -595,10 +595,16 @@ public class AbilityFactoryPump {
|
||||
|
||||
// is the creature blocking and unable to destroy the attacker
|
||||
// or would be destroyed itself?
|
||||
if (c.isBlocking()
|
||||
&& (CombatUtil.blockerWouldBeDestroyed(c) || !CombatUtil.attackerWouldBeDestroyed(AllZone
|
||||
.getCombat().getAttackerBlockedBy(c)))) {
|
||||
return true;
|
||||
if (c.isBlocking()) {
|
||||
if (CombatUtil.blockerWouldBeDestroyed(c)) {
|
||||
return true;
|
||||
}
|
||||
CardList blockedBy = AllZone.getCombat().getAttackersBlockedBy(c);
|
||||
// For now, Only care the first creature blocked by a card.
|
||||
// TODO Add in better BlockAdditional support
|
||||
if (blockedBy.size() != 0 && !CombatUtil.attackerWouldBeDestroyed(blockedBy.get(0))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// is the creature unblocked and the spell will pump its power?
|
||||
@@ -617,11 +623,17 @@ public class AbilityFactoryPump {
|
||||
}
|
||||
|
||||
// if the life of the computer is in danger, try to pump blockers blocking Tramplers
|
||||
CardList blockedBy = AllZone.getCombat().getAttackersBlockedBy(c);
|
||||
boolean attackerHasTrample = false;
|
||||
for(Card b : blockedBy) {
|
||||
attackerHasTrample |= b.hasKeyword("Trample");
|
||||
}
|
||||
|
||||
if (phase.getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
|
||||
&& phase.isPlayerTurn(AllZone.getHumanPlayer())
|
||||
&& c.isBlocking()
|
||||
&& defense > 0
|
||||
&& AllZone.getCombat().getAttackerBlockedBy(c).hasKeyword("Trample")
|
||||
&& attackerHasTrample
|
||||
&& (sa.isAbility() || CombatUtil.lifeInDanger(AllZone.getCombat()))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
*/
|
||||
package forge.control.input;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import forge.AllZone;
|
||||
import forge.Card;
|
||||
import forge.CardList;
|
||||
import forge.Singletons;
|
||||
import forge.game.phase.CombatUtil;
|
||||
import forge.game.zone.PlayerZone;
|
||||
@@ -43,7 +44,7 @@ public class InputBlock extends Input {
|
||||
private static final long serialVersionUID = 6120743598368928128L;
|
||||
|
||||
private Card currentAttacker = null;
|
||||
private final ArrayList<Card> allBlocking = new ArrayList<Card>();
|
||||
private final HashMap<Card,CardList> allBlocking = new HashMap<Card, CardList>();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -88,7 +89,7 @@ public class InputBlock extends Input {
|
||||
// Done blocking
|
||||
ButtonUtil.reset();
|
||||
|
||||
CombatUtil.orderMultipleBlockers(AllZone.getCombat());
|
||||
CombatUtil.orderMultipleCombatants(AllZone.getCombat());
|
||||
|
||||
Singletons.getModel().getGameState().getPhaseHandler().setNeedToNextPhase(true);
|
||||
}
|
||||
@@ -98,17 +99,35 @@ public class InputBlock extends Input {
|
||||
@Override
|
||||
public final void selectCard(final Card card, final PlayerZone zone) {
|
||||
// is attacking?
|
||||
boolean reminder = true;
|
||||
|
||||
if (AllZone.getCombat().getAttackers().contains(card)) {
|
||||
this.currentAttacker = card;
|
||||
} else if (zone.is(ZoneType.Battlefield, AllZone.getHumanPlayer()) && card.isCreature()
|
||||
&& CombatUtil.canBlock(this.currentAttacker, card, AllZone.getCombat())
|
||||
&& this.currentAttacker != null && !this.allBlocking.contains(card)
|
||||
&& card.getController().isHuman()) {
|
||||
this.allBlocking.add(card);
|
||||
AllZone.getCombat().addBlocker(this.currentAttacker, card);
|
||||
reminder = false;
|
||||
} else {
|
||||
// Make sure this card is valid to even be a blocker
|
||||
if (this.currentAttacker != null && card.isCreature() && card.getController().isHuman()
|
||||
&& zone.is(ZoneType.Battlefield, AllZone.getHumanPlayer())) {
|
||||
// Create a new blockedBy list if it doesn't exist
|
||||
if (!this.allBlocking.containsKey(card)) {
|
||||
this.allBlocking.put(card, new CardList());
|
||||
}
|
||||
|
||||
CardList attackersBlocked = this.allBlocking.get(card);
|
||||
if (!attackersBlocked.contains(this.currentAttacker) &&
|
||||
CombatUtil.canBlock(this.currentAttacker, card, AllZone.getCombat()) &&
|
||||
CombatUtil.canBlockMoreCreatures(card, attackersBlocked)) {
|
||||
attackersBlocked.add(this.currentAttacker);
|
||||
AllZone.getCombat().addBlocker(this.currentAttacker, card);
|
||||
reminder = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reminder) {
|
||||
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
|
||||
}
|
||||
|
||||
this.showMessage();
|
||||
} // selectCard()
|
||||
}
|
||||
|
||||
@@ -49,21 +49,21 @@ import forge.gui.match.CMatchUI;
|
||||
public class Combat {
|
||||
// key is attacker Card
|
||||
// value is CardList of blockers
|
||||
private final Map<Card, CardList> map = new TreeMap<Card, CardList>();
|
||||
private final Map<Card, CardList> attackerMap = new TreeMap<Card, CardList>();
|
||||
private final Map<Card, CardList> blockerMap = new TreeMap<Card, CardList>();
|
||||
|
||||
private final Set<Card> blocked = new HashSet<Card>();
|
||||
|
||||
private final HashMap<Card, CardList> unblockedMap = new HashMap<Card, CardList>();
|
||||
private final HashMap<Card, Integer> defendingDamageMap = new HashMap<Card, Integer>();
|
||||
|
||||
// Defenders are the Defending Player + Each Planeswalker that player
|
||||
// controls
|
||||
// Defenders are the Defending Player + Each controlled Planeswalker
|
||||
private List<GameEntity> defenders = new ArrayList<GameEntity>();
|
||||
private Map<GameEntity, CardList> defenderMap = new TreeMap<GameEntity, CardList>();
|
||||
private int currentDefender = 0;
|
||||
private int nextDefender = 0;
|
||||
|
||||
// This Hash keeps track of
|
||||
private final HashMap<Card, Integer> attackerToDefender = new HashMap<Card, Integer>();
|
||||
|
||||
private final HashMap<Card, GameEntity> attackerToDefender = new HashMap<Card, GameEntity>();
|
||||
|
||||
private Player attackingPlayer = null;
|
||||
private Player defendingPlayer = null;
|
||||
@@ -107,11 +107,14 @@ public class Combat {
|
||||
*/
|
||||
public final void initiatePossibleDefenders(final Player defender) {
|
||||
this.defenders.clear();
|
||||
this.defenders.add(defender);
|
||||
this.defenderMap.clear();
|
||||
this.defenders.add((GameEntity)defender);
|
||||
this.defenderMap.put((GameEntity)defender, new CardList());
|
||||
CardList planeswalkers = defender.getCardsIn(ZoneType.Battlefield);
|
||||
planeswalkers = planeswalkers.getType("Planeswalker");
|
||||
for (final Card pw : planeswalkers) {
|
||||
this.defenders.add(pw);
|
||||
this.defenders.add((GameEntity)pw);
|
||||
this.defenderMap.put((GameEntity)pw, new CardList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +202,9 @@ public class Combat {
|
||||
*/
|
||||
public final void setDefenders(final List<GameEntity> newDef) {
|
||||
this.defenders = newDef;
|
||||
for(GameEntity entity : this.defenders) {
|
||||
this.defenderMap.put(entity, new CardList());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,8 +302,7 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void addDefendingDamage(final int n, final Card source) {
|
||||
final int slot = this.getDefenderByAttacker(source);
|
||||
final GameEntity ge = this.defenders.get(slot);
|
||||
final GameEntity ge = this.getDefenderByAttacker(source);
|
||||
|
||||
if (ge instanceof Card) {
|
||||
final Card pw = (Card) ge;
|
||||
@@ -321,18 +326,19 @@ public class Combat {
|
||||
* @return an array of {@link forge.CardList} objects.
|
||||
*/
|
||||
public final CardList[] sortAttackerByDefender() {
|
||||
final CardList[] attackers = new CardList[this.defenders.size()];
|
||||
for (int i = 0; i < attackers.length; i++) {
|
||||
attackers[i] = new CardList();
|
||||
}
|
||||
|
||||
for (final Card atk : this.attackerToDefender.keySet()) {
|
||||
final int i = this.attackerToDefender.get(atk);
|
||||
attackers[i].add(atk);
|
||||
int size = this.defenders.size();
|
||||
final CardList[] attackers = new CardList[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
attackers[i] = getAttackersByDefenderSlot(i);
|
||||
}
|
||||
|
||||
return attackers;
|
||||
}
|
||||
|
||||
public final CardList getAttackersByDefenderSlot(int slot) {
|
||||
GameEntity entity = this.defenders.get(slot);
|
||||
return this.defenderMap.get(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -344,7 +350,7 @@ public class Combat {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isAttacking(final Card c) {
|
||||
return this.map.get(c) != null;
|
||||
return this.attackerMap.get(c) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,8 +362,7 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void addAttacker(final Card c) {
|
||||
this.map.put(c, new CardList());
|
||||
this.attackerToDefender.put(c, this.currentDefender);
|
||||
this.addAttacker(c, defenders.get(this.currentDefender));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,13 +376,14 @@ public class Combat {
|
||||
* a GameEntity object.
|
||||
*/
|
||||
public final void addAttacker(final Card c, GameEntity defender) {
|
||||
int n = defenders.indexOf(defender);
|
||||
if (-1 == n) {
|
||||
if (!defenders.contains(defender)) {
|
||||
System.out.println("Trying to add Attacker " + c + " to missing defender " + defender);
|
||||
} else {
|
||||
this.map.put(c, new CardList());
|
||||
this.attackerToDefender.put(c, n);
|
||||
return;
|
||||
}
|
||||
|
||||
this.attackerMap.put(c, new CardList());
|
||||
this.attackerToDefender.put(c, defender);
|
||||
this.defenderMap.get(defender).add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,12 +395,20 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
* @return a {@link java.lang.Object} object.
|
||||
*/
|
||||
public final Integer getDefenderByAttacker(final Card c) {
|
||||
public final GameEntity getDefenderByAttacker(final Card c) {
|
||||
return this.attackerToDefender.get(c);
|
||||
}
|
||||
|
||||
public final GameEntity getDefendingEntity(final Card c) {
|
||||
return this.getDefenders().get(this.attackerToDefender.get(c));
|
||||
GameEntity defender = this.attackerToDefender.get(c);
|
||||
|
||||
if (this.defenders.contains(defender)) {
|
||||
return defender;
|
||||
}
|
||||
|
||||
System.out.println("Attacker " + c + " missing defender " + defender);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -403,8 +417,9 @@ public class Combat {
|
||||
* </p>
|
||||
*/
|
||||
public final void resetAttackers() {
|
||||
this.map.clear();
|
||||
this.attackerMap.clear();
|
||||
this.attackerToDefender.clear();
|
||||
this.blockerMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,7 +430,7 @@ public class Combat {
|
||||
* @return an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public final List<Card> getAttackers() {
|
||||
return new ArrayList<Card>(this.map.keySet());
|
||||
return new ArrayList<Card>(this.attackerMap.keySet());
|
||||
} // getAttackers()
|
||||
|
||||
/**
|
||||
@@ -426,7 +441,7 @@ public class Combat {
|
||||
* @return an array of {@link forge.Card} objects.
|
||||
*/
|
||||
public final CardList getAttackerList() {
|
||||
return new CardList(this.map.keySet());
|
||||
return new CardList(this.attackerMap.keySet());
|
||||
} // getAttackers()
|
||||
|
||||
/**
|
||||
@@ -454,7 +469,13 @@ public class Combat {
|
||||
*/
|
||||
public final void addBlocker(final Card attacker, final Card blocker) {
|
||||
this.blocked.add(attacker);
|
||||
this.getBlockerList(attacker).add(blocker);
|
||||
this.attackerMap.get(attacker).add(blocker);
|
||||
if (!this.blockerMap.containsKey(blocker)) {
|
||||
this.blockerMap.put(blocker, new CardList(attacker));
|
||||
}
|
||||
else {
|
||||
this.blockerMap.get(blocker).add(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,12 +486,8 @@ public class Combat {
|
||||
* @return a {@link forge.CardList} object.
|
||||
*/
|
||||
public final CardList getAllBlockers() {
|
||||
final CardList att = this.getAttackerList();
|
||||
final CardList block = new CardList();
|
||||
|
||||
for (int i = 0; i < att.size(); i++) {
|
||||
block.addAll(this.getBlockers(att.get(i)));
|
||||
}
|
||||
block.addAll(blockerMap.keySet());
|
||||
|
||||
return block;
|
||||
} // getAllBlockers()
|
||||
@@ -485,10 +502,10 @@ public class Combat {
|
||||
* @return a {@link forge.CardList} object.
|
||||
*/
|
||||
public final CardList getBlockers(final Card attacker) {
|
||||
if (this.getBlockerList(attacker) == null) {
|
||||
if (this.getBlockingAttackerList(attacker) == null) {
|
||||
return new CardList();
|
||||
} else {
|
||||
return new CardList(this.getBlockerList(attacker));
|
||||
return new CardList(this.getBlockingAttackerList(attacker));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,17 +518,11 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
* @return a {@link forge.Card} object.
|
||||
*/
|
||||
public final Card getAttackerBlockedBy(final Card blocker) {
|
||||
// TODO(sol) Return CardList instead of a card
|
||||
final CardList att = this.getAttackerList();
|
||||
|
||||
for (int i = 0; i < att.size(); i++) {
|
||||
if (this.getBlockers(att.get(i)).contains(blocker)) {
|
||||
return att.get(i);
|
||||
}
|
||||
} // for
|
||||
|
||||
return null;
|
||||
public final CardList getAttackersBlockedBy(final Card blocker) {
|
||||
if (blockerMap.containsKey(blocker)) {
|
||||
return blockerMap.get(blocker);
|
||||
}
|
||||
return new CardList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,8 +534,8 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
* @return a {@link forge.CardList} object.
|
||||
*/
|
||||
private CardList getBlockerList(final Card attacker) {
|
||||
return this.map.get(attacker);
|
||||
private CardList getBlockingAttackerList(final Card attacker) {
|
||||
return this.attackerMap.get(attacker);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,7 +548,11 @@ public class Combat {
|
||||
* @return a {@link forge.CardList} object.
|
||||
*/
|
||||
public void setBlockerList(final Card attacker, final CardList blockers) {
|
||||
this.map.put(attacker, blockers);
|
||||
this.attackerMap.put(attacker, blockers);
|
||||
}
|
||||
|
||||
public void setAttackersBlockedByList(final Card blocker, final CardList attackers) {
|
||||
this.blockerMap.put(blocker, attackers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -549,21 +564,24 @@ public class Combat {
|
||||
* a {@link forge.Card} object.
|
||||
*/
|
||||
public final void removeFromCombat(final Card c) {
|
||||
// todo(sol) add some more solid error checking in here
|
||||
// is card an attacker?
|
||||
final CardList att = this.getAttackerList();
|
||||
if (att.contains(c)) {
|
||||
this.map.remove(c);
|
||||
if (this.attackerMap.containsKey(c)) {
|
||||
CardList blockers = this.attackerMap.get(c);
|
||||
this.attackerMap.remove(c);
|
||||
for(Card b : blockers) {
|
||||
this.blockerMap.get(b).remove(c);
|
||||
}
|
||||
this.attackerToDefender.remove(c);
|
||||
} else { // card is a blocker
|
||||
for (final Card a : att) {
|
||||
if (this.getBlockers(a).contains(c)) {
|
||||
this.getBlockerList(a).remove(c);
|
||||
// TODO if Declare Blockers and Declare Blockers (Abilities)
|
||||
// merge this logic needs to be tweaked
|
||||
if ((this.getBlockers(a).size() == 0)
|
||||
&& Singletons.getModel().getGameState().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
||||
this.blocked.remove(a);
|
||||
}
|
||||
} else if (this.blockerMap.containsKey(c)){ // card is a blocker
|
||||
CardList attackers = this.blockerMap.get(c);
|
||||
|
||||
boolean stillDeclaring = Singletons.getModel().getGameState().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS);
|
||||
this.blockerMap.remove(c);
|
||||
for(Card a : attackers) {
|
||||
this.attackerMap.get(a).remove(c);
|
||||
if (stillDeclaring && this.attackerMap.get(a).size() == 0) {
|
||||
this.blocked.remove(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,7 +599,7 @@ public class Combat {
|
||||
final CardList att = this.getAttackerList();
|
||||
for (final Card attacker : att) {
|
||||
if (this.getBlockers(attacker).contains(blocker)) {
|
||||
this.getBlockerList(attacker).remove(blocker);
|
||||
this.getBlockingAttackerList(attacker).remove(blocker);
|
||||
if (this.getBlockers(attacker).size() == 0) {
|
||||
this.blocked.remove(attacker);
|
||||
}
|
||||
@@ -636,10 +654,7 @@ public class Combat {
|
||||
|
||||
for (final Card blocker : blockers) {
|
||||
if (blocker.hasDoubleStrike() || blocker.hasFirstStrike() == firstStrikeDamage) {
|
||||
// TODO Switch comment lines when Blockers can block more than one creature
|
||||
final Card attacker = this.getAttackerBlockedBy(blocker);
|
||||
CardList attackers = new CardList(attacker);
|
||||
//CardList attackers = this.getAttackersBlockedBy(b);
|
||||
CardList attackers = this.getAttackersBlockedBy(blocker);
|
||||
|
||||
final int damage = blocker.getNetCombatDamage();
|
||||
|
||||
@@ -647,7 +662,7 @@ public class Combat {
|
||||
// Just in case it was removed or something
|
||||
} else {
|
||||
assignedDamage = true;
|
||||
if (this.getAttackingPlayer().isHuman()) { // human attacks
|
||||
if (this.getAttackingPlayer().isComputer()) { // ai attacks
|
||||
if (attackers.size() > 1) {
|
||||
CMatchUI.SINGLETON_INSTANCE.assignDamage(blocker, attackers, damage);
|
||||
} else {
|
||||
|
||||
@@ -157,6 +157,17 @@ public class CombatUtil {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean canBlockMoreCreatures(final Card blocker, final CardList blockedBy) {
|
||||
// TODO(sol) expand this for the additional blocking keyword
|
||||
int size = blockedBy.size();
|
||||
|
||||
if (size == 0 || blocker.hasKeyword("CARDNAME can block any number of creatures.")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return blocker.getKeywordAmount("CARDNAME can block an additional creature.") >= size;
|
||||
}
|
||||
|
||||
// can the attacker be blocked at all?
|
||||
/**
|
||||
@@ -387,7 +398,12 @@ public class CombatUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void orderMultipleBlockers(final Combat combat) {
|
||||
public static void orderMultipleCombatants(final Combat combat) {
|
||||
CombatUtil.orderMultipleBlockers(combat);
|
||||
CombatUtil.orderBlockingMultipleAttackers(combat);
|
||||
}
|
||||
|
||||
private static void orderMultipleBlockers(final Combat combat) {
|
||||
// If there are multiple blockers, the Attacker declares the Assignment Order
|
||||
final Player player = combat.getAttackingPlayer();
|
||||
final CardList attackers = combat.getAttackerList();
|
||||
@@ -415,6 +431,34 @@ public class CombatUtil {
|
||||
// Refresh Combat Panel
|
||||
}
|
||||
|
||||
private static void orderBlockingMultipleAttackers(final Combat combat) {
|
||||
// If there are multiple blockers, the Attacker declares the Assignment Order
|
||||
final Player player = combat.getDefendingPlayer();
|
||||
final CardList blockers = combat.getAllBlockers();
|
||||
for (final Card blocker : blockers) {
|
||||
CardList attackers = combat.getAttackersBlockedBy(blocker);
|
||||
if (attackers.size() <= 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CardList orderedAttacker = null;
|
||||
if (player.isHuman()) {
|
||||
List<Object> ordered = GuiUtils.getOrderChoices("Choose Blocking Order", "Damaged First", true, (Object[])attackers.toArray());
|
||||
|
||||
orderedAttacker = new CardList();
|
||||
for(Object o : ordered) {
|
||||
orderedAttacker.add((Card)o);
|
||||
}
|
||||
}
|
||||
else {
|
||||
orderedAttacker = ComputerUtilBlock.orderAttackers(blocker, attackers);
|
||||
}
|
||||
combat.setAttackersBlockedByList(blocker, orderedAttacker);
|
||||
}
|
||||
CombatUtil.showCombat();
|
||||
// Refresh Combat Panel
|
||||
}
|
||||
|
||||
|
||||
// can the blocker block an attacker with a lure effect?
|
||||
/**
|
||||
@@ -1040,7 +1084,7 @@ public class CombatUtil {
|
||||
|
||||
int damage = 0;
|
||||
|
||||
final CardList attackers = combat.sortAttackerByDefender()[0];
|
||||
final CardList attackers = combat.getAttackersByDefenderSlot(0);
|
||||
final CardList unblocked = new CardList();
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
@@ -1082,7 +1126,7 @@ public class CombatUtil {
|
||||
|
||||
int poison = 0;
|
||||
|
||||
final CardList attackers = combat.sortAttackerByDefender()[0];
|
||||
final CardList attackers = combat.getAttackersByDefenderSlot(0);
|
||||
final CardList unblocked = new CardList();
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
@@ -1127,7 +1171,7 @@ public class CombatUtil {
|
||||
}
|
||||
|
||||
// check for creatures that must be blocked
|
||||
final CardList attackers = combat.sortAttackerByDefender()[0];
|
||||
final CardList attackers = combat.getAttackersByDefenderSlot(0);
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
|
||||
@@ -1181,7 +1225,7 @@ public class CombatUtil {
|
||||
}
|
||||
|
||||
// check for creatures that must be blocked
|
||||
final CardList attackers = combat.sortAttackerByDefender()[0];
|
||||
final CardList attackers = combat.getAttackersByDefenderSlot(0);
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
|
||||
@@ -2215,11 +2259,15 @@ public class CombatUtil {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean blockerWouldBeDestroyed(final Card blocker) {
|
||||
final Card attacker = AllZone.getCombat().getAttackerBlockedBy(blocker);
|
||||
// TODO THis function only checks if a single attacker at a time would destroy a blocker
|
||||
// This needs to expand to tally up damage
|
||||
final CardList attackers = AllZone.getCombat().getAttackersBlockedBy(blocker);
|
||||
|
||||
if (CombatUtil.canDestroyBlocker(blocker, attacker, AllZone.getCombat(), true)
|
||||
&& !(attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))) {
|
||||
return true;
|
||||
for(Card attacker : attackers) {
|
||||
if (CombatUtil.canDestroyBlocker(blocker, attacker, AllZone.getCombat(), true)
|
||||
&& !(attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2436,7 +2484,13 @@ public class CombatUtil {
|
||||
* </p>
|
||||
*/
|
||||
public static void showCombat() {
|
||||
// TODO(sol) ShowCombat seems to be resetting itself when switching away and switching back?
|
||||
final StringBuilder display = new StringBuilder();
|
||||
|
||||
if (!Singletons.getModel().getGameState().getPhaseHandler().inCombat()) {
|
||||
VCombat.SINGLETON_INSTANCE.updateCombat(display.toString().trim());
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through Defenders
|
||||
// Append Defending Player/Planeswalker
|
||||
|
||||
@@ -281,7 +281,7 @@ public class ComputerAIGeneral implements Computer {
|
||||
|
||||
AllZone.setCombat(ComputerUtilBlock.getBlockers(AllZone.getCombat(), blockers));
|
||||
|
||||
CombatUtil.orderMultipleBlockers(AllZone.getCombat());
|
||||
CombatUtil.orderMultipleCombatants(AllZone.getCombat());
|
||||
|
||||
Singletons.getModel().getGameState().getPhaseHandler().setNeedToNextPhase(true);
|
||||
}
|
||||
|
||||
@@ -781,7 +781,7 @@ public class ComputerUtilAttack {
|
||||
final int blockNum = this.blockers.size();
|
||||
int attackNum = 0;
|
||||
int damage = 0;
|
||||
CardList attacking = combat.sortAttackerByDefender()[combat.getCurrentDefenderNumber()];
|
||||
CardList attacking = combat.getAttackersByDefenderSlot(combat.getCurrentDefenderNumber());
|
||||
CardListUtil.sortAttackLowFirst(attacking);
|
||||
for (Card atta : attacking) {
|
||||
if (attackNum >= blockNum || !CombatUtil.canBeBlocked(attacker, this.blockers)) {
|
||||
|
||||
@@ -928,4 +928,17 @@ public class ComputerUtilBlock {
|
||||
|
||||
return blockers;
|
||||
}
|
||||
|
||||
public static CardList orderAttackers(Card attacker, CardList blockers) {
|
||||
// This shouldn't really take trample into account, but otherwise should be pretty similar to orderBlockers
|
||||
// very very simple ordering of attackers, sort by evaluate, then sort by attack
|
||||
//final int damage = attacker.getNetCombatDamage();
|
||||
CardListUtil.sortByEvaluateCreature(blockers);
|
||||
CardListUtil.sortAttack(blockers);
|
||||
|
||||
// TODO: Take total damage, and attempt to maximize killing the greatest evaluation of creatures
|
||||
// It's probably generally better to kill the largest creature, but sometimes its better to kill a few smaller ones
|
||||
|
||||
return blockers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +61,7 @@ import forge.util.MyRandom;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class Player extends GameEntity {
|
||||
|
||||
public abstract class Player extends GameEntity implements Comparable<Player> {
|
||||
/** The poison counters. */
|
||||
private int poisonCounters;
|
||||
|
||||
@@ -2681,6 +2680,19 @@ public abstract class Player extends GameEntity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Player o) {
|
||||
if (o == null) {
|
||||
return +1;
|
||||
}
|
||||
int subtractedHash = o.hashCode() - this.hashCode();
|
||||
if (subtractedHash == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.abs(subtractedHash)/subtractedHash;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
Reference in New Issue
Block a user