forked from External/mage
Reworking goad effects (ready for review) (#8034)
* changing goad to designation, refactored goad effects to be continuous * [AFC] Implemented Vengeful Ancestor * reworked effects which goad an attached creature * updated goading implementation * updated combat with new goad logic * some more changes, added a test * another fix * update to test, still fails * added more failing tests * more failing tests * added additional goad check * small fix to two tests (still failing * added a regular combat test (passes and fails randomly) * fixed bug in computer player random selection * some changes to how TargetDefender is handled * removed unnecessary class * more combat fixes, tests pass now * removed tests which no longer work due to combat changes * small merge fix * [NEC] Implemented Komainu Battle Armor * [NEC] Implemented Kaima, the Fractured Calm * [NEC] added all variants
This commit is contained in:
parent
5725873aeb
commit
4591ac07cc
30 changed files with 812 additions and 438 deletions
|
|
@ -1,6 +1,5 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
|
|
@ -11,9 +10,11 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
|
@ -74,18 +75,15 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
getEffects().setValue("attacker", permanent);
|
||||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PLAYER:
|
||||
UUID playerId = controller ? permanent.getControllerId() : game.getCombat().getDefendingPlayerId(permanent.getId(), game);
|
||||
if (playerId != null) {
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(playerId));
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(playerId));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -101,10 +99,8 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever " + (filter.getMessage().startsWith("an") ? "" : "a ")
|
||||
+ filter.getMessage() + " attacks"
|
||||
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "")
|
||||
+ ", " ;
|
||||
return "Whenever " + CardUtil.addArticle(filter.getMessage()) + " attacks"
|
||||
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + ", ";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class GoadAttachedAbility extends StaticAbility {
|
||||
|
||||
public GoadAttachedAbility(Effect... effects) {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
for (Effect effect : effects) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
this.addEffect(new AttacksIfAbleAttachedEffect(
|
||||
Duration.WhileOnBattlefield, AttachmentType.AURA
|
||||
).setText((getEffects().size() > 1 ? ", " : " ") + "and is goaded. <i>(It attacks each combat if able"));
|
||||
this.addEffect(new GoadAttackEffect());
|
||||
}
|
||||
|
||||
private GoadAttachedAbility(final GoadAttachedAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoadAttachedAbility copy() {
|
||||
return new GoadAttachedAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GoadAttackEffect extends RestrictionEffect {
|
||||
|
||||
GoadAttackEffect() {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
staticText = "and attacks a player other than you if able.)</i>";
|
||||
}
|
||||
|
||||
private GoadAttackEffect(final GoadAttackEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoadAttackEffect copy() {
|
||||
return new GoadAttackEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
||||
return attachment != null && attachment.getAttachedTo() != null
|
||||
&& permanent.getId().equals(attachment.getAttachedTo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
|
||||
if (defenderId == null
|
||||
|| game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you
|
||||
return true;
|
||||
}
|
||||
// A planeswalker controlled by the controller is the defender
|
||||
if (game.getPermanent(defenderId) != null) {
|
||||
return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId());
|
||||
}
|
||||
// The controller is the defender
|
||||
return !defenderId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CantAttackControllerDueToGoadEffect extends RestrictionEffect {
|
||||
|
||||
public CantAttackControllerDueToGoadEffect(Duration duration) {
|
||||
super(duration);
|
||||
}
|
||||
|
||||
public CantAttackControllerDueToGoadEffect(final CantAttackControllerDueToGoadEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CantAttackControllerDueToGoadEffect copy() {
|
||||
return new CantAttackControllerDueToGoadEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return this.getTargetPointer().getTargets(game, source).contains(permanent.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
|
||||
if (defenderId == null
|
||||
|| game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you
|
||||
return true;
|
||||
}
|
||||
// A planeswalker controlled by the controller is the defender
|
||||
if (game.getPermanent(defenderId) != null) {
|
||||
return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId());
|
||||
}
|
||||
// The controller is the defender
|
||||
return !defenderId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class GoadAttachedEffect extends ContinuousEffectImpl {
|
||||
|
||||
public GoadAttachedEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment);
|
||||
staticText = "and is goaded";
|
||||
}
|
||||
|
||||
private GoadAttachedEffect(final GoadAttachedEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent attached = game.getPermanent(permanent.getAttachedTo());
|
||||
if (attached == null) {
|
||||
return false;
|
||||
}
|
||||
attached.addGoadingPlayer(source.getControllerId());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoadAttachedEffect copy() {
|
||||
return new GoadAttachedEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,19 @@ package mage.abilities.effects.common.combat;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class GoadTargetEffect extends OneShotEffect {
|
||||
public class GoadTargetEffect extends ContinuousEffectImpl {
|
||||
|
||||
/**
|
||||
* 701.36. Goad
|
||||
|
|
@ -24,10 +24,10 @@ public class GoadTargetEffect extends OneShotEffect {
|
|||
* each combat if able and attacks a player other than that player if able.
|
||||
*/
|
||||
public GoadTargetEffect() {
|
||||
super(Outcome.Detriment);
|
||||
super(Duration.UntilYourNextTurn, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment);
|
||||
}
|
||||
|
||||
public GoadTargetEffect(final GoadTargetEffect effect) {
|
||||
private GoadTargetEffect(final GoadTargetEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
|
@ -37,26 +37,22 @@ public class GoadTargetEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (targetCreature != null && controller != null) {
|
||||
// TODO: Allow goad to target controller, current AttacksIfAbleTargetEffect does not support it
|
||||
// https://github.com/magefree/mage/issues/5283
|
||||
/*
|
||||
If the creature doesn’t meet any of the above exceptions and can attack, it must attack a player other than
|
||||
the controller of the spell or ability that goaded it if able. If the creature can’t attack any of those
|
||||
players but could otherwise attack, it must attack an opposing planeswalker (controlled by any opponent)
|
||||
or the player that goaded it. (2016-08-23)
|
||||
*/
|
||||
ContinuousEffect effect = new AttacksIfAbleTargetEffect(Duration.UntilYourNextTurn);
|
||||
effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game));
|
||||
game.addEffect(effect, source);
|
||||
effect = new CantAttackControllerDueToGoadEffect(Duration.UntilYourNextTurn); // remember current controller
|
||||
effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game));
|
||||
game.addEffect(effect, source);
|
||||
game.informPlayers(controller.getLogName() + " is goading " + targetCreature.getLogName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (targetCreature == null) {
|
||||
return false;
|
||||
}
|
||||
targetCreature.addGoadingPlayer(source.getControllerId());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue