[KTK] Added Raid-, Prowess-, and Outlast ability. Added FerociousCondition.

This commit is contained in:
LevelX2 2014-09-01 19:28:06 +02:00
parent cb835f4f9b
commit 9b1388b322
12 changed files with 383 additions and 57 deletions

View file

@ -33,26 +33,19 @@ import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.combat.UnblockableTargetEffect; import mage.abilities.effects.common.combat.UnblockableTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.Filter; import mage.filter.Filter;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
/** /**
* *

View file

@ -69,11 +69,6 @@ public class RustScarab extends CardImpl {
} }
@Override
public void adjustTargets(Ability ability, Game game) {
}
public RustScarab(final RustScarab card) { public RustScarab(final RustScarab card) {
super(card); super(card);
} }

View file

@ -39,11 +39,9 @@ import mage.abilities.mana.WhiteManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.WatcherScope;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.watchers.common.PlayerAttackedWatcher;
import mage.watchers.Watcher;
/** /**
* *
@ -65,7 +63,7 @@ public class WindbriskHeights extends CardImpl {
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
this.addAbility(ability); this.addAbility(ability);
this.addWatcher(new WindbriskHeightsWatcher()); this.addWatcher(new PlayerAttackedWatcher());
} }
@ -79,41 +77,6 @@ public class WindbriskHeights extends CardImpl {
} }
} }
class WindbriskHeightsWatcher extends Watcher {
private int numberOfattackers;
public WindbriskHeightsWatcher() {
super("WindbriskHeightsAttackersWatcher", WatcherScope.PLAYER);
}
public WindbriskHeightsWatcher(final WindbriskHeightsWatcher watcher) {
super(watcher);
this.numberOfattackers = watcher.numberOfattackers;
}
@Override
public WindbriskHeightsWatcher copy() {
return new WindbriskHeightsWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.DECLARED_ATTACKERS && game.getActivePlayerId().equals(this.getControllerId())) {
numberOfattackers += game.getCombat().getAttackers().size(); // because there are more than one attack phase possible, sum up the attackers
if (numberOfattackers > 2) {
condition = true;
}
}
}
@Override
public void reset() {
super.reset();
numberOfattackers = 0;
}
}
class WindbriskHeightsAttackersCondition implements Condition { class WindbriskHeightsAttackersCondition implements Condition {
private static final WindbriskHeightsAttackersCondition fInstance = new WindbriskHeightsAttackersCondition(); private static final WindbriskHeightsAttackersCondition fInstance = new WindbriskHeightsAttackersCondition();
@ -124,8 +87,8 @@ class WindbriskHeightsAttackersCondition implements Condition {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Watcher watcher = game.getState().getWatchers().get("WindbriskHeightsAttackersWatcher", source.getControllerId()); PlayerAttackedWatcher watcher = (PlayerAttackedWatcher) game.getState().getWatchers().get("PlayerAttackedWatcher");
return watcher != null && watcher.conditionMet(); return watcher != null && watcher.getNumberOfAttackersCurrentTurn(source.getControllerId()) >= 3;
} }
@Override @Override

View file

@ -49,6 +49,7 @@ import mage.players.Player;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
import mage.constants.AbilityType;
import mage.constants.CostModificationType; import mage.constants.CostModificationType;
/** /**
@ -106,12 +107,14 @@ class AdjustingCostsAbility extends SimpleStaticAbility implements AdjustingSour
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void adjustCosts(Ability ability, Game game) {
if (ability.getAbilityType().equals(AbilityType.SPELL)) {
Player player = game.getPlayer(ability.getControllerId()); Player player = game.getPlayer(ability.getControllerId());
if (player != null && player.getLife() < 4) { if (player != null && player.getLife() < 4) {
CardUtil.adjustCost((SpellAbility)ability, 6); CardUtil.adjustCost((SpellAbility)ability, 6);
} }
} }
} }
}
class AdjustingCostsEffect extends CostModificationEffectImpl { class AdjustingCostsEffect extends CostModificationEffectImpl {

View file

@ -0,0 +1,81 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.abilityword;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.cards.Card;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.watchers.common.PlayerAttackedWatcher;
/**
*
* @author LevelX2
*/
public class RaidAbility extends TriggeredAbilityImpl {
public RaidAbility(Card card, Effect effect) {
this(card, effect, false);
}
public RaidAbility(Card card, Effect effect, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
card.addWatcher(new PlayerAttackedWatcher());
// this.setAbilityWord(AbilityWord.RAID); // not supported yet for rule generation
}
public RaidAbility(final RaidAbility ability) {
super(ability);
}
@Override
public RaidAbility copy() {
return new RaidAbility(this);
}
@Override
public boolean checkInterveningIfClause(Game game) {
// seems unneccessary to check twice because condition can't change until effect resolves, but who knows what the future brings
PlayerAttackedWatcher watcher = (PlayerAttackedWatcher) game.getState().getWatchers().get("PlayerAttackedWatcher");
return watcher != null && watcher.getNumberOfAttackersCurrentTurn(getControllerId()) > 0;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return EventType.ENTERS_THE_BATTLEFIELD.equals(event.getType()) && getSourceId().equals(event.getTargetId());
}
@Override
public String getRule() {
return "<i>Raid</i> - When {this} enters the battlefield, if you attacked with a creature this turn, " + super.getRule();
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.filter.Filter;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.Game;
/**
*
* @author LevelX2
*/
public class FerociousCondition implements Condition {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(new PowerPredicate(Filter.ComparisonType.GreaterThan, 3));
}
private static final FerociousCondition fInstance = new FerociousCondition();
private FerociousCondition() {};
public static FerociousCondition getInstance() {
return fInstance;
}
@Override
public boolean apply(Game game, Ability source) {
return game.getBattlefield().countAll(filter, source.getControllerId(), game) > 0;
}
}

View file

@ -70,7 +70,7 @@ public class ExileFromGraveCost extends CostImpl {
} }
public ExileFromGraveCost(ExileFromGraveCost cost) { public ExileFromGraveCost(final ExileFromGraveCost cost) {
super(cost); super(cost);
} }

View file

@ -22,6 +22,12 @@ public class AddManaToManaPoolEffect extends OneShotEffect {
protected Mana mana; protected Mana mana;
/**
* Adds mana to the mana pool of target pointer player
*
* @param mana mana that will be added to the pool
* @param textManaPoolOwner text that references to the mana pool owner (e.g. "damaged player's")
*/
public AddManaToManaPoolEffect(Mana mana, String textManaPoolOwner) { public AddManaToManaPoolEffect(Mana mana, String textManaPoolOwner) {
super(Outcome.PutManaInPool); super(Outcome.PutManaInPool);
this.mana = mana; this.mana = mana;

View file

@ -0,0 +1,67 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.keyword;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.counters.CounterType;
/**
*
* @author LevelX2
*/
public class OutlastAbility extends ActivatedAbilityImpl {
public OutlastAbility(Cost cost) {
super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), cost);
this.addCost(new TapSourceCost());
this.timing = TimingRule.SORCERY;
}
public OutlastAbility(final OutlastAbility ability) {
super(ability);
}
@Override
public OutlastAbility copy() {
return new OutlastAbility(this);
}
@Override
public String getRule() {
StringBuilder sb = new StringBuilder("Outcast ").append(manaCosts.getText());
sb.append(" <i>(").append(costs.getText()).append("{T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery.)</i>").toString();
return sb.toString();
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.keyword;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.common.continious.BoostSourceEffect;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
/**
*
* @author LevelX2
*/
public class ProwessAbility extends SpellCastControllerTriggeredAbility {
private static final FilterSpell filterNonCreatureSpell = new FilterSpell("noncreature spell");
static {
filterNonCreatureSpell.add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
}
public ProwessAbility() {
super(new BoostSourceEffect(1,1,Duration.EndOfTurn), false);
this.filter = filterNonCreatureSpell;
}
public ProwessAbility(final ProwessAbility ability) {
super(ability);
}
@Override
public String getRule() {
return "Prowess <i>(Whenever you cast a noncreature spell, this creature gets +1/+1 until end of turn.)</i>";
}
@Override
public ProwessAbility copy() {
return new ProwessAbility(this);
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.watchers.common;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
/**
*
* @author LevelX2
*/
public class PlayerAttackedWatcher extends Watcher {
// With how many creatures attacked this player this turn
private final Map<UUID,Integer> playerAttacked = new HashMap<>();
public PlayerAttackedWatcher() {
super("PlayerAttackedWatcher", WatcherScope.GAME);
}
public PlayerAttackedWatcher(final PlayerAttackedWatcher watcher) {
super(watcher);
for (Map.Entry<UUID,Integer> entry: playerAttacked.entrySet()) {
this.playerAttacked.put(entry.getKey(), entry.getValue());
}
}
@Override
public PlayerAttackedWatcher copy() {
return new PlayerAttackedWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.DECLARED_ATTACKERS) {
int numberAttackers = playerAttacked.containsKey(event.getPlayerId()) ? playerAttacked.get(event.getPlayerId()) : 0;
playerAttacked.put(event.getPlayerId(), numberAttackers + game.getCombat().getAttackers().size());
}
}
@Override
public void reset() {
super.reset();
playerAttacked.clear();
}
public int getNumberOfAttackersCurrentTurn(UUID playerId) {
return playerAttacked.containsKey(playerId) ? playerAttacked.get(playerId) : 0;
}
}

View file

@ -8,6 +8,7 @@ Cascade|new|
Cumulative upkeep|cost| Cumulative upkeep|cost|
Cycling|cost| Cycling|cost|
Deathtouch|instance| Deathtouch|instance|
Delve|new|
Dethrone|new| Dethrone|new|
Defender|instance| Defender|instance|
Double Strike|instance| Double Strike|instance|
@ -38,11 +39,13 @@ Miracle|cost|
Mountaincycling|cost| Mountaincycling|cost|
Mountainwalk|new| Mountainwalk|new|
Morph|card, cost| Morph|card, cost|
Outlast|cost|
Persist|new| Persist|new|
Phasing|instance| Phasing|instance|
Plainscycling|cost| Plainscycling|cost|
Plainswalk|new| Plainswalk|new|
Provoke|new| Provoke|new|
Prowess|new|
Reach|instance| Reach|instance|
Rebound|new| Rebound|new|
Scavenge|cost| Scavenge|cost|