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:
Evan Kranzler 2022-02-15 09:18:21 -05:00 committed by GitHub
parent 5725873aeb
commit 4591ac07cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 812 additions and 438 deletions

View file

@ -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" : "") + ", ";
}
}

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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 doesnt 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 cant 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;
}