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:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -2552,6 +2552,7 @@ res/cardsfolder/d/defender_of_law.txt svneol=native#text/plain
|
||||
res/cardsfolder/d/defender_of_the_order.txt svneol=native#text/plain
|
||||
res/cardsfolder/d/defense_grid.txt svneol=native#text/plain
|
||||
res/cardsfolder/d/defense_of_the_heart.txt svneol=native#text/plain
|
||||
res/cardsfolder/d/defensive_formation.txt -text
|
||||
res/cardsfolder/d/defensive_maneuvers.txt -text svneol=unset#text/plain
|
||||
res/cardsfolder/d/defensive_stance.txt svneol=native#text/plain
|
||||
res/cardsfolder/d/defiant_elf.txt svneol=native#text/plain
|
||||
|
||||
8
res/cardsfolder/d/defensive_formation.txt
Normal file
8
res/cardsfolder/d/defensive_formation.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Defensive Formation
|
||||
ManaCost:W
|
||||
Types:Enchantment
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You assign combat damage of each creature attacking you. | Description$ Rather than the attacking player, you assign the combat damage of each creature attacking you. You can divide that creature's combat damage as you choose among any of the creatures blocking it.
|
||||
SVar:NonStackingEffect:True
|
||||
SVar:RemAIDeck:True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/defensive_formation.jpg
|
||||
Oracle:Rather than the attacking player, you assign the combat damage of each creature attacking you. You can divide that creature's combat damage as you choose among any of the creatures blocking it.
|
||||
@@ -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