mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
[KHM] Implemented Toralf, God of Fury / Toralf's Hammer
This commit is contained in:
parent
e18e3c79d4
commit
c0efada19a
4 changed files with 253 additions and 44 deletions
189
Mage.Sets/src/mage/cards/t/ToralfGodOfFury.java
Normal file
189
Mage.Sets/src/mage/cards/t/ToralfGodOfFury.java
Normal file
|
@ -0,0 +1,189 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.condition.common.AttachedToMatchesFilterCondition;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.common.UnattachCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.common.TapTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityWithAttachmentEffect;
|
||||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.ModalDoubleFacesCard;
|
||||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePlayerOrPlaneswalker;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetAnyTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class ToralfGodOfFury extends ModalDoubleFacesCard {
|
||||
|
||||
private static final Condition condition
|
||||
= new AttachedToMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_LEGENDARY);
|
||||
|
||||
public ToralfGodOfFury(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo,
|
||||
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "{2}{R}{R}",
|
||||
"", new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{1}{R}"
|
||||
);
|
||||
|
||||
// 1.
|
||||
// Toralf, God of Fury
|
||||
// Legendary Creature - God
|
||||
this.getLeftHalfCard().addSuperType(SuperType.LEGENDARY);
|
||||
this.getLeftHalfCard().setPT(new MageInt(5), new MageInt(4));
|
||||
|
||||
// Trample
|
||||
this.getLeftHalfCard().addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// Whenever a creature or planeswalker an opponent controls is dealt excess noncombat damage, Toralf, God of Fury deals damage equal to the excess to any target other than that permanent.
|
||||
this.getLeftHalfCard().addAbility(new ToralfGodOfFuryTriggeredAbility());
|
||||
|
||||
// 2.
|
||||
// Toralf's Hammer
|
||||
// Legendary Artifact - Equipment
|
||||
this.getRightHalfCard().addSuperType(SuperType.LEGENDARY);
|
||||
|
||||
// Equipped creature has "{1}{R}, {T}, Unattach Toralf's Hammer: It deals 3 damage to any target. Return Toralf's Hammer to its owner's hand."
|
||||
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityWithAttachmentEffect(
|
||||
"equipped creature has \"{tap}, Unattach {this}: It deals 3 damage to any target. Return {this} to its owner's hand.\"",
|
||||
new TapTargetEffect(), new TargetAnyTarget(), new UnattachCost(), new ManaCostsImpl<>("{1]{R}"), new TapSourceCost()
|
||||
)));
|
||||
|
||||
// Equipped creature get +3/+0 as long as its legendary.
|
||||
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
|
||||
new BoostEquippedEffect(3, 0), condition,
|
||||
"equipped creature get +3/+0 as long as it's legendary"
|
||||
)));
|
||||
|
||||
// Equip {1}{R}
|
||||
this.getRightHalfCard().addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl<>("{1}{R}")));
|
||||
}
|
||||
|
||||
private ToralfGodOfFury(final ToralfGodOfFury card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToralfGodOfFury copy() {
|
||||
return new ToralfGodOfFury(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ToralfGodOfFuryTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
ToralfGodOfFuryTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
}
|
||||
|
||||
private ToralfGodOfFuryTriggeredAbility(final ToralfGodOfFuryTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
switch (event.getType()) {
|
||||
case DAMAGED_CREATURE:
|
||||
case DAMAGED_PLANESWALKER:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
DamagedEvent dEvent = (DamagedEvent) event;
|
||||
if (dEvent.getExcess() < 1
|
||||
|| dEvent.isCombatDamage()
|
||||
|| !game.getOpponents(getControllerId()).contains(game.getControllerId(event.getTargetId()))) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().clear();
|
||||
this.getTargets().clear();
|
||||
this.addEffect(new DamageTargetEffect(dEvent.getExcess()));
|
||||
FilterCreaturePlayerOrPlaneswalker filter = new FilterCreaturePlayerOrPlaneswalker();
|
||||
filter.getPermanentFilter().add(Predicates.not(new MageObjectReferencePredicate(new MageObjectReference(event.getTargetId(), game))));
|
||||
this.addTarget(new TargetAnyTarget(filter));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToralfGodOfFuryTriggeredAbility copy() {
|
||||
return new ToralfGodOfFuryTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a creature or planeswalker an opponent controls is dealt excess noncombat damage, " +
|
||||
"{this} deals damage equal to the excess to any target other than that permanent.";
|
||||
}
|
||||
}
|
||||
|
||||
class ToralfsHammerEffect extends OneShotEffect {
|
||||
|
||||
ToralfsHammerEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
private ToralfsHammerEffect(final ToralfsHammerEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToralfsHammerEffect copy() {
|
||||
return new ToralfsHammerEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Object object = getValue("attachedPermanent");
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (!(object instanceof Permanent) || player == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = (Permanent) object;
|
||||
Permanent targetedPermanent = game.getPermanent(source.getFirstTarget());
|
||||
if (targetedPermanent == null) {
|
||||
Player targetedPlayer = game.getPlayer(source.getFirstTarget());
|
||||
if (targetedPlayer != null) {
|
||||
targetedPlayer.damage(3, permanent.getId(), source, game);
|
||||
}
|
||||
} else {
|
||||
targetedPermanent.damage(3, permanent.getId(), source, game);
|
||||
}
|
||||
player.moveCards(permanent, Zone.HAND, source, game);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
String name = "Toralf's Hammer";
|
||||
Object object = getValue("attachedPermanent");
|
||||
if (object instanceof Permanent) {
|
||||
name = ((Permanent) object).getName();
|
||||
}
|
||||
return "It deals 3 damage to any target. Return " + name + " to its owner's hand.";
|
||||
}
|
||||
}
|
|
@ -169,6 +169,7 @@ public final class Kaldheim extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("The Trickster-God's Heist", 232, Rarity.UNCOMMON, mage.cards.t.TheTricksterGodsHeist.class));
|
||||
cards.add(new SetCardInfo("The World Tree", 275, Rarity.RARE, mage.cards.t.TheWorldTree.class));
|
||||
cards.add(new SetCardInfo("Thornmantle Striker", 387, Rarity.UNCOMMON, mage.cards.t.ThornmantleStriker.class));
|
||||
cards.add(new SetCardInfo("Toralf, God of Fury", 154, Rarity.MYTHIC, mage.cards.t.ToralfGodOfFury.class));
|
||||
cards.add(new SetCardInfo("Toski, Bearer of Secrets", 197, Rarity.RARE, mage.cards.t.ToskiBearerOfSecrets.class));
|
||||
cards.add(new SetCardInfo("Tyvar Kell", 198, Rarity.MYTHIC, mage.cards.t.TyvarKell.class));
|
||||
cards.add(new SetCardInfo("Undersea Invader", 78, Rarity.COMMON, mage.cards.u.UnderseaInvader.class));
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
|
||||
|
||||
package mage.game.events;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class DamagedEvent extends GameEvent {
|
||||
|
||||
protected boolean combat;
|
||||
protected int excess;
|
||||
|
||||
public DamagedEvent(EventType type, UUID targetId, UUID attackerId, UUID playerId, int amount, boolean combat) {
|
||||
super(type, targetId, null, playerId, amount, false);
|
||||
this.combat = combat;
|
||||
this.excess = 0;
|
||||
this.setSourceId(attackerId);
|
||||
}
|
||||
|
||||
|
@ -26,4 +25,11 @@ public abstract class DamagedEvent extends GameEvent {
|
|||
return flag;
|
||||
}
|
||||
|
||||
public void setExcess(int excess) {
|
||||
this.excess = Math.max(excess, 0);
|
||||
}
|
||||
|
||||
public int getExcess() {
|
||||
return excess;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -853,7 +853,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
/**
|
||||
* @param damageAmount
|
||||
* @param attackerId id of the permanent or player who make damage (source.getSourceId() in most cases)
|
||||
* @param attackerId id of the permanent or player who make damage (source.getSourceId() in most cases)
|
||||
* @param source
|
||||
* @param game
|
||||
* @param preventable
|
||||
|
@ -975,53 +975,64 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
protected int damagePlaneswalker(int damage, UUID attackerId, Ability source, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
|
||||
GameEvent event = new DamagePlaneswalkerEvent(objectId, attackerId, controllerId, damage, preventable, combat);
|
||||
event.setAppliedEffects(appliedEffects);
|
||||
if (!game.replaceEvent(event)) {
|
||||
int actualDamage = checkProtectionAbilities(event, attackerId, source, game);
|
||||
if (actualDamage > 0) {
|
||||
int countersToRemove = actualDamage;
|
||||
if (countersToRemove > getCounters(game).getCount(CounterType.LOYALTY)) {
|
||||
countersToRemove = getCounters(game).getCount(CounterType.LOYALTY);
|
||||
}
|
||||
removeCounters(CounterType.LOYALTY.getName(), countersToRemove, source, game);
|
||||
DamagedEvent damagedEvent = new DamagedPlaneswalkerEvent(objectId, attackerId, controllerId, actualDamage, combat);
|
||||
game.fireEvent(damagedEvent);
|
||||
game.getState().addSimultaneousDamage(damagedEvent, game);
|
||||
return actualDamage;
|
||||
}
|
||||
if (game.replaceEvent(event)) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
int actualDamage = checkProtectionAbilities(event, attackerId, source, game);
|
||||
if (actualDamage <= 0) {
|
||||
return 0;
|
||||
}
|
||||
int countersToRemove = Math.min(actualDamage, getCounters(game).getCount(CounterType.LOYALTY));
|
||||
removeCounters(CounterType.LOYALTY.getName(), countersToRemove, source, game);
|
||||
DamagedEvent damagedEvent = new DamagedPlaneswalkerEvent(objectId, attackerId, controllerId, actualDamage, combat);
|
||||
damagedEvent.setExcess(actualDamage - countersToRemove);
|
||||
game.fireEvent(damagedEvent);
|
||||
game.getState().addSimultaneousDamage(damagedEvent, game);
|
||||
return actualDamage;
|
||||
}
|
||||
|
||||
protected int damageCreature(int damage, UUID attackerId, Ability source, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
|
||||
GameEvent event = new DamageCreatureEvent(this.getId(), attackerId, this.getControllerId(), damage, preventable, combat);
|
||||
event.setAppliedEffects(appliedEffects);
|
||||
if (!game.replaceEvent(event)) {
|
||||
int actualDamage = checkProtectionAbilities(event, attackerId, source, game);
|
||||
if (actualDamage > 0) {
|
||||
MageObject attacker = game.getObject(attackerId);
|
||||
if (attacker != null && (attacker.getAbilities().containsKey(InfectAbility.getInstance().getId())
|
||||
|| attacker.getAbilities().containsKey(WitherAbility.getInstance().getId()))) {
|
||||
if (markDamage) {
|
||||
// mark damage only
|
||||
markDamage(CounterType.M1M1.createInstance(actualDamage), attacker);
|
||||
} else {
|
||||
Ability damageSourceAbility = null;
|
||||
if (attacker instanceof Permanent) {
|
||||
damageSourceAbility = ((Permanent) attacker).getSpellAbility();
|
||||
}
|
||||
// deal damage immediately
|
||||
addCounters(CounterType.M1M1.createInstance(actualDamage), damageSourceAbility, game);
|
||||
}
|
||||
} else {
|
||||
this.damage = CardUtil.addWithOverflowCheck(this.damage, actualDamage);
|
||||
}
|
||||
DamagedEvent damagedEvent = new DamagedCreatureEvent(this.getId(), attackerId, this.getControllerId(), actualDamage, combat);
|
||||
game.fireEvent(damagedEvent);
|
||||
game.getState().addSimultaneousDamage(damagedEvent, game);
|
||||
return actualDamage;
|
||||
}
|
||||
if (game.replaceEvent(event)) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
int actualDamage = checkProtectionAbilities(event, attackerId, source, game);
|
||||
if (actualDamage <= 0) {
|
||||
return 0;
|
||||
}
|
||||
MageObject attacker = game.getObject(attackerId);
|
||||
int lethal = 0;
|
||||
if (game.getState().getActivePowerInsteadOfToughnessForDamageLethalityFilters().stream().anyMatch(f -> f.match(this, game))) {
|
||||
lethal = power.getValue();
|
||||
} else {
|
||||
lethal = toughness.getValue();
|
||||
}
|
||||
lethal = Math.max(lethal - this.damage, 0);
|
||||
if (attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())) {
|
||||
lethal = Math.min(1, lethal);
|
||||
}
|
||||
if (attacker != null && (attacker.getAbilities().containsKey(InfectAbility.getInstance().getId())
|
||||
|| attacker.getAbilities().containsKey(WitherAbility.getInstance().getId()))) {
|
||||
if (markDamage) {
|
||||
// mark damage only
|
||||
markDamage(CounterType.M1M1.createInstance(actualDamage), attacker);
|
||||
} else {
|
||||
Ability damageSourceAbility = null;
|
||||
if (attacker instanceof Permanent) {
|
||||
damageSourceAbility = ((Permanent) attacker).getSpellAbility();
|
||||
}
|
||||
// deal damage immediately
|
||||
addCounters(CounterType.M1M1.createInstance(actualDamage), damageSourceAbility, game);
|
||||
}
|
||||
} else {
|
||||
this.damage = CardUtil.addWithOverflowCheck(this.damage, actualDamage);
|
||||
}
|
||||
DamagedEvent damagedEvent = new DamagedCreatureEvent(this.getId(), attackerId, this.getControllerId(), actualDamage, combat);
|
||||
damagedEvent.setExcess(actualDamage - lethal);
|
||||
game.fireEvent(damagedEvent);
|
||||
game.getState().addSimultaneousDamage(damagedEvent, game);
|
||||
return actualDamage;
|
||||
}
|
||||
|
||||
private int checkProtectionAbilities(GameEvent event, UUID attackerId, Ability source, Game game) {
|
||||
|
@ -1211,6 +1222,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
/**
|
||||
* Simple event without source
|
||||
*
|
||||
* @param eventType
|
||||
* @param game
|
||||
*/
|
||||
|
@ -1220,6 +1232,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
|
||||
/**
|
||||
* Simple event without source
|
||||
*
|
||||
* @param eventType
|
||||
* @param game
|
||||
* @return
|
||||
|
|
Loading…
Reference in a new issue