39
39
import java .io .Serializable ;
40
40
import java .util .*;
41
41
import java .util .stream .Collectors ;
42
+ import java .util .stream .Stream ;
42
43
43
44
/**
44
45
* @author BetaSteward_at_googlemail.com
@@ -59,6 +60,7 @@ public class Combat implements Serializable, Copyable<Combat> {
59
60
private final List <FilterCreaturePermanent > useToughnessForDamageFilters = new ArrayList <>();
60
61
61
62
protected List <CombatGroup > groups = new ArrayList <>();
63
+ protected List <CombatGroup > formerGroups = new ArrayList <>();
62
64
protected Map <UUID , CombatGroup > blockingGroups = new HashMap <>();
63
65
// all possible defenders (players, planeswalkers or battle)
64
66
protected Set <UUID > defenders = new HashSet <>();
@@ -83,6 +85,9 @@ protected Combat(final Combat combat) {
83
85
for (CombatGroup group : combat .groups ) {
84
86
groups .add (group .copy ());
85
87
}
88
+ for (CombatGroup group : combat .formerGroups ) {
89
+ formerGroups .add (group .copy ());
90
+ }
86
91
defenders .addAll (combat .defenders );
87
92
for (Map .Entry <UUID , CombatGroup > group : combat .blockingGroups .entrySet ()) {
88
93
blockingGroups .put (group .getKey (), group .getValue ());
@@ -181,6 +186,7 @@ public void checkForRemoveFromCombat(Game game) {
181
186
182
187
public void clear () {
183
188
groups .clear ();
189
+ formerGroups .clear ();
184
190
blockingGroups .clear ();
185
191
defenders .clear ();
186
192
attackingPlayerId = null ;
@@ -1679,6 +1685,36 @@ public UUID getDefenderId(UUID attackerId) {
1679
1685
* @return
1680
1686
*/
1681
1687
public UUID getDefendingPlayerId (UUID attackingCreatureId , Game game ) {
1688
+ return getDefendingPlayerId (attackingCreatureId , game , true );
1689
+ }
1690
+
1691
+ /**
1692
+ * Returns the playerId of the player that is attacked by given attacking
1693
+ * creature or formerly-attacking creature.
1694
+ *
1695
+ * @param attackingCreatureId
1696
+ * @param game
1697
+ * @return
1698
+ */
1699
+ public UUID getDefendingPlayerId (UUID attackingCreatureId , Game game , boolean allowFormer ) {
1700
+ if (allowFormer ) {
1701
+ /*
1702
+ * 802.2a. Any rule, object, or effect that refers to a "defending player" refers to one specific defending
1703
+ * player, not to all of the defending players. If an ability of an attacking creature refers to a
1704
+ * defending player, or a spell or ability refers to both an attacking creature and a defending player,
1705
+ * then unless otherwise specified, the defending player it's referring to is the player that creature is
1706
+ * attacking, the controller of the planeswalker that creature is attacking, or the protector of the battle
1707
+ * that player is attacking. If that creature is no longer attacking, the defending player it's referring
1708
+ * to is the player that creature was attacking before it was removed from combat, the controller of the
1709
+ * planeswalker that creature was attacking before it was removed from combat, or the protector of the
1710
+ * battle that player was attacking before it was removed from combat.
1711
+ */
1712
+ return Stream .concat (groups .stream (), formerGroups .stream ())
1713
+ .filter (group -> (group .getAttackers ().contains (attackingCreatureId ) || group .getFormerAttackers ().contains (attackingCreatureId )))
1714
+ .map (CombatGroup ::getDefendingPlayerId )
1715
+ .findFirst ()
1716
+ .orElse (null );
1717
+ }
1682
1718
return groups
1683
1719
.stream ()
1684
1720
.filter (group -> group .getAttackers ().contains (attackingCreatureId ))
@@ -1743,6 +1779,7 @@ public void removeAttacker(UUID attackerId, Game game) {
1743
1779
}
1744
1780
}
1745
1781
if (group .attackers .isEmpty ()) {
1782
+ formerGroups .add (group );
1746
1783
groups .remove (group );
1747
1784
}
1748
1785
return ;
0 commit comments