mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
- 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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -200,9 +200,10 @@ public enum CMatchUI {
|
||||
* @param attacker   {@link forge.Card}
|
||||
* @param blockers   {@link forge.CardList}
|
||||
* @param damage   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];
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user