- Added Defensive Formation

- Added some logic for controllers of combatants to assign combat damage (required for Banding and Defensive Formation)
This commit is contained in:
Sol
2013-06-08 04:08:47 +00:00
parent d29b9cb0fd
commit ac021be730
9 changed files with 60 additions and 22 deletions

View File

@@ -1670,8 +1670,10 @@ public class ComputerUtilCombat {
* @param dmgCanDeal
* a int.
* @param defender
* @param overrideOrder overriding combatant order
*/
public static Map<Card, Integer> distributeAIDamage(final Card attacker, final List<Card> block, int dmgCanDeal, GameEntity defender) {
public static Map<Card, Integer> distributeAIDamage(final Card attacker, final List<Card> block, int dmgCanDeal, GameEntity defender, boolean overrideOrder) {
// TODO: Distribute defensive Damage (AI controls how damage is dealt to own cards) for Banding and Defensive Formation
Map<Card, Integer> damageMap = new HashMap<Card, Integer>();
boolean isAttacking = defender != null;

View File

@@ -618,7 +618,7 @@ public class Combat {
if (!attackers.isEmpty()) {
assignedDamage = true;
Map<Card, Integer> map = blocker.getController().getController().assignCombatDamage(blocker, attackers, damage, null);
Map<Card, Integer> map = blocker.getController().getController().assignCombatDamage(blocker, attackers, damage, null, false);
for (Entry<Card, Integer> dt : map.entrySet()) {
dt.getKey().addAssignedDamage(dt.getValue(), blocker);
dt.getKey().updateObservers();
@@ -659,7 +659,22 @@ public class Combat {
continue;
}
} else {
Map<Card, Integer> map = this.getAttackingPlayer().getController().assignCombatDamage(attacker, blockers, damageDealt, this.getDefenderByAttacker(attacker));
GameEntity defender = this.getDefenderByAttacker(attacker);
Player assigningPlayer = this.getAttackingPlayer();
// Defensive Formation is very similar to Banding with Blockers
// It allows the defending player to assign damage instead of the attacking player
if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) {
assigningPlayer = (Player)defender;
}
if (!assigningPlayer.equals(defender)) {
List<Card> blockingBand = CardLists.getKeyword(blockers, "Banding");
if (!blockingBand.isEmpty()) {
assigningPlayer = blockingBand.get(0).getController();
}
}
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(attacker, blockers, damageDealt, defender, this.getAttackingPlayer() != assigningPlayer);
for (Entry<Card, Integer> dt : map.entrySet()) {
if( dt.getKey() == null) {
if (dt.getValue() > 0)

View File

@@ -96,7 +96,7 @@ public abstract class PlayerController {
public abstract Deck sideboard(final Deck deck, GameType gameType);
public abstract Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender);
public abstract Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender, boolean overrideOrder);
public abstract Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero);
public abstract List<Card> choosePermanentsToSacrifice(SpellAbility sa, int min, int max, List<Card> validTargets, String message);

View File

@@ -113,8 +113,8 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender) {
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender);
public Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender, boolean overrideOrder) {
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, damageDealt, defender, overrideOrder);
}
@Override

View File

@@ -180,7 +180,7 @@ public class PlayerControllerHuman extends PlayerController {
* @see forge.game.player.PlayerController#assignCombatDamage()
*/
@Override
public Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender) {
public Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender, boolean overrideOrder) {
// Attacker is a poor name here, since the creature assigning damage
// could just as easily be the blocker.
Map<Card, Integer> map;
@@ -189,7 +189,7 @@ public class PlayerControllerHuman extends PlayerController {
map.put(null, damageDealt);
} else {
if ((attacker.hasKeyword("Trample") && defender != null) || (blockers.size() > 1)) {
map = CMatchUI.SINGLETON_INSTANCE.getDamageToAssign(attacker, blockers, damageDealt, defender);
map = CMatchUI.SINGLETON_INSTANCE.getDamageToAssign(attacker, blockers, damageDealt, defender, overrideOrder);
} else {
map = new HashMap<Card, Integer>();
map.put(blockers.get(0), damageDealt);

View File

@@ -200,9 +200,10 @@ public enum CMatchUI {
* @param attacker &emsp; {@link forge.Card}
* @param blockers &emsp; {@link forge.CardList}
* @param damage &emsp; int
* @param overrideOrder overriding combatant order
*/
@SuppressWarnings("unchecked")
public Map<Card, Integer> getDamageToAssign(final Card attacker, final List<Card> blockers, final int damage, final GameEntity defender) {
public Map<Card, Integer> getDamageToAssign(final Card attacker, final List<Card> blockers, final int damage, final GameEntity defender, final boolean overrideOrder) {
if (damage <= 0) {
return new HashMap<Card, Integer>();
}
@@ -219,8 +220,7 @@ public enum CMatchUI {
FThreads.invokeInEdtAndWait(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
VAssignDamage v = new VAssignDamage(attacker, blockers, damage, defender);
VAssignDamage v = new VAssignDamage(attacker, blockers, damage, defender, overrideOrder);
result[0] = v.getDamageMap();
}});
return (Map<Card, Integer>)result[0];

View File

@@ -69,6 +69,7 @@ public class VAssignDamage {
private boolean attackerHasDeathtouch = false;
private boolean attackerHasTrample = false;
private boolean attackerHasInfect = false;
private boolean overrideCombatantOrder = false;
private final GameEntity defender;
@@ -136,17 +137,20 @@ public class VAssignDamage {
/** Constructor.
*
* @param attacker0 {@link forge.Card}
* @param defenders0 List<{@link forge.Card}>
* @param defenderCards List<{@link forge.Card}>
* @param damage0 int
* @param defender GameEntity that's bein attacked
* @param overrideOrder override combatant order
*/
public VAssignDamage(final Card attacker0, final List<Card> defenderCards, final int damage0, final GameEntity defender) {
public VAssignDamage(final Card attacker0, final List<Card> defenderCards, final int damage0, final GameEntity defender, boolean overrideOrder) {
// Set damage storage vars
this.totalDamageToAssign = damage0;
this.defender = defender;
this.attackerHasDeathtouch = attacker0.hasKeyword("Deathtouch");
this.attackerHasInfect = attacker0.hasKeyword("Infect");
this.attackerHasTrample = defender != null && attacker0.hasKeyword("Trample");
this.overrideCombatantOrder = overrideOrder;
// Top-level UI stuff
final JPanel overlay = SOverlayUtils.genericOverlay();
@@ -275,8 +279,10 @@ public class VAssignDamage {
if ( !damage.containsKey(source) )
source = null;
// Allow click if this is active, or next to active and active has lethal
if (isAdding && !VAssignDamage.this.canAssignTo(source)) {
// If trying to assign to the defender, follow the normal assignment rules
// No need to check for "active" creature assignee when overiding combatant order
if ((source == null || source == this.defender || !this.overrideCombatantOrder) && isAdding &&
!VAssignDamage.this.canAssignTo(source)) {
return;
}
@@ -301,9 +307,9 @@ public class VAssignDamage {
if ( damageToAdd > leftToAssign )
damageToAdd = leftToAssign;
// cannot assign first blocker less than lethal damage
// cannot assign first blocker less than lethal damage except when overriding order
boolean isFirstBlocker = defenders.get(0).card == source;
if ( isFirstBlocker && damageToAdd + damageItHad < lethalDamage )
if (!this.overrideCombatantOrder && isFirstBlocker && damageToAdd + damageItHad < lethalDamage )
return;
if ( 0 == damageToAdd || damageToAdd + damageItHad < 0)
@@ -314,23 +320,29 @@ public class VAssignDamage {
updateLabels();
}
/**
* TODO: Write javadoc for this method.
*/
private void checkDamageQueue() {
// Clear out any Damage that shouldn't be assigned to other combatants
boolean hasAliveEnemy = false;
for(DamageTarget dt : defenders) {
int lethal = getDamageToKill(dt.card);
int damage = dt.damage;
if ( hasAliveEnemy )
// If overriding combatant order, make sure everything has lethal if defender has damage assigned to it
// Otherwise, follow normal combatant order
if ( hasAliveEnemy && (!this.overrideCombatantOrder || dt.card == null || dt.card == this.defender))
dt.damage = 0;
else
hasAliveEnemy = damage < lethal;
hasAliveEnemy |= damage < lethal;
}
}
// will assign all damage to defenders and rest to player, if present
private void initialAssignDamage(boolean toAllBlockers) {
if (!toAllBlockers && this.overrideCombatantOrder) {
// Don't auto assign the first damage when overriding combatant order
updateLabels();
return;
}
int dmgLeft = totalDamageToAssign;
DamageTarget dtLast = null;
for(DamageTarget dt : defenders) { // MUST NOT RUN WITH EMPTY collection