Butcher Orgg!!!

This commit is contained in:
Tim Mocny
2020-12-30 02:35:25 +00:00
committed by Sol
parent 136c99377d
commit f700b9d43b
12 changed files with 87 additions and 21 deletions

View File

@@ -1133,6 +1133,7 @@ public class CardView extends GameEntityView {
public boolean hasDeathtouch() { return get(TrackableProperty.HasDeathtouch); }
public boolean hasDevoid() { return get(TrackableProperty.HasDevoid); }
public boolean hasDefender() { return get(TrackableProperty.HasDefender); }
public boolean hasDivideDamage() { return get(TrackableProperty.HasDivideDamage); }
public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); }
public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); }
public boolean hasFlying() { return get(TrackableProperty.HasFlying); }
@@ -1173,6 +1174,8 @@ public class CardView extends GameEntityView {
set(TrackableProperty.HasDeathtouch, c.hasKeyword(Keyword.DEATHTOUCH, state));
set(TrackableProperty.HasDevoid, c.hasKeyword(Keyword.DEVOID, state));
set(TrackableProperty.HasDefender, c.hasKeyword(Keyword.DEFENDER, state));
set(TrackableProperty.HasDivideDamage, c.hasKeyword("You may assign CARDNAME's combat damage divided as " +
"you choose among defending player and/or any number of creatures they control."));
set(TrackableProperty.HasDoubleStrike, c.hasKeyword(Keyword.DOUBLE_STRIKE, state));
set(TrackableProperty.HasFirstStrike, c.hasKeyword(Keyword.FIRST_STRIKE, state));
set(TrackableProperty.HasFlying, c.hasKeyword(Keyword.FLYING, state));

View File

@@ -20,21 +20,18 @@ package forge.game.combat;
import com.google.common.base.Function;
import com.google.common.collect.*;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType;
import forge.game.GameObjectMap;
import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardDamageMap;
import forge.game.card.*;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
@@ -64,6 +61,7 @@ public class Combat {
private Map<Card, CardCollection> blockersOrderedForDamageAssignment = Maps.newHashMap();
private Map<GameEntity, CombatLki> lkiCache = Maps.newHashMap();
private CardDamageMap dealtDamageTo = new CardDamageMap();
private boolean dividedToPlayer = false;
// List holds creatures who have dealt 1st strike damage to disallow them deal damage on regular basis (unless they have double-strike KW)
private CardCollection combatantsThatDealtFirstStrikeDamage = new CardCollection();
@@ -373,7 +371,7 @@ public class Combat {
blocker.updateBlockingForView();
}
// remove blocked from specific attacker
// remove blocker from specific attacker
public final void removeBlockAssignment(final Card attacker, final Card blocker) {
AttackingBand band = getBandOfAttackerNotNull(attacker);
Collection<Card> cc = blockedBands.get(band);
@@ -400,6 +398,15 @@ public class Combat {
return result;
}
public final CardCollection getDefendersCreatures() {
CardCollection result = new CardCollection();
for (Card attacker : getAttackers()) {
CardCollection cc = getDefenderPlayerByAttacker(attacker).getCreaturesInPlay();
result.addAll(cc);
}
return result;
}
public final CardCollection getBlockers(final AttackingBand band) {
Collection<Card> blockers = blockedBands.get(band);
return blockers == null ? new CardCollection() : new CardCollection(blockers);
@@ -716,8 +723,26 @@ public class Combat {
continue;
}
boolean divideCombatDamageAsChoose = (getDefendersCreatures().size() > 0 &&
attacker.hasKeyword("You may assign CARDNAME's combat damage divided as you choose among " +
"defending player and/or any number of creatures they control.")
&& attacker.getController().getController().confirmAction(null, null,
Localizer.getInstance().getMessage("lblAssignCombatDamageAsChoose",
CardTranslation.getTranslatedName(attacker.getName()))));
boolean trampler = attacker.hasKeyword(Keyword.TRAMPLE);
orderedBlockers = blockersOrderedForDamageAssignment.get(attacker);
if (divideCombatDamageAsChoose) {
if (orderedBlockers == null || orderedBlockers.isEmpty()) {
orderedBlockers = getDefendersCreatures();
}
else {
for (Card c : getDefendersCreatures()) {
if (!orderedBlockers.contains(c)) {
orderedBlockers.add(c);
}
}
}
}
assignedDamage = true;
// If the Attacker is unblocked, or it's a trampler and has 0 blockers, deal damage to defender
if (orderedBlockers == null || orderedBlockers.isEmpty()) {
@@ -730,6 +755,10 @@ public class Combat {
Player assigningPlayer = 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 Card && divideCombatDamageAsChoose) {
defender = getDefenderPlayerByAttacker(attacker);
dividedToPlayer = true;
}
if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) {
assigningPlayer = (Player)defender;
}
@@ -737,7 +766,8 @@ public class Combat {
assigningPlayer = orderedBlockers.get(0).getController();
}
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(attacker, orderedBlockers, damageDealt, defender, getAttackingPlayer() != assigningPlayer);
Map<Card, Integer> map = assigningPlayer.getController().assignCombatDamage(attacker, orderedBlockers,
damageDealt, defender, divideCombatDamageAsChoose || getAttackingPlayer() != assigningPlayer);
for (Entry<Card, Integer> dt : map.entrySet()) {
if (dt.getKey() == null) {
if (dt.getValue() > 0)
@@ -767,7 +797,7 @@ public class Combat {
private final void addDefendingDamage(final int n, final Card source) {
final GameEntity ge = getDefenderByAttacker(source);
if (ge instanceof Card) {
if (ge instanceof Card && !dividedToPlayer) {
final Card planeswalker = (Card) ge;
planeswalker.addAssignedDamage(n, source);
return;
@@ -805,6 +835,9 @@ public class Combat {
// This function handles both Regular and First Strike combat assignment
for (final Entry<Card, Integer> entry : defendingDamageMap.entrySet()) {
GameEntity defender = getDefenderByAttacker(entry.getKey());
if (dividedToPlayer) {
defender = getDefenderPlayerByAttacker(entry.getKey());
}
if (defender instanceof Player) { // player
defender.addCombatDamage(entry.getValue(), entry.getKey(), dealtDamageTo, preventMap, counterTable);
}
@@ -819,6 +852,7 @@ public class Combat {
combatants.addAll(getAttackers());
combatants.addAll(getAllBlockers());
combatants.addAll(getDefendingPlaneswalkers());
combatants.addAll(getDefendersCreatures());
for (final Card c : combatants) {
// if no assigned damage to resolve, move to next

View File

@@ -100,6 +100,7 @@ public enum TrackableProperty {
HasDeathtouch(TrackableTypes.BooleanType),
HasDevoid(TrackableTypes.BooleanType),
HasDefender(TrackableTypes.BooleanType),
HasDivideDamage(TrackableTypes.BooleanType),
HasDoubleStrike(TrackableTypes.BooleanType),
HasFirstStrike(TrackableTypes.BooleanType),
HasFlying(TrackableTypes.BooleanType),