mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
- Human may now declare attacks in a band
- Added Benalish Hero
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -912,6 +912,7 @@ res/cardsfolder/b/benalish_cavalry.txt svneol=native#text/plain
|
|||||||
res/cardsfolder/b/benalish_commander.txt -text
|
res/cardsfolder/b/benalish_commander.txt -text
|
||||||
res/cardsfolder/b/benalish_emissary.txt svneol=native#text/plain
|
res/cardsfolder/b/benalish_emissary.txt svneol=native#text/plain
|
||||||
res/cardsfolder/b/benalish_heralds.txt svneol=native#text/plain
|
res/cardsfolder/b/benalish_heralds.txt svneol=native#text/plain
|
||||||
|
res/cardsfolder/b/benalish_hero.txt -text
|
||||||
res/cardsfolder/b/benalish_knight.txt svneol=native#text/plain
|
res/cardsfolder/b/benalish_knight.txt svneol=native#text/plain
|
||||||
res/cardsfolder/b/benalish_lancer.txt -text
|
res/cardsfolder/b/benalish_lancer.txt -text
|
||||||
res/cardsfolder/b/benalish_missionary.txt svneol=native#text/plain
|
res/cardsfolder/b/benalish_missionary.txt svneol=native#text/plain
|
||||||
|
|||||||
7
res/cardsfolder/b/benalish_hero.txt
Normal file
7
res/cardsfolder/b/benalish_hero.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name:Benalish Hero
|
||||||
|
ManaCost:W
|
||||||
|
Types:Creature Human Soldier
|
||||||
|
PT:1/1
|
||||||
|
K:Banding
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/benalish_hero.jpg
|
||||||
|
Oracle:Banding (Any creatures with banding, and up to one without, can attack in a band. Bands are blocked as a group. If any creatures with banding you control are blocking or being blocked by a creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking.)
|
||||||
@@ -207,6 +207,16 @@ public class Combat {
|
|||||||
return defenderMap.get(defender);
|
return defenderMap.get(defender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final List<AttackingBand> getAttackingBandsOf(GameEntity defender) {
|
||||||
|
List<AttackingBand> bands = new ArrayList<AttackingBand>();
|
||||||
|
for(AttackingBand band : this.attackingBands) {
|
||||||
|
if (band.getDefender().equals(defender)) {
|
||||||
|
bands.add(band);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bands;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* isAttacking.
|
* isAttacking.
|
||||||
@@ -503,11 +513,17 @@ public class Combat {
|
|||||||
this.blockerToBandsMap.get(b).remove(c);
|
this.blockerToBandsMap.get(b).remove(c);
|
||||||
}
|
}
|
||||||
// Clear removed attacker from assignment order
|
// Clear removed attacker from assignment order
|
||||||
|
if (this.blockerDamageAssignmentOrder.containsKey(b)) {
|
||||||
this.blockerDamageAssignmentOrder.get(b).remove(c);
|
this.blockerDamageAssignmentOrder.get(b).remove(c);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.defenderMap.get(band.getDefender()).remove(c);
|
this.defenderMap.get(band.getDefender()).remove(c);
|
||||||
} else if (this.blockerDamageAssignmentOrder.containsKey(c)) { // card is a blocker
|
|
||||||
|
if (band.getAttackers().isEmpty() && band.getBlockers().isEmpty()) {
|
||||||
|
this.getAttackingBands().remove(band);
|
||||||
|
}
|
||||||
|
} else if (this.blockerToBandsMap.containsKey(c)) { // card is a blocker
|
||||||
List<AttackingBand> attackers = this.blockerToBandsMap.get(c);
|
List<AttackingBand> attackers = this.blockerToBandsMap.get(c);
|
||||||
|
|
||||||
this.blockerToBandsMap.remove(c);
|
this.blockerToBandsMap.remove(c);
|
||||||
@@ -515,10 +531,12 @@ public class Combat {
|
|||||||
for (AttackingBand a : attackers) {
|
for (AttackingBand a : attackers) {
|
||||||
a.removeBlocker(c);
|
a.removeBlocker(c);
|
||||||
for(Card atk : a.getAttackers()) {
|
for(Card atk : a.getAttackers()) {
|
||||||
|
if (this.attackerDamageAssignmentOrder.containsKey(atk)) {
|
||||||
this.attackerDamageAssignmentOrder.get(atk).remove(c);
|
this.attackerDamageAssignmentOrder.get(atk).remove(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} // removeFromCombat()
|
} // removeFromCombat()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.google.common.collect.Iterables;
|
|||||||
import forge.Card;
|
import forge.Card;
|
||||||
import forge.CardPredicates;
|
import forge.CardPredicates;
|
||||||
import forge.GameEntity;
|
import forge.GameEntity;
|
||||||
|
import forge.game.combat.AttackingBand;
|
||||||
import forge.game.phase.Combat;
|
import forge.game.phase.Combat;
|
||||||
import forge.game.phase.CombatUtil;
|
import forge.game.phase.CombatUtil;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -52,6 +53,7 @@ public class InputAttack extends InputSyncronizedBase {
|
|||||||
private GameEntity currentDefender;
|
private GameEntity currentDefender;
|
||||||
private final Player playerAttacks;
|
private final Player playerAttacks;
|
||||||
private final Player playerDeclares;
|
private final Player playerDeclares;
|
||||||
|
private AttackingBand activeBand = null;
|
||||||
|
|
||||||
public InputAttack(Player attacks, Player declares, Combat combat) {
|
public InputAttack(Player attacks, Player declares, Combat combat) {
|
||||||
this.playerAttacks = attacks;
|
this.playerAttacks = attacks;
|
||||||
@@ -97,8 +99,10 @@ public class InputAttack extends InputSyncronizedBase {
|
|||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected final void onOk() {
|
protected final void onOk() {
|
||||||
|
// TODO Add check to see if each must attack creature is attacking
|
||||||
// Propaganda costs could have been paid here.
|
// Propaganda costs could have been paid here.
|
||||||
setCurrentDefender(null); // remove highlights
|
setCurrentDefender(null); // remove highlights
|
||||||
|
activateBand(null);
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,12 +119,33 @@ public class InputAttack extends InputSyncronizedBase {
|
|||||||
protected final void onCardSelected(final Card card, boolean isMetaDown) {
|
protected final void onCardSelected(final Card card, boolean isMetaDown) {
|
||||||
final List<Card> att = combat.getAttackers();
|
final List<Card> att = combat.getAttackers();
|
||||||
if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) {
|
if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) {
|
||||||
|
// TODO Is there no way to attacks each turn cards to attack Planeswalkers?
|
||||||
combat.removeFromCombat(card);
|
combat.removeFromCombat(card);
|
||||||
|
card.setUsedToPay(false);
|
||||||
showCombat();
|
showCombat();
|
||||||
|
// When removing an attacker should I clear the attacking band?
|
||||||
|
this.activateBand(this.activeBand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card.isAttacking(currentDefender)) {
|
if (card.isAttacking(currentDefender)) {
|
||||||
|
// Activate band by selecting/deselecting a band member
|
||||||
|
if (this.activeBand == null) {
|
||||||
|
this.activateBand(combat.getBandByAttacker(card));
|
||||||
|
} else if (this.activeBand.getAttackers().contains(card)) {
|
||||||
|
this.activateBand(null);
|
||||||
|
} else { // Join a band by selecting a non-active band member after activating a band
|
||||||
|
if (this.activeBand.canJoinBand(card)) {
|
||||||
|
combat.removeFromCombat(card);
|
||||||
|
combat.addAttacker(card, currentDefender, this.activeBand);
|
||||||
|
this.activateBand(this.activeBand);
|
||||||
|
updateMessage();
|
||||||
|
} else {
|
||||||
|
flashIncorrectAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,10 +157,20 @@ public class InputAttack extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (playerAttacks.getZone(ZoneType.Battlefield).contains(card) && CombatUtil.canAttack(card, currentDefender, combat)) {
|
if (playerAttacks.getZone(ZoneType.Battlefield).contains(card) && CombatUtil.canAttack(card, currentDefender, combat)) {
|
||||||
if( combat.isAttacking(card)) {
|
if (this.activeBand != null && !this.activeBand.canJoinBand(card)) {
|
||||||
|
this.activateBand(null);
|
||||||
|
updateMessage();
|
||||||
|
flashIncorrectAction();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(combat.isAttacking(card)) {
|
||||||
combat.removeFromCombat(card);
|
combat.removeFromCombat(card);
|
||||||
}
|
}
|
||||||
combat.addAttacker(card, currentDefender);
|
|
||||||
|
combat.addAttacker(card, currentDefender, this.activeBand);
|
||||||
|
this.activateBand(this.activeBand);
|
||||||
|
updateMessage();
|
||||||
showCombat();
|
showCombat();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -157,13 +192,45 @@ public class InputAttack extends InputSyncronizedBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String header = playerAttacks == playerDeclares ? "declare attackers." : "declare attackers for " + playerAttacks.getName();
|
updateMessage();
|
||||||
showMessage(playerDeclares.getName() + ", " + header + "\nSelecting Creatures to Attack " + currentDefender +
|
|
||||||
"\n\nTo attack other players or their planewalkers just click on them");
|
|
||||||
|
|
||||||
// This will instantly highlight targets
|
// This will instantly highlight targets
|
||||||
for(MyObservable updateable : toUpdate) {
|
for(MyObservable updateable : toUpdate) {
|
||||||
updateable.updateObservers();
|
updateable.updateObservers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final void activateBand(AttackingBand band) {
|
||||||
|
Set<MyObservable> toUpdate = new HashSet<MyObservable>();
|
||||||
|
if (this.activeBand != null) {
|
||||||
|
for(Card card : this.activeBand.getAttackers()) {
|
||||||
|
card.setUsedToPay(false);
|
||||||
|
toUpdate.add(card.getController().getZone(ZoneType.Battlefield));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.activeBand = band;
|
||||||
|
|
||||||
|
if (this.activeBand != null) {
|
||||||
|
for(Card card : this.activeBand.getAttackers()) {
|
||||||
|
card.setUsedToPay(true);
|
||||||
|
toUpdate.add(card.getController().getZone(ZoneType.Battlefield));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will instantly highlight targets
|
||||||
|
for(MyObservable updateable : toUpdate) {
|
||||||
|
updateable.updateObservers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMessage() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(playerDeclares.getName()).append(", ");
|
||||||
|
sb.append(playerAttacks == playerDeclares ? "declare attackers." : "declare attackers for " + playerAttacks.getName()).append("\n");
|
||||||
|
sb.append("Selecting Creatures to Attack ").append(currentDefender).append("\n\n");
|
||||||
|
sb.append("To change the current defender, click on the player or planeswalker you wish to attack.\n");
|
||||||
|
sb.append("To attack as a band, click an attacking creature to activate its 'band', select another to join the band.");
|
||||||
|
|
||||||
|
showMessage(sb.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import forge.Card;
|
|||||||
import forge.Command;
|
import forge.Command;
|
||||||
import forge.GameEntity;
|
import forge.GameEntity;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
|
import forge.game.combat.AttackingBand;
|
||||||
import forge.game.phase.Combat;
|
import forge.game.phase.Combat;
|
||||||
import forge.game.phase.PhaseHandler;
|
import forge.game.phase.PhaseHandler;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
@@ -70,8 +71,8 @@ public enum CCombat implements ICDoc {
|
|||||||
|
|
||||||
// Not a big fan of the triple nested loop here
|
// Not a big fan of the triple nested loop here
|
||||||
for (GameEntity defender : combat.getDefenders()) {
|
for (GameEntity defender : combat.getDefenders()) {
|
||||||
List<Card> atk = combat.getAttackersOf(defender);
|
List<AttackingBand> bands = combat.getAttackingBandsOf(defender);
|
||||||
if (atk == null || atk.isEmpty()) {
|
if (bands == null || bands.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,18 +87,23 @@ public enum CCombat implements ICDoc {
|
|||||||
|
|
||||||
display.append(defender.getName()).append(" is attacked by:\n");
|
display.append(defender.getName()).append(" is attacked by:\n");
|
||||||
|
|
||||||
for (final Card c : atk) {
|
// Associate Bands, Attackers Blockers
|
||||||
// loop through attackers
|
for(AttackingBand band : bands) {
|
||||||
|
display.append(" BAND");
|
||||||
|
if (band.getBlocked()) {
|
||||||
|
display.append(" (blocked)");
|
||||||
|
}
|
||||||
|
display.append("\n");
|
||||||
|
|
||||||
|
for (final Card c : band.getAttackers()) {
|
||||||
display.append(" > ");
|
display.append(" > ");
|
||||||
display.append(combatantToString(c)).append("\n");
|
display.append(combatantToString(c)).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
List<Card> blockers = combat.getBlockers(c, true);
|
for (final Card element : band.getBlockers()) {
|
||||||
|
|
||||||
// loop through blockers
|
|
||||||
for (final Card element : blockers) {
|
|
||||||
display.append(" < ").append(combatantToString(element)).append("\n");
|
display.append(" < ").append(combatantToString(element)).append("\n");
|
||||||
}
|
}
|
||||||
} // loop through attackers
|
}
|
||||||
}
|
}
|
||||||
return display.toString().trim();
|
return display.toString().trim();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user