[AFR] Implementing Class enchantments (ready for review) (#7992)

* [AFR] Implemented Druid Class

* [AFR] Implemented Wizard Class

* [AFR] Implemented Cleric Class

* [AFR] Implemented Fighter Class

* reworked class ability implementation

* fixed an error with setting class level

* small reworking of class triggers

* added class level hint

* added tests

* small change

* added common class for reminder text
This commit is contained in:
Evan Kranzler 2021-07-14 09:17:07 -04:00 committed by GitHub
parent d00765c2d5
commit 5b88484cb6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 884 additions and 5 deletions

View file

@ -1,5 +1,6 @@
package mage.abilities.common;
import mage.MageObjectReference;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
@ -64,6 +65,7 @@ public class AttacksCreatureYouControlTriggeredAbility extends TriggeredAbilityI
if (setTargetPointer) {
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game));
}
this.getEffects().setValue("attackerRef", new MageObjectReference(sourcePermanent, game));
return true;
}
return false;

View file

@ -0,0 +1,45 @@
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
* @author TheElk801
*/
public class BecomesClassLevelTriggeredAbility extends TriggeredAbilityImpl {
private final int level;
public BecomesClassLevelTriggeredAbility(Effect effect, int level) {
super(Zone.BATTLEFIELD, effect);
this.level = level;
}
private BecomesClassLevelTriggeredAbility(final BecomesClassLevelTriggeredAbility ability) {
super(ability);
this.level = ability.level;
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.GAINS_CLASS_LEVEL;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getAmount() == level && event.getSourceId().equals(getSourceId());
}
@Override
public BecomesClassLevelTriggeredAbility copy() {
return new BecomesClassLevelTriggeredAbility(this);
}
@Override
public String getRule() {
return "When this Class becomes level " + level + ", " + super.getRule();
}
}

View file

@ -0,0 +1,55 @@
package mage.abilities.effects.common.continuous;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect;
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 GainClassAbilitySourceEffect extends ContinuousEffectImpl implements SourceEffect {
private final Ability ability;
private final int level;
public GainClassAbilitySourceEffect(Effect effect, int level) {
this(new SimpleStaticAbility(effect), level);
}
public GainClassAbilitySourceEffect(Ability ability, int level) {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = ability.getRule();
this.ability = ability;
this.level = level;
this.ability.setRuleVisible(false);
generateGainAbilityDependencies(ability, null);
}
private GainClassAbilitySourceEffect(final GainClassAbilitySourceEffect effect) {
super(effect);
this.level = effect.level;
this.ability = effect.ability;
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null || permanent.getClassLevel() < level) {
return false;
}
permanent.addAbility(ability, source.getSourceId(), game);
return true;
}
@Override
public GainClassAbilitySourceEffect copy() {
return new GainClassAbilitySourceEffect(this);
}
}

View file

@ -1,6 +1,7 @@
package mage.abilities.effects.common.cost;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
@ -8,22 +9,28 @@ import mage.game.Game;
import mage.util.CardUtil;
/**
*
* @author Styxo
*/
public class AbilitiesCostReductionControllerEffect extends CostModificationEffectImpl {
private final Class activatedAbility;
private final Class<? extends ActivatedAbility> activatedAbility;
private final int amount;
public AbilitiesCostReductionControllerEffect(Class activatedAbility, String activatedAbilityName) {
public AbilitiesCostReductionControllerEffect(Class<? extends ActivatedAbility> activatedAbility, String activatedAbilityName) {
this(activatedAbility, activatedAbilityName, 1);
}
public AbilitiesCostReductionControllerEffect(Class<? extends ActivatedAbility> activatedAbility, String activatedAbilityName, int amount) {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.activatedAbility = activatedAbility;
staticText = activatedAbilityName + " costs you pay cost {1} less";
staticText = activatedAbilityName + " costs you pay cost {" + amount + "} less";
this.amount = amount;
}
public AbilitiesCostReductionControllerEffect(AbilitiesCostReductionControllerEffect effect) {
super(effect);
this.activatedAbility = effect.activatedAbility;
this.amount = effect.amount;
}
@Override
@ -33,7 +40,7 @@ public class AbilitiesCostReductionControllerEffect extends CostModificationEffe
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
CardUtil.reduceCost(abilityToModify, 1);
CardUtil.reduceCost(abilityToModify, amount);
return true;
}

View file

@ -0,0 +1,27 @@
package mage.abilities.hint.common;
import mage.abilities.Ability;
import mage.abilities.hint.Hint;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author TheElk801
*/
public enum ClassLevelHint implements Hint {
instance;
@Override
public String getText(Game game, Ability ability) {
Permanent permanent = ability.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
return null;
}
return "Class level: " + permanent.getClassLevel();
}
@Override
public ClassLevelHint copy() {
return this;
}
}

View file

@ -0,0 +1,88 @@
package mage.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public class ClassLevelAbility extends ActivatedAbilityImpl {
private final int level;
private final String manaString;
public ClassLevelAbility(int level, String manaString) {
super(Zone.BATTLEFIELD, new SetClassLevelEffect(level), new ManaCostsImpl<>(manaString));
this.level = level;
this.manaString = manaString;
setTiming(TimingRule.SORCERY);
}
private ClassLevelAbility(final ClassLevelAbility ability) {
super(ability);
this.level = ability.level;
this.manaString = ability.manaString;
}
@Override
public ClassLevelAbility copy() {
return new ClassLevelAbility(this);
}
@Override
public String getRule() {
return manaString + ": Level " + level;
}
@Override
public ActivationStatus canActivate(UUID playerId, Game game) {
Permanent permanent = getSourcePermanentIfItStillExists(game);
if (permanent != null && permanent.getClassLevel() == level - 1) {
return super.canActivate(playerId, game);
}
return ActivationStatus.getFalse();
}
}
class SetClassLevelEffect extends OneShotEffect {
private final int level;
SetClassLevelEffect(int level) {
super(Outcome.Benefit);
this.level = level;
}
private SetClassLevelEffect(final SetClassLevelEffect effect) {
super(effect);
this.level = effect.level;
}
@Override
public SetClassLevelEffect copy() {
return new SetClassLevelEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null || !permanent.setClassLevel(level)) {
return false;
}
game.fireEvent(GameEvent.getEvent(
GameEvent.EventType.GAINS_CLASS_LEVEL, source.getSourceId(),
source, source.getControllerId(), level
));
return true;
}
}

View file

@ -0,0 +1,30 @@
package mage.abilities.keyword;
import mage.abilities.StaticAbility;
import mage.abilities.hint.common.ClassLevelHint;
import mage.constants.Zone;
/**
* @author TheElk801
*/
public class ClassReminderAbility extends StaticAbility {
public ClassReminderAbility() {
super(Zone.ALL, null);
this.addHint(ClassLevelHint.instance);
}
private ClassReminderAbility(final ClassReminderAbility ability) {
super(ability);
}
@Override
public ClassReminderAbility copy() {
return new ClassReminderAbility(this);
}
@Override
public String getRule() {
return "<i>(Gain the next level as a sorcery to add its ability.)</i>";
}
}

View file

@ -32,6 +32,7 @@ public enum SubType {
// 205.3h Enchantments have their own unique set of subtypes; these subtypes are called enchantment types.
AURA("Aura", SubTypeSet.EnchantmentType),
CARTOUCHE("Cartouche", SubTypeSet.EnchantmentType),
CLASS("Class", SubTypeSet.EnchantmentType),
CURSE("Curse", SubTypeSet.EnchantmentType),
RUNE("Rune", SubTypeSet.EnchantmentType),
SAGA("Saga", SubTypeSet.EnchantmentType),

View file

@ -340,6 +340,7 @@ public class GameEvent implements Serializable {
*/
BECOMES_EXERTED,
BECOMES_RENOWNED,
GAINS_CLASS_LEVEL,
/* BECOMES_MONARCH
targetId playerId of the player that becomes the monarch
sourceId id of the source object that created that effect, if no effect exist it's null

View file

@ -73,6 +73,10 @@ public interface Permanent extends Card, Controllable {
void setRenowned(boolean value);
int getClassLevel();
boolean setClassLevel(int classLevel);
void setCardNumber(String cid);
void setExpansionSetCode(String expansionSetCode);

View file

@ -72,6 +72,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
protected boolean renowned;
protected boolean manifested = false;
protected boolean morphed = false;
protected int classLevel = 1;
protected UUID originalControllerId;
protected UUID controllerId;
protected UUID beforeResetControllerId;
@ -163,6 +164,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.transformed = permanent.transformed;
this.monstrous = permanent.monstrous;
this.renowned = permanent.renowned;
this.classLevel = permanent.classLevel;
this.pairedPermanent = permanent.pairedPermanent;
this.bandedCards.addAll(permanent.bandedCards);
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
@ -1519,6 +1521,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.renowned = value;
}
@Override
public int getClassLevel() {
return classLevel;
}
@Override
public boolean setClassLevel(int classLevel) {
if (this.classLevel == classLevel - 1) {
this.classLevel = classLevel;
return true;
}
return false;
}
@Override
public void setPairedCard(MageObjectReference pairedCard) {
this.pairedPermanent = pairedCard;