mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 12:31:59 -08:00
Merge pull request #5580 from magefree/5497-dynamic-hints-for-cards
UI: Add dynamic hints for cards
This commit is contained in:
commit
c52a3c8a48
215 changed files with 1840 additions and 1137 deletions
|
|
@ -8,6 +8,7 @@ import mage.abilities.costs.mana.ManaCost;
|
|||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.AbilityWord;
|
||||
import mage.constants.EffectType;
|
||||
|
|
@ -525,4 +526,8 @@ public interface Ability extends Controllable, Serializable {
|
|||
CostAdjuster getCostAdjuster();
|
||||
|
||||
void adjustCosts(Game game);
|
||||
|
||||
List<Hint> getHints();
|
||||
|
||||
Ability addHint(Hint hint);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import mage.abilities.effects.Effects;
|
|||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ManaEffect;
|
||||
import mage.abilities.effects.mana.DynamicManaEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.SplitCard;
|
||||
|
|
@ -73,6 +74,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected boolean canFizzle = true;
|
||||
protected TargetAdjuster targetAdjuster = null;
|
||||
protected CostAdjuster costAdjuster = null;
|
||||
protected List<Hint> hints = new ArrayList<>();
|
||||
|
||||
public AbilityImpl(AbilityType abilityType, Zone zone) {
|
||||
this.id = UUID.randomUUID();
|
||||
|
|
@ -120,6 +122,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
this.canFizzle = ability.canFizzle;
|
||||
this.targetAdjuster = ability.targetAdjuster;
|
||||
this.costAdjuster = ability.costAdjuster;
|
||||
for (Hint hint : ability.getHints()) {
|
||||
this.hints.add(hint.copy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -256,7 +261,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
if (modes.getAdditionalCost() != null) {
|
||||
((OptionalAdditionalModeSourceCosts) modes.getAdditionalCost()).addOptionalAdditionalModeCosts(this, game);
|
||||
modes.getAdditionalCost().addOptionalAdditionalModeCosts(this, game);
|
||||
}
|
||||
// 20130201 - 601.2b
|
||||
// If the spell has alternative or additional costs that will be paid as it's being cast such
|
||||
|
|
@ -952,9 +957,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
} else if (!object.getAbilities().contains(this)) {
|
||||
// check if it's an ability that is temporary gained to a card
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId());
|
||||
if (otherAbilities == null || !otherAbilities.contains(this)) {
|
||||
return false;
|
||||
}
|
||||
return otherAbilities != null && otherAbilities.contains(this);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1243,4 +1246,15 @@ public abstract class AbilityImpl implements Ability {
|
|||
costAdjuster.adjustCosts(this, game);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Hint> getHints() {
|
||||
return this.hints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ability addHint(Hint hint) {
|
||||
this.hints.add(hint);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,11 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.CardType;
|
||||
import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public enum DeliriumCondition implements Condition {
|
||||
|
|
@ -20,15 +14,7 @@ public enum DeliriumCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
EnumSet<CardType> foundCardTypes = EnumSet.noneOf(CardType.class);
|
||||
for (Card card : controller.getGraveyard().getCards(game)) {
|
||||
foundCardTypes.addAll(card.getCardType());
|
||||
}
|
||||
return foundCardTypes.size() >= 4;
|
||||
}
|
||||
return false;
|
||||
return CardTypesInGraveyardCount.instance.calculate(game, source, null) >= 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.dynamicvalue.common.OpponentsLostLifeCount;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum OpponentsLostLifeCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return OpponentsLostLifeCount.instance.calculate(game, source.getControllerId()) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "opponents lost life";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.CardType;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum CardTypesInGraveyardCount implements DynamicValue {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
Player controller = game.getPlayer(sourceAbility.getControllerId());
|
||||
if (controller != null) {
|
||||
EnumSet<CardType> foundCardTypes = EnumSet.noneOf(CardType.class);
|
||||
for (Card card : controller.getGraveyard().getCards(game)) {
|
||||
foundCardTypes.addAll(card.getCardType());
|
||||
}
|
||||
return foundCardTypes.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardTypesInGraveyardCount copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "the number of opponents you attacked this turn";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum CreaturesYouControlCount implements DynamicValue {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURES, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreaturesYouControlCount copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "creatures you control";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum GateYouControlCount implements DynamicValue {
|
||||
|
||||
instance;
|
||||
private static final FilterPermanent filter = new FilterControlledPermanent("Gate you control");
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate(SubType.GATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GateYouControlCount copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "gate you control";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
|
||||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.PlayerLostLifeWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class OpponentsLostLifeCount implements DynamicValue {
|
||||
public enum OpponentsLostLifeCount implements DynamicValue {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
|
|
@ -29,7 +30,7 @@ public class OpponentsLostLifeCount implements DynamicValue {
|
|||
|
||||
@Override
|
||||
public OpponentsLostLifeCount copy() {
|
||||
return new OpponentsLostLifeCount();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.abilities.effects;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.EffectType;
|
||||
|
|
@ -9,8 +7,9 @@ import mage.constants.Outcome;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class RestrictionEffect extends ContinuousEffectImpl {
|
||||
|
|
@ -39,6 +38,13 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attacker
|
||||
* @param defenderId id of planeswalker or player to attack, can be empty for general checks
|
||||
* @param source
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -47,6 +53,13 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attacker can be empty for general checks
|
||||
* @param blocker
|
||||
* @param source
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -32,6 +30,9 @@ public class CanBlockOnlyFlyingAttachedEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (attacker == null) {
|
||||
return true;
|
||||
}
|
||||
return attacker.getAbilities().contains(FlyingAbility.getInstance());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -10,7 +8,6 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
|
@ -33,6 +30,9 @@ public class CanBlockOnlyFlyingEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (attacker == null) {
|
||||
return true;
|
||||
}
|
||||
return attacker.getAbilities().contains(FlyingAbility.getInstance());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.AttachmentType;
|
||||
|
|
@ -10,9 +7,10 @@ import mage.constants.Duration;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
|
@ -34,6 +32,10 @@ public class CantAttackControllerAttachedEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (defenderId.equals(source.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.Duration;
|
||||
|
|
@ -11,8 +8,9 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BursegSardaukar
|
||||
*/
|
||||
|
||||
|
|
@ -38,6 +36,10 @@ public class CantAttackIfDefenderControlsPermanent extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UUID defendingPlayerId;
|
||||
Player player = game.getPlayer(defenderId);
|
||||
if (player == null) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
|
||||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.Duration;
|
||||
|
|
@ -11,8 +8,9 @@ import mage.game.Game;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
|
|
@ -38,6 +36,10 @@ public class CantAttackUnlessDefenderControllsPermanent extends RestrictionEffec
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UUID defendingPlayerId;
|
||||
Player player = game.getPlayer(defenderId);
|
||||
if (player == null) {
|
||||
|
|
@ -50,10 +52,7 @@ public class CantAttackUnlessDefenderControllsPermanent extends RestrictionEffec
|
|||
} else {
|
||||
defendingPlayerId = defenderId;
|
||||
}
|
||||
if (defendingPlayerId != null && game.getBattlefield().countAll(filter, defendingPlayerId, game) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return defendingPlayerId == null || game.getBattlefield().countAll(filter, defendingPlayerId, game) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -13,7 +12,6 @@ import mage.game.permanent.Permanent;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CantAttackYouAllEffect extends RestrictionEffect {
|
||||
|
|
@ -51,6 +49,9 @@ public class CantAttackYouAllEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
if (alsoPlaneswalker) {
|
||||
Permanent planeswalker = game.getPermanent(defenderId);
|
||||
if (planeswalker != null) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
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;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CantAttackYouEffect extends RestrictionEffect {
|
||||
|
|
@ -34,6 +33,9 @@ public class CantAttackYouEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
return !defenderId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.Duration;
|
||||
|
|
@ -10,8 +8,9 @@ import mage.filter.common.FilterCreaturePermanent;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public class CantAttackYouOrPlaneswalkerAllEffect extends RestrictionEffect {
|
||||
|
|
@ -40,6 +39,10 @@ public class CantAttackYouOrPlaneswalkerAllEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (defenderId.equals(source.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
|
||||
package mage.abilities.effects.common.combat;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.Duration;
|
||||
import static mage.constants.Duration.EndOfTurn;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import static mage.constants.Duration.EndOfTurn;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public class CantBlockAttachedEffect extends RestrictionEffect {
|
||||
|
|
@ -70,6 +69,9 @@ public class CantBlockAttachedEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (attacker == null) {
|
||||
return true;
|
||||
}
|
||||
return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ public class CantBlockCreaturesSourceEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (attacker == null) {
|
||||
return true;
|
||||
}
|
||||
return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game);
|
||||
}
|
||||
|
||||
|
|
|
|||
59
Mage/src/main/java/mage/abilities/hint/ConditionHint.java
Normal file
59
Mage/src/main/java/mage/abilities/hint/ConditionHint.java
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package mage.abilities.hint;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class ConditionHint implements Hint {
|
||||
|
||||
private Condition condition;
|
||||
private String trueText;
|
||||
private Color trueColor;
|
||||
private String falseText;
|
||||
private Color falseColor;
|
||||
private Boolean useIcons;
|
||||
|
||||
public ConditionHint(Condition condition, String textWithIcons) {
|
||||
this(condition, textWithIcons, null, textWithIcons, null, true);
|
||||
}
|
||||
|
||||
public ConditionHint(Condition condition, String trueText, Color trueColor, String falseText, Color falseColor, Boolean useIcons) {
|
||||
this.condition = condition;
|
||||
this.trueText = trueText;
|
||||
this.trueColor = trueColor;
|
||||
this.falseText = falseText;
|
||||
this.falseColor = falseColor;
|
||||
this.useIcons = useIcons;
|
||||
}
|
||||
|
||||
private ConditionHint(final ConditionHint hint) {
|
||||
this.condition = hint.condition;
|
||||
this.trueText = hint.trueText;
|
||||
this.trueColor = hint.trueColor;
|
||||
this.falseText = hint.falseText;
|
||||
this.falseColor = hint.falseColor;
|
||||
this.useIcons = hint.useIcons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
String icon;
|
||||
if (condition.apply(game, ability)) {
|
||||
icon = this.useIcons ? HintUtils.HINT_ICON_GOOD : null;
|
||||
return HintUtils.prepareText(this.trueText, this.trueColor, icon);
|
||||
} else {
|
||||
icon = this.useIcons ? HintUtils.HINT_ICON_BAD : null;
|
||||
return HintUtils.prepareText(this.falseText, this.falseColor, icon);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return new ConditionHint(this);
|
||||
}
|
||||
}
|
||||
16
Mage/src/main/java/mage/abilities/hint/Hint.java
Normal file
16
Mage/src/main/java/mage/abilities/hint/Hint.java
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package mage.abilities.hint;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public interface Hint extends Serializable {
|
||||
|
||||
String getText(Game game, Ability ability);
|
||||
|
||||
Hint copy();
|
||||
}
|
||||
56
Mage/src/main/java/mage/abilities/hint/HintUtils.java
Normal file
56
Mage/src/main/java/mage/abilities/hint/HintUtils.java
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package mage.abilities.hint;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class HintUtils {
|
||||
|
||||
public static final boolean ABILITY_HINTS_ENABLE = true;
|
||||
public static final boolean RESTRICT_HINTS_ENABLE = true;
|
||||
|
||||
// icons changes to real files on client side (see mana icons replacement)
|
||||
public static final String HINT_ICON_GOOD = "ICON_GOOD";
|
||||
public static final String HINT_ICON_BAD = "ICON_BAD";
|
||||
public static final String HINT_ICON_RESTRICT = "ICON_RESTRICT";
|
||||
|
||||
//
|
||||
public static final String HINT_START_MARK = "<br/><hintstart/>"; // workaround to find hint text in rules list and shows it in html
|
||||
|
||||
public static String prepareText(String text, Color color) {
|
||||
return prepareText(text, color, null);
|
||||
}
|
||||
|
||||
public static String prepareText(String text, Color color, String icon) {
|
||||
String res;
|
||||
|
||||
// text
|
||||
if (text != null && color != null) {
|
||||
String hex = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getGreen());
|
||||
res = String.format("<font color=%s>%s</font>", hex, text);
|
||||
} else {
|
||||
res = text;
|
||||
}
|
||||
|
||||
// icon
|
||||
if (res != null && icon != null) {
|
||||
res = icon + res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void appendHints(List<String> destList, List<String> newHints) {
|
||||
// append only unique hints
|
||||
HashSet<String> used = new HashSet<>();
|
||||
for (String s : newHints) {
|
||||
if (!used.contains(s)) {
|
||||
destList.add(s);
|
||||
used.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Mage/src/main/java/mage/abilities/hint/StaticHint.java
Normal file
36
Mage/src/main/java/mage/abilities/hint/StaticHint.java
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package mage.abilities.hint;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class StaticHint implements Hint {
|
||||
|
||||
private String text;
|
||||
|
||||
public StaticHint(String text) {
|
||||
this(text, null);
|
||||
}
|
||||
|
||||
public StaticHint(String text, Color color) {
|
||||
this.text = HintUtils.prepareText(text, color);
|
||||
}
|
||||
|
||||
private StaticHint(final StaticHint hint) {
|
||||
this.text = hint.text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return new StaticHint(this);
|
||||
}
|
||||
}
|
||||
34
Mage/src/main/java/mage/abilities/hint/ValueHint.java
Normal file
34
Mage/src/main/java/mage/abilities/hint/ValueHint.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package mage.abilities.hint;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class ValueHint implements Hint {
|
||||
|
||||
private String name;
|
||||
private DynamicValue value;
|
||||
|
||||
public ValueHint(String name, DynamicValue value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private ValueHint(final ValueHint hint) {
|
||||
this.name = hint.name;
|
||||
this.value = hint.value.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return name + ": " + value.calculate(game, ability, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return new ValueHint(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.CitysBlessingCondition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum CitysBlessingHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final ConditionHint hint = new ConditionHint(CitysBlessingCondition.instance, "You have city's blessing");
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.common.CreaturesYouControlCount;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum CreaturesYouControlHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final Hint hint = new ValueHint("Creatures you control", CreaturesYouControlCount.instance);
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.DeliriumCondition;
|
||||
import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum DeliriumHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final ConditionHint hint = new ConditionHint(DeliriumCondition.instance, "4+ card types in your graveyard");
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability) + " (current: " + CardTypesInGraveyardCount.instance.calculate(game, ability, null) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.FerociousCondition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum FerociousHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final ConditionHint hint = new ConditionHint(FerociousCondition.instance, "You control a creature with power 4+");
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.common.GateYouControlCount;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum GateYouControlHint implements Hint {
|
||||
|
||||
instance;
|
||||
|
||||
private static final Hint hint = new ValueHint("Gate you control", GateYouControlCount.instance);
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.OpponentsLostLifeCondition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum SpectacleHint implements Hint {
|
||||
|
||||
instance;
|
||||
private static final ConditionHint hint = new ConditionHint(OpponentsLostLifeCondition.instance, "Opponents lost life this turn");
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.EvasionAbility;
|
||||
import mage.abilities.MageSingleton;
|
||||
|
|
@ -10,6 +9,8 @@ import mage.constants.Duration;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
/**
|
||||
* "Shadow" keyword
|
||||
*
|
||||
|
|
@ -60,6 +61,9 @@ class ShadowEffect extends RestrictionEffect implements MageSingleton {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (attacker == null) {
|
||||
return true;
|
||||
}
|
||||
return attacker.getAbilities().containsKey(ShadowAbility.getInstance().getId());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.EvasionAbility;
|
||||
import mage.abilities.MageSingleton;
|
||||
|
|
@ -10,8 +8,9 @@ import mage.constants.Duration;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class SpaceflightAbility extends EvasionAbility implements MageSingleton {
|
||||
|
|
@ -59,6 +58,9 @@ class SpaceFlightEffect extends RestrictionEffect implements MageSingleton {
|
|||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (attacker == null) {
|
||||
return true;
|
||||
}
|
||||
return attacker.getAbilities().containsKey(SpaceflightAbility.getInstance().getId());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.dynamicvalue.common.OpponentsLostLifeCount;
|
||||
import mage.abilities.hint.common.SpectacleHint;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.PlayerLostLifeWatcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
|
@ -31,6 +31,7 @@ public class SpectacleAbility extends SpellAbility {
|
|||
this.setRuleAtTheTop(true);
|
||||
this.rule = "Spectacle " + spectacleCosts.getText()
|
||||
+ " <i>(You may cast this spell for its spectacle cost rather than its mana cost if an opponent lost life this turn.)</i>";
|
||||
this.addHint(SpectacleHint.instance);
|
||||
}
|
||||
|
||||
public SpectacleAbility(final SpectacleAbility ability) {
|
||||
|
|
@ -40,8 +41,7 @@ public class SpectacleAbility extends SpellAbility {
|
|||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class);
|
||||
if (watcher != null && watcher.getAllOppLifeLost(playerId, game) > 0) {
|
||||
if (OpponentsLostLifeCount.instance.calculate(game, playerId) > 0) {
|
||||
return super.canActivate(playerId, game);
|
||||
}
|
||||
return ActivationStatus.getFalse();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import mage.MageObjectImpl;
|
|||
import mage.Mana;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.HintUtils;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.cards.repository.PluginClassloaderRegistery;
|
||||
import mage.constants.*;
|
||||
|
|
@ -243,6 +245,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
try {
|
||||
List<String> rules = getRules();
|
||||
if (game != null) {
|
||||
// debug state
|
||||
CardState cardState = game.getState().getCardState(objectId);
|
||||
if (cardState != null) {
|
||||
for (String data : cardState.getInfo().values()) {
|
||||
|
|
@ -252,6 +255,27 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
rules.add(ability.getRule());
|
||||
}
|
||||
}
|
||||
|
||||
// ability hints
|
||||
List<String> abilityHints = new ArrayList<>();
|
||||
if (HintUtils.ABILITY_HINTS_ENABLE) {
|
||||
for (Ability ability : abilities) {
|
||||
for (Hint hint : ability.getHints()) {
|
||||
String s = hint.getText(game, ability);
|
||||
if (s != null && !s.isEmpty()) {
|
||||
abilityHints.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restrict hints only for permanents, not cards
|
||||
|
||||
// total hints
|
||||
if (!abilityHints.isEmpty()) {
|
||||
rules.add(HintUtils.HINT_START_MARK);
|
||||
HintUtils.appendHints(rules, abilityHints);
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
} catch (Exception e) {
|
||||
|
|
@ -486,7 +510,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
}
|
||||
}
|
||||
if (lkiObject != null) {
|
||||
removed = game.getState().getCommand().remove((CommandObject) lkiObject);
|
||||
removed = game.getState().getCommand().remove(lkiObject);
|
||||
}
|
||||
break;
|
||||
case OUTSIDE:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
|
||||
package mage.game.command.planes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.ActivateIfConditionActivatedAbility;
|
||||
|
|
@ -33,8 +29,11 @@ import mage.target.Target;
|
|||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.watchers.common.PlanarRollWatcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class AgyremPlane extends Plane {
|
||||
|
|
@ -152,6 +151,10 @@ class AgyremRestrictionEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Plane cPlane = game.getState().getCurrentPlane();
|
||||
if (cPlane != null && cPlane.getName().equalsIgnoreCase("Plane - Agyrem")) {
|
||||
return !defenderId.equals(source.getControllerId());
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.HintUtils;
|
||||
import mage.abilities.keyword.*;
|
||||
import mage.abilities.text.TextPart;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -236,17 +238,83 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
public List<String> getRules(Game game) {
|
||||
try {
|
||||
List<String> rules = getRules();
|
||||
|
||||
// info
|
||||
if (info != null) {
|
||||
for (String data : info.values()) {
|
||||
rules.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
// ability hints
|
||||
List<String> abilityHints = new ArrayList<>();
|
||||
if (HintUtils.ABILITY_HINTS_ENABLE) {
|
||||
for (Ability ability : abilities) {
|
||||
for (Hint hint : ability.getHints()) {
|
||||
String s = hint.getText(game, ability);
|
||||
if (s != null && !s.isEmpty()) {
|
||||
abilityHints.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restrict hints
|
||||
List<String> restrictHints = new ArrayList<>();
|
||||
if (HintUtils.RESTRICT_HINTS_ENABLE) {
|
||||
for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
|
||||
for (Ability ability : entry.getValue()) {
|
||||
if (!entry.getKey().applies(this, ability, game)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entry.getKey().canAttack(game) || !entry.getKey().canAttack(this, null, ability, game)) {
|
||||
restrictHints.add(HintUtils.prepareText("Can't attack" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
|
||||
}
|
||||
|
||||
if (!entry.getKey().canBlock(null, this, ability, game)) {
|
||||
restrictHints.add(HintUtils.prepareText("Can't block" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
|
||||
}
|
||||
|
||||
if (!entry.getKey().canBeUntapped(this, ability, game)) {
|
||||
restrictHints.add(HintUtils.prepareText("Can't untapped" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
|
||||
}
|
||||
|
||||
if (!entry.getKey().canUseActivatedAbilities(this, ability, game)) {
|
||||
restrictHints.add(HintUtils.prepareText("Can't use activated abilities" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
|
||||
}
|
||||
|
||||
if (!entry.getKey().canTransform(this, ability, game)) {
|
||||
restrictHints.add(HintUtils.prepareText("Can't transform" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT));
|
||||
}
|
||||
}
|
||||
}
|
||||
restrictHints.sort(String::compareTo);
|
||||
}
|
||||
|
||||
// total hints
|
||||
if (!abilityHints.isEmpty() || !restrictHints.isEmpty()) {
|
||||
rules.add(HintUtils.HINT_START_MARK);
|
||||
HintUtils.appendHints(rules, abilityHints);
|
||||
HintUtils.appendHints(rules, restrictHints);
|
||||
}
|
||||
|
||||
return rules;
|
||||
} catch (Exception e) {
|
||||
return rulesError;
|
||||
}
|
||||
}
|
||||
|
||||
private String addSourceObjectName(Game game, Ability ability) {
|
||||
if (ability != null) {
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
if (object != null) {
|
||||
return " (" + object.getIdName() + ")";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities() {
|
||||
return abilities;
|
||||
|
|
@ -477,7 +545,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
public boolean phaseIn(Game game, boolean onlyDirect) {
|
||||
if (!phasedIn) {
|
||||
if (!replaceEvent(EventType.PHASE_IN, game)
|
||||
&& ((onlyDirect && !indirectPhase) || (!onlyDirect))) {
|
||||
&& (!onlyDirect || !indirectPhase)) {
|
||||
this.phasedIn = true;
|
||||
this.indirectPhase = false;
|
||||
if (!game.isSimulation()) {
|
||||
|
|
@ -768,7 +836,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
sourceControllerId = ((Card) source).getOwnerId();
|
||||
} else if (source instanceof CommandObject) {
|
||||
sourceControllerId = ((CommandObject) source).getControllerId();
|
||||
sourceAbilities = ((CommandObject) source).getAbilities();
|
||||
sourceAbilities = source.getAbilities();
|
||||
} else {
|
||||
source = null;
|
||||
}
|
||||
|
|
@ -969,9 +1037,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
// needed to get the correct possible targets if target rule modification effects are active
|
||||
// e.g. Fiendslayer Paladin tried to target with Ultimate Price
|
||||
if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(EventType.TARGET, this.getId(), source.getId(), sourceControllerId), null, game, true)) {
|
||||
return false;
|
||||
}
|
||||
return !game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(EventType.TARGET, this.getId(), source.getId(), sourceControllerId), null, game, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.dynamicvalue.common.CreaturesYouControlCount;
|
||||
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class VoiceOfResurgenceToken extends TokenImpl {
|
||||
|
|
@ -28,8 +25,9 @@ public final class VoiceOfResurgenceToken extends TokenImpl {
|
|||
power = new MageInt(0);
|
||||
toughness = new MageInt(0);
|
||||
|
||||
// This creature's power and toughness are each equal to the number of creatures you control.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(
|
||||
new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame)));
|
||||
CreaturesYouControlCount.instance, Duration.EndOfGame)));
|
||||
}
|
||||
|
||||
public VoiceOfResurgenceToken(final VoiceOfResurgenceToken token) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import mage.abilities.costs.mana.ManaCosts;
|
|||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.text.TextPart;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.FrameStyle;
|
||||
|
|
@ -647,4 +648,15 @@ public class StackAbility extends StackObjImpl implements Ability {
|
|||
costAdjuster.adjustCosts(this, game);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Hint> getHints() {
|
||||
return this.ability.getHints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ability addHint(Hint hint) {
|
||||
// only abilities supports addhint
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
package mage.players;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import mage.ConditionalMana;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
|
|
@ -69,6 +65,11 @@ import mage.util.GameLog;
|
|||
import mage.util.RandomUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public abstract class PlayerImpl implements Player, Serializable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PlayerImpl.class);
|
||||
|
|
@ -1422,10 +1423,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
!= null
|
||||
// if anyone sees an issue with this code, please report it. Worked in my testing.
|
||||
|| game.getContinuousEffects().asThough(object.getId(),
|
||||
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
|
||||
ability,
|
||||
this.getId(),
|
||||
game)
|
||||
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
|
||||
ability,
|
||||
this.getId(),
|
||||
game)
|
||||
!= null) {
|
||||
if (canUse
|
||||
|| ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||
|
|
@ -2527,7 +2528,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
for (Card card : library.getCards(game)) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability.getClass() == WhileSearchingPlayFromLibraryAbility.class) {
|
||||
libraryCastableCardTracker.put(card.getId(), card.getName() + " [" + card.getId().toString().substring(0, 3) + "]");
|
||||
libraryCastableCardTracker.put(card.getId(), card.getIdName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2636,7 +2637,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
/**
|
||||
* @param game
|
||||
* @param appliedEffects
|
||||
* @param numSides Number of sides the dice has
|
||||
* @param numSides Number of sides the dice has
|
||||
* @return the number that the player rolled
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -2670,10 +2671,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
/**
|
||||
* @param game
|
||||
* @param appliedEffects
|
||||
* @param numberChaosSides The number of chaos sides the planar die
|
||||
* currently has (normally 1 but can be 5)
|
||||
* @param numberChaosSides The number of chaos sides the planar die
|
||||
* currently has (normally 1 but can be 5)
|
||||
* @param numberPlanarSides The number of chaos sides the planar die
|
||||
* currently has (normally 1)
|
||||
* currently has (normally 1)
|
||||
* @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll
|
||||
* or NilRoll
|
||||
*/
|
||||
|
|
@ -2830,7 +2831,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
/**
|
||||
* @param ability
|
||||
* @param available if null, it won't be checked if enough mana is available
|
||||
* @param available if null, it won't be checked if enough mana is available
|
||||
* @param sourceObject
|
||||
* @param game
|
||||
* @return
|
||||
|
|
@ -3380,7 +3381,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId,
|
||||
UUID controllerId, Game game
|
||||
UUID controllerId, Game game
|
||||
) {
|
||||
return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game);
|
||||
}
|
||||
|
|
@ -3528,8 +3529,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCards(Card card, Zone toZone,
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
) {
|
||||
Set<Card> cardList = new HashSet<>();
|
||||
if (card != null) {
|
||||
|
|
@ -3540,22 +3541,22 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCards(Cards cards, Zone toZone,
|
||||
Ability source, Game game
|
||||
Ability source, Game game
|
||||
) {
|
||||
return moveCards(cards.getCards(game), toZone, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone,
|
||||
Ability source, Game game
|
||||
Ability source, Game game
|
||||
) {
|
||||
return moveCards(cards, toZone, source, game, false, false, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCards(Set<Card> cards, Zone toZone,
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
Ability source, Game game,
|
||||
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
|
||||
) {
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
|
|
@ -3641,8 +3642,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardsToExile(Card card, Ability source,
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
) {
|
||||
Set<Card> cards = new HashSet<>();
|
||||
cards.add(card);
|
||||
|
|
@ -3651,8 +3652,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardsToExile(Set<Card> cards, Ability source,
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
Game game, boolean withName, UUID exileId,
|
||||
String exileZoneName
|
||||
) {
|
||||
if (cards.isEmpty()) {
|
||||
return true;
|
||||
|
|
@ -3667,14 +3668,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
|
||||
Game game
|
||||
Game game
|
||||
) {
|
||||
return this.moveCardToHandWithInfo(card, sourceId, game, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
|
||||
Game game, boolean withName
|
||||
Game game, boolean withName
|
||||
) {
|
||||
boolean result = false;
|
||||
Zone fromZone = game.getState().getZone(card.getId());
|
||||
|
|
@ -3699,7 +3700,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source,
|
||||
Game game, Zone fromZone
|
||||
Game game, Zone fromZone
|
||||
) {
|
||||
UUID sourceId = source == null ? null : source.getSourceId();
|
||||
Set<Card> movedCards = new LinkedHashSet<>();
|
||||
|
|
@ -3707,7 +3708,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
// identify cards from one owner
|
||||
Cards cards = new CardsImpl();
|
||||
UUID ownerId = null;
|
||||
for (Iterator<Card> it = allCards.iterator(); it.hasNext();) {
|
||||
for (Iterator<Card> it = allCards.iterator(); it.hasNext(); ) {
|
||||
Card card = it.next();
|
||||
if (cards.isEmpty()) {
|
||||
ownerId = card.getOwnerId();
|
||||
|
|
@ -3768,7 +3769,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId,
|
||||
Game game, Zone fromZone
|
||||
Game game, Zone fromZone
|
||||
) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
|
|
@ -3797,8 +3798,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId,
|
||||
Game game, Zone fromZone,
|
||||
boolean toTop, boolean withName
|
||||
Game game, Zone fromZone,
|
||||
boolean toTop, boolean withName
|
||||
) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
|
|
@ -3832,7 +3833,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
@Override
|
||||
public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId,
|
||||
Game game, Zone fromZone, boolean withName) {
|
||||
Game game, Zone fromZone, boolean withName) {
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
|
||||
package mage.util;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class GameLog {
|
||||
|
|
@ -40,11 +38,11 @@ public final class GameLog {
|
|||
}
|
||||
|
||||
public static String getColoredObjectIdName(MageObject mageObject) {
|
||||
return "<font color=\'" + getColorName(mageObject.getColor(null)) + "\'>" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]</font>";
|
||||
return "<font color=\'" + getColorName(mageObject.getColor(null)) + "\'>" + mageObject.getIdName() + "</font>";
|
||||
}
|
||||
|
||||
public static String getColoredObjectIdNameForTooltip(MageObject mageObject) {
|
||||
return "<font color=\'" + getTooltipColorName(mageObject.getColor(null)) + "\'>" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]</font>";
|
||||
return "<font color=\'" + getTooltipColorName(mageObject.getColor(null)) + "\'>" + mageObject.getIdName() + "</font>";
|
||||
}
|
||||
|
||||
public static String getNeutralColoredText(String text) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue