mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
* Doran, the Siege Tower - Fixed handling of use toughness instead of power for damage effect. Prevention effects work now always for the correct amount of damage.
This commit is contained in:
parent
19714312cd
commit
a7f9ba65fe
5 changed files with 85 additions and 43 deletions
|
@ -36,9 +36,13 @@ import mage.constants.Zone;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamageCreatureEvent;
|
||||
import mage.game.events.DamagePlaneswalkerEvent;
|
||||
|
@ -47,6 +51,15 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* 613.10. Some continuous effects affect game rules rather than objects. For example,
|
||||
* effects may modify a player's maximum hand size, or say that a creature must attack
|
||||
* this turn if able. These effects are applied after all other continuous effects have
|
||||
* been applied. Continuous effects that affect the costs of spells or abilities are
|
||||
* applied according to the order specified in rule 601.2e. All other such effects are
|
||||
* applied in timestamp order. See also the rules for timestamp order and dependency
|
||||
* (rules 613.6 and 613.7)
|
||||
*
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
@ -66,7 +79,7 @@ public class DoranTheSiegeTower extends CardImpl<DoranTheSiegeTower> {
|
|||
this.toughness = new MageInt(5);
|
||||
|
||||
// Each creature assigns combat damage equal to its toughness rather than its power.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DoranTheSiegeTowerEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DoranTheSiegeTowerCombatDamageRuleEffect()));
|
||||
}
|
||||
|
||||
public DoranTheSiegeTower(final DoranTheSiegeTower card) {
|
||||
|
@ -79,56 +92,40 @@ public class DoranTheSiegeTower extends CardImpl<DoranTheSiegeTower> {
|
|||
}
|
||||
}
|
||||
|
||||
class DoranTheSiegeTowerEffect extends ReplacementEffectImpl<DoranTheSiegeTowerEffect> {
|
||||
class DoranTheSiegeTowerCombatDamageRuleEffect extends ContinuousEffectImpl<DoranTheSiegeTowerCombatDamageRuleEffect> {
|
||||
|
||||
public DoranTheSiegeTowerEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Damage);
|
||||
public DoranTheSiegeTowerCombatDamageRuleEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
||||
staticText = "Each creature assigns combat damage equal to its toughness rather than its power";
|
||||
}
|
||||
|
||||
public DoranTheSiegeTowerEffect(final DoranTheSiegeTowerEffect effect) {
|
||||
public DoranTheSiegeTowerCombatDamageRuleEffect(final DoranTheSiegeTowerCombatDamageRuleEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoranTheSiegeTowerEffect copy() {
|
||||
return new DoranTheSiegeTowerEffect(this);
|
||||
public DoranTheSiegeTowerCombatDamageRuleEffect copy() {
|
||||
return new DoranTheSiegeTowerCombatDamageRuleEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
switch (event.getType()) {
|
||||
case DAMAGE_PLAYER:
|
||||
if (((DamagePlayerEvent) event).isCombatDamage()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DAMAGE_PLANESWALKER:
|
||||
if (((DamagePlaneswalkerEvent) event).isCombatDamage()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DAMAGE_CREATURE:
|
||||
if (((DamageCreatureEvent) event).isCombatDamage()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||
switch (layer) {
|
||||
case RulesEffects:
|
||||
// Change the rule
|
||||
game.getCombat().setUseToughnessForDamage(true);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (permanent != null) {
|
||||
event.setAmount(permanent.getToughness().getValue());
|
||||
}
|
||||
return false;
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.RulesEffects;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -384,6 +384,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
player.reset();
|
||||
}
|
||||
battlefield.reset(game);
|
||||
combat.reset();
|
||||
resetOtherAbilities();
|
||||
effects.apply(game);
|
||||
battlefield.fireControlChangeEvents(game);
|
||||
|
@ -578,6 +579,16 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
values.put(valueId, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Other abilities are used to implement some special kind of continious effects.
|
||||
*
|
||||
* Crucible of Worlds - You may play land cards from your graveyard.
|
||||
* Past in Flames - Each instant and sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost.
|
||||
*
|
||||
* @param objectId
|
||||
* @param zone
|
||||
* @return
|
||||
*/
|
||||
public Abilities<ActivatedAbility> getOtherAbilities(UUID objectId, Zone zone) {
|
||||
if (otherAbilities.containsKey(objectId)) {
|
||||
return otherAbilities.get(objectId).getActivatedAbilities(zone);
|
||||
|
|
|
@ -56,6 +56,8 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
|
||||
private static FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent();
|
||||
private static FilterCreatureForCombatBlock filterBlockers = new FilterCreatureForCombatBlock();
|
||||
// There are effects that let creatures assigns combat damage equal to its toughness rather than its power
|
||||
private boolean useToughnessForDamage;
|
||||
|
||||
protected List<CombatGroup> groups = new ArrayList<CombatGroup>();
|
||||
protected Map<UUID, CombatGroup> blockingGroups = new HashMap<UUID, CombatGroup>();
|
||||
|
@ -64,7 +66,10 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
// <creature that can block, <all attackers that force the creature to block it>>
|
||||
protected Map<UUID, Set<UUID>> creaturesForcedToBlockAttackers = new HashMap<UUID, Set<UUID>>();
|
||||
|
||||
|
||||
|
||||
public Combat() {
|
||||
this.useToughnessForDamage = false;
|
||||
}
|
||||
|
||||
public Combat(final Combat combat) {
|
||||
|
@ -76,6 +81,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
for (Map.Entry<UUID, CombatGroup> group : combat.blockingGroups.entrySet()) {
|
||||
blockingGroups.put(group.getKey(), group.getValue());
|
||||
}
|
||||
this.useToughnessForDamage = combat.useToughnessForDamage;
|
||||
}
|
||||
|
||||
public List<CombatGroup> getGroups() {
|
||||
|
@ -106,6 +112,18 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
return blockers;
|
||||
}
|
||||
|
||||
public boolean useToughnessForDamage() {
|
||||
return useToughnessForDamage;
|
||||
}
|
||||
|
||||
public void setUseToughnessForDamage(boolean useToughnessForDamage) {
|
||||
this.useToughnessForDamage = useToughnessForDamage;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.useToughnessForDamage = false;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
groups.clear();
|
||||
blockingGroups.clear();
|
||||
|
|
|
@ -209,20 +209,22 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
if (canDamage(attacker, first)) {
|
||||
//20091005 - 510.1c, 702.17c
|
||||
if (!blocked || hasTrample(attacker)) {
|
||||
defenderDamage(attacker, attacker.getPower().getValue(), game);
|
||||
defenderDamage(attacker, getDamageValueFromPermanent(attacker, game), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void singleBlockerDamage(boolean first, Game game) {
|
||||
//TODO: handle banding
|
||||
Permanent blocker = game.getPermanent(blockers.get(0));
|
||||
Permanent attacker = game.getPermanent(attackers.get(0));
|
||||
if (blocker != null && attacker != null) {
|
||||
int blockerDamage = blocker.getPower().getValue(); // must be set before attacker damage marking because of effects like Test of Faith
|
||||
int blockerDamage = getDamageValueFromPermanent(blocker, game); // must be set before attacker damage marking because of effects like Test of Faith
|
||||
if (blocked && canDamage(attacker, first)) {
|
||||
int damage = attacker.getPower().getValue();
|
||||
int damage = getDamageValueFromPermanent(attacker, game);
|
||||
if (hasTrample(attacker)) {
|
||||
int lethalDamage;
|
||||
if (attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())) {
|
||||
|
@ -262,7 +264,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
return;
|
||||
}
|
||||
Player player = game.getPlayer(attacker.getControllerId());
|
||||
int damage = attacker.getPower().getValue();
|
||||
int damage = getDamageValueFromPermanent(attacker, game);
|
||||
if (canDamage(attacker, first)) {
|
||||
// must be set before attacker damage marking because of effects like Test of Faith
|
||||
Map<UUID, Integer> blockerPower = new HashMap<UUID, Integer>();
|
||||
|
@ -270,7 +272,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (canDamage(blocker, first)) {
|
||||
if (blocker.getBlocking() == 1) { // blocking several creatures handled separately
|
||||
blockerPower.put(blockerId, blocker.getPower().getValue());
|
||||
blockerPower.put(blockerId, getDamageValueFromPermanent(blocker, game));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +314,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
for (UUID blockerId: blockerOrder) {
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
if (canDamage(blocker, first)) {
|
||||
attacker.markDamage(blocker.getPower().getValue(), blocker.getId(), game, true, true);
|
||||
attacker.markDamage(getDamageValueFromPermanent(blocker, game), blocker.getId(), game, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +334,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
Permanent attacker = game.getPermanent(attackers.get(0));
|
||||
if (blocker != null && attacker != null) {
|
||||
if (canDamage(blocker, first)) {
|
||||
int damage = blocker.getPower().getValue();
|
||||
int damage = getDamageValueFromPermanent(blocker, game);
|
||||
attacker.markDamage(damage, blocker.getId(), game, true, true);
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +355,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
return;
|
||||
}
|
||||
Player player = game.getPlayer(blocker.getControllerId());
|
||||
int damage = blocker.getPower().getValue();
|
||||
int damage = getDamageValueFromPermanent(blocker, game);
|
||||
|
||||
if (canDamage(blocker, first)) {
|
||||
Map<UUID, Integer> assigned = new HashMap<UUID, Integer>();
|
||||
|
@ -474,7 +476,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
public int totalAttackerDamage(Game game) {
|
||||
int total = 0;
|
||||
for (UUID attackerId: attackers) {
|
||||
total += game.getPermanent(attackerId).getPower().getValue();
|
||||
total += getDamageValueFromPermanent(game.getPermanent(attackerId), game);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
@ -574,6 +576,21 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
|||
}
|
||||
return blockWasLegal;
|
||||
}
|
||||
/**
|
||||
* There are effects that let creatures assigns combat damage equal to its toughness rather than its power.
|
||||
* So this method takes this into account to get the value of damage a creature will assign
|
||||
*
|
||||
* @param permanent
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
private int getDamageValueFromPermanent(Permanent permanent, Game game) {
|
||||
if (game.getCombat().useToughnessForDamage()) {
|
||||
return permanent.getToughness().getValue();
|
||||
} else {
|
||||
return permanent.getPower().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatGroup copy() {
|
||||
|
|
|
@ -619,8 +619,7 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
|
|||
*/
|
||||
private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, ArrayList<UUID> appliedEffects) {
|
||||
int damageDone = 0;
|
||||
// because of "Doran, the Siege Tower" we can't check here for 0 damage.
|
||||
if (canDamage(game.getObject(sourceId), game)) {
|
||||
if (damageAmount > 0 && canDamage(game.getObject(sourceId), game)) {
|
||||
if (cardType.contains(CardType.PLANESWALKER)) {
|
||||
damageDone = damagePlaneswalker(damageAmount, sourceId, game, preventable, combat, markDamage, appliedEffects);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue