mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 20:41:58 -08:00
Implementing Daybound/Nightbound mechanic (#8200)
* adding initial day/night support in game state * remove card exclusion for testing * added functional implementation to abilities from main branch * functionally implemented NightCondition * updated DayNightHint * added support for nightbound entering transformed at night * [MID] Implemented Unnatural Moonrise * [MID] Implemented The Celestus * added some docs * changed access for state day/night methods * added transformation to day/night switch * re-added unfinished filter, removed day/night cards * fixed some errors with transforming * added hints to all day/night cards * added transformation prevention plus a test * added Immerwolf test * [MID] Implemented Tovolar, Dire Overlord / Tovolar, The Midnight Scourge * refactored some cards to not use isTransformable * removed transformable parameter * simplified some transform code * fixed null pointer exception * removed unnecessary canTransform method * fixed a small error * reworked implementation of rule 701.28f * small change in transform logic * fixed failiing test * fixed verify failure * small merge change * added support for day/night switching based on spells cast * [MID] Implemented Curse of Leeches / Leeching Lurkers * moved day/night handling to untap step * added tests for cards which set day and trigger from a change * [MID] Implemented Ludevic, Necrogenius / Olag, Ludevic's Hubris * added support for creatures transforming to match day/night when necessary * fixed verify failures * fixed another verify failure * remove temporary verify skip * added transform message * removed unnecessary transform message * [MID] Implemented Angelic Enforcer / Enduring Angel * updated DayNightHint with more information * fixed verify failure * merge fix * fixed Startled Awake / Persistent Nightmare / Moonmist interaction * added another test for Moonmist * merge fix * merge fix * [MID] Implemented Baneblade Scoundrel / Baneclaw Marauder * merge fix * [MID] various text fixes * [MID] a few more text fixes * Merge fix * Improved transform game logs (hints, source), fixed day/night logs, fixed miss game param (due code style); * fixed a test failure * Merge fix Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
This commit is contained in:
parent
6d4e5672c3
commit
30afb11cd2
305 changed files with 2174 additions and 1064 deletions
|
|
@ -531,6 +531,10 @@ public interface Ability extends Controllable, Serializable {
|
|||
*/
|
||||
Permanent getSourcePermanentOrLKI(Game game);
|
||||
|
||||
void setSourcePermanentTransformCount(Game game);
|
||||
|
||||
boolean checkTransformCount(Permanent permanent, Game game);
|
||||
|
||||
String getTargetDescription(Targets targets, Game game);
|
||||
|
||||
void setCanFizzle(boolean canFizzle);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected Outcome customOutcome = null; // uses for AI decisions instead effects
|
||||
protected MageIdentifier identifier; // used to identify specific ability (e.g. to match with corresponding watcher)
|
||||
protected String appendToRule = null;
|
||||
protected int sourcePermanentTransformCount = 0;
|
||||
|
||||
public AbilityImpl(AbilityType abilityType, Zone zone) {
|
||||
this.id = UUID.randomUUID();
|
||||
|
|
@ -135,6 +136,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
this.identifier = ability.identifier;
|
||||
this.activated = ability.activated;
|
||||
this.appendToRule = ability.appendToRule;
|
||||
this.sourcePermanentTransformCount = ability.sourcePermanentTransformCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -246,6 +248,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (getSourceObjectZoneChangeCounter() == 0) {
|
||||
setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(getSourceId()));
|
||||
}
|
||||
setSourcePermanentTransformCount(game);
|
||||
|
||||
/* 20130201 - 601.2b
|
||||
* If the player wishes to splice any cards onto the spell (see rule 702.45), he
|
||||
|
|
@ -1292,6 +1295,24 @@ public abstract class AbilityImpl implements Ability {
|
|||
return sourceObjectZoneChangeCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourcePermanentTransformCount(Game game) {
|
||||
Permanent permanent = getSourcePermanentOrLKI(game);
|
||||
if (permanent != null) {
|
||||
this.sourcePermanentTransformCount = permanent.getTransformCount();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTransformCount(Permanent permanent, Game game) {
|
||||
if (permanent == null
|
||||
|| !permanent.getId().equals(sourceId)
|
||||
|| permanent.getZoneChangeCounter(game) != sourceObjectZoneChangeCounter) {
|
||||
return true;
|
||||
}
|
||||
return permanent.getTransformCount() == sourcePermanentTransformCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canFizzle() {
|
||||
return canFizzle;
|
||||
|
|
|
|||
|
|
@ -2,17 +2,18 @@ package mage.abilities.common;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.hint.common.DayNightHint;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* TODO: this is just a placeholder for the actual ability
|
||||
*/
|
||||
public class BecomeDayAsEntersAbility extends EntersBattlefieldAbility {
|
||||
|
||||
public BecomeDayAsEntersAbility() {
|
||||
super(new BecomeDayEffect());
|
||||
this.addHint(DayNightHint.instance);
|
||||
}
|
||||
|
||||
private BecomeDayAsEntersAbility(final BecomeDayAsEntersAbility ability) {
|
||||
|
|
@ -33,7 +34,7 @@ public class BecomeDayAsEntersAbility extends EntersBattlefieldAbility {
|
|||
class BecomeDayEffect extends OneShotEffect {
|
||||
|
||||
BecomeDayEffect() {
|
||||
super(Outcome.Benefit);
|
||||
super(Outcome.Neutral);
|
||||
}
|
||||
|
||||
private BecomeDayEffect(final BecomeDayEffect effect) {
|
||||
|
|
@ -47,6 +48,10 @@ class BecomeDayEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
if (!game.hasDayNight()) {
|
||||
game.setDaytime(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import mage.game.events.GameEvent;
|
|||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* TODO: this is just a placeholder for the actual ability
|
||||
*/
|
||||
public class BecomesDayOrNightTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
|
|
@ -26,7 +25,7 @@ public class BecomesDayOrNightTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return false;
|
||||
return event.getType() == GameEvent.EventType.BECOMES_DAY_NIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import mage.game.Game;
|
|||
public class WerewolfBackTriggeredAbility extends BeginningOfUpkeepTriggeredAbility {
|
||||
|
||||
public WerewolfBackTriggeredAbility() {
|
||||
super(new TransformSourceEffect(false), TargetController.ANY, false);
|
||||
super(new TransformSourceEffect(), TargetController.ANY, false);
|
||||
}
|
||||
|
||||
private WerewolfBackTriggeredAbility(final WerewolfBackTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import mage.game.Game;
|
|||
public class WerewolfFrontTriggeredAbility extends BeginningOfUpkeepTriggeredAbility {
|
||||
|
||||
public WerewolfFrontTriggeredAbility() {
|
||||
super(new TransformSourceEffect(true), TargetController.ANY, false);
|
||||
super(new TransformSourceEffect(), TargetController.ANY, false);
|
||||
}
|
||||
|
||||
private WerewolfFrontTriggeredAbility(final WerewolfFrontTriggeredAbility ability) {
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import mage.game.Game;
|
|||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* TODO: Implement this
|
||||
*/
|
||||
public enum NightCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
return game.checkDayNight(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,43 +1,23 @@
|
|||
|
||||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author nantuko
|
||||
*/
|
||||
public class TransformSourceEffect extends OneShotEffect {
|
||||
|
||||
private boolean withoutTrigger;
|
||||
private boolean fromDayToNight;
|
||||
|
||||
/**
|
||||
* @param fromDayToNight Defines whether we transform from "day" side to
|
||||
* "night" or vice versa.
|
||||
*/
|
||||
public TransformSourceEffect(boolean fromDayToNight) {
|
||||
this(fromDayToNight, false);
|
||||
}
|
||||
|
||||
public TransformSourceEffect(boolean fromDayToNight, boolean withoutTrigger) {
|
||||
public TransformSourceEffect() {
|
||||
super(Outcome.Transform);
|
||||
this.withoutTrigger = withoutTrigger;
|
||||
this.fromDayToNight = fromDayToNight;
|
||||
staticText = "transform {this}";
|
||||
}
|
||||
|
||||
public TransformSourceEffect(final TransformSourceEffect effect) {
|
||||
super(effect);
|
||||
this.withoutTrigger = effect.withoutTrigger;
|
||||
this.fromDayToNight = effect.fromDayToNight;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -47,37 +27,8 @@ public class TransformSourceEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game); // Transform only if it's the same object as the effect was put on the stack
|
||||
if (sourceObject instanceof Permanent) {
|
||||
Permanent sourcePermanent = (Permanent) sourceObject;
|
||||
if (sourcePermanent.canTransform(source, game)) {
|
||||
// check not to transform twice the same side
|
||||
if (sourcePermanent.isTransformed() != fromDayToNight) {
|
||||
if (withoutTrigger) {
|
||||
sourcePermanent.setTransformed(fromDayToNight);
|
||||
} else {
|
||||
if (sourcePermanent.isTransformed()) {
|
||||
Card orgCard = game.getCard(source.getSourceId());
|
||||
sourcePermanent.getPower().modifyBaseValue(orgCard.getPower().getValue());
|
||||
sourcePermanent.getToughness().modifyBaseValue(orgCard.getToughness().getValue());
|
||||
}
|
||||
sourcePermanent.transform(game);
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
if (fromDayToNight) {
|
||||
if (sourcePermanent.getSecondCardFace() != null) {
|
||||
if (sourcePermanent instanceof PermanentCard) {
|
||||
game.informPlayers(((PermanentCard) sourcePermanent).getCard().getLogName() + " transforms into " + sourcePermanent.getSecondCardFace().getLogName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
game.informPlayers(sourcePermanent.getSecondCardFace().getLogName() + " transforms into " + sourcePermanent.getLogName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
|
||||
// check not to transform twice the same side
|
||||
return permanent != null && permanent.transform(source, game);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.target.Target;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class TransformTargetEffect extends OneShotEffect {
|
||||
|
||||
private boolean withoutTrigger;
|
||||
|
||||
public TransformTargetEffect() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
public TransformTargetEffect(boolean withoutTrigger) {
|
||||
super(Outcome.Transform);
|
||||
this.withoutTrigger = withoutTrigger;
|
||||
}
|
||||
|
||||
public TransformTargetEffect(final TransformTargetEffect effect) {
|
||||
super(effect);
|
||||
this.withoutTrigger = effect.withoutTrigger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformTargetEffect copy() {
|
||||
return new TransformTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (permanent != null) {
|
||||
if (permanent.canTransform(source, game)) {
|
||||
// check not to transform twice the same side
|
||||
if (withoutTrigger) {
|
||||
permanent.setTransformed(!permanent.isTransformed());
|
||||
} else {
|
||||
permanent.transform(game);
|
||||
}
|
||||
if (!game.isSimulation()) {
|
||||
if (permanent.isTransformed()) {
|
||||
if (permanent.getSecondCardFace() != null) {
|
||||
if (permanent instanceof PermanentCard) {
|
||||
game.informPlayers(((PermanentCard) permanent).getCard().getLogName() + " transforms into " + permanent.getSecondCardFace().getLogName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
game.informPlayers(permanent.getSecondCardFace().getLogName() + " transforms into " + permanent.getLogName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
if (mode.getTargets().isEmpty()) {
|
||||
return "transform target";
|
||||
}
|
||||
Target target = mode.getTargets().get(0);
|
||||
if (target.getMaxNumberOfTargets() > 1) {
|
||||
if (target.getMaxNumberOfTargets() == target.getNumberOfTargets()) {
|
||||
return "transform " + CardUtil.numberToText(target.getNumberOfTargets()) + " target " + target.getTargetName();
|
||||
} else {
|
||||
return "transform up to " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + " target " + target.getTargetName();
|
||||
}
|
||||
} else {
|
||||
return "transform target " + mode.getTargets().get(0).getTargetName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.CastSpellLastTurnWatcher;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum DayNightHint implements Hint {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
if (!game.hasDayNight()) {
|
||||
return "It's neither day nor night.";
|
||||
}
|
||||
boolean isDay = game.checkDayNight(true);
|
||||
int spellsThisTurn = game
|
||||
.getState()
|
||||
.getWatcher(CastSpellLastTurnWatcher.class)
|
||||
.getActivePlayerThisTurnCount();
|
||||
StringBuilder sb = new StringBuilder("It's currently ");
|
||||
sb.append(isDay ? "day" : "night");
|
||||
sb.append(", active player has cast ");
|
||||
sb.append(spellsThisTurn);
|
||||
sb.append(" spells this turn. It will ");
|
||||
sb.append((isDay ? spellsThisTurn == 0 : spellsThisTurn >= 2) ? "" : "not");
|
||||
sb.append(" become ");
|
||||
sb.append(isDay ? "night" : "day");
|
||||
sb.append(" next turn.");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DayNightHint copy() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package mage.abilities.hint.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.common.NightCondition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum NightHint implements Hint {
|
||||
instance;
|
||||
private static final Hint hint = new ConditionHint(
|
||||
NightCondition.instance, "It's currently night"
|
||||
);
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
return hint.getText(game, ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,20 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.hint.common.DayNightHint;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* TODO: Implement this
|
||||
*/
|
||||
public class DayboundAbility extends StaticAbility {
|
||||
|
||||
public DayboundAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super(Zone.BATTLEFIELD, new DayboundEffect());
|
||||
this.addHint(DayNightHint.instance);
|
||||
}
|
||||
|
||||
private DayboundAbility(final DayboundAbility ability) {
|
||||
|
|
@ -27,3 +31,27 @@ public class DayboundAbility extends StaticAbility {
|
|||
return new DayboundAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class DayboundEffect extends ContinuousEffectImpl {
|
||||
|
||||
DayboundEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
|
||||
}
|
||||
|
||||
private DayboundEffect(final DayboundEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DayboundEffect copy() {
|
||||
return new DayboundEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (!game.hasDayNight()) {
|
||||
game.setDaytime(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.hint.common.DayNightHint;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* TODO: Implement this
|
||||
*/
|
||||
public class NightboundAbility extends StaticAbility {
|
||||
|
||||
public NightboundAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super(Zone.BATTLEFIELD, new NightboundEffect());
|
||||
this.addHint(DayNightHint.instance);
|
||||
}
|
||||
|
||||
private NightboundAbility(final NightboundAbility ability) {
|
||||
|
|
@ -26,4 +31,34 @@ public class NightboundAbility extends StaticAbility {
|
|||
public NightboundAbility copy() {
|
||||
return new NightboundAbility(this);
|
||||
}
|
||||
|
||||
public static boolean checkCard(Card card, Game game) {
|
||||
return game.checkDayNight(false)
|
||||
&& card.getSecondCardFace() != null
|
||||
&& card.getSecondCardFace().getAbilities().containsClass(NightboundAbility.class);
|
||||
}
|
||||
}
|
||||
|
||||
class NightboundEffect extends ContinuousEffectImpl {
|
||||
|
||||
NightboundEffect() {
|
||||
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
|
||||
}
|
||||
|
||||
private NightboundEffect(final NightboundEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NightboundEffect copy() {
|
||||
return new NightboundEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (!game.hasDayNight()) {
|
||||
game.setDaytime(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ public class TransformAbility extends SimpleStaticAbility {
|
|||
}
|
||||
permanent.getPower().modifyBaseValue(sourceCard.getPower().getValue());
|
||||
permanent.getToughness().modifyBaseValue(sourceCard.getToughness().getValue());
|
||||
permanent.setTransformable(sourceCard.isTransformable());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,8 +70,6 @@ public interface Card extends MageObject {
|
|||
|
||||
boolean isTransformable();
|
||||
|
||||
void setTransformable(boolean transformable);
|
||||
|
||||
Card getSecondCardFace();
|
||||
|
||||
boolean isNightCard();
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
protected String tokenSetCode;
|
||||
protected String tokenDescriptor;
|
||||
protected Rarity rarity;
|
||||
protected boolean transformable;
|
||||
protected Class<?> secondSideCardClazz;
|
||||
protected Card secondSideCard;
|
||||
protected boolean nightCard;
|
||||
|
|
@ -121,7 +120,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
tokenDescriptor = card.tokenDescriptor;
|
||||
rarity = card.rarity;
|
||||
|
||||
transformable = card.transformable;
|
||||
secondSideCardClazz = card.secondSideCardClazz;
|
||||
secondSideCard = null; // will be set on first getSecondCardFace call if card has one
|
||||
nightCard = card.nightCard;
|
||||
|
|
@ -618,12 +616,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
|
||||
@Override
|
||||
public boolean isTransformable() {
|
||||
return this.transformable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransformable(boolean transformable) {
|
||||
this.transformable = transformable;
|
||||
return this.secondSideCardClazz != null || this.nightCard;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ public class MockCard extends CardImpl {
|
|||
|
||||
this.flipCard = card.isFlipCard();
|
||||
|
||||
this.transformable = card.isDoubleFaced();
|
||||
this.nightCard = card.isNightCard();
|
||||
if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty()) {
|
||||
this.secondSideCard = new MockCard(CardRepository.instance.findCardWPreferredSet(card.getSecondSideName(), card.getSetCode(), false));
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ public class MockSplitCard extends SplitCard {
|
|||
this.color = card.getColor();
|
||||
this.flipCard = card.isFlipCard();
|
||||
|
||||
this.transformable = card.isDoubleFaced();
|
||||
this.nightCard = card.isNightCard();
|
||||
if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty()) {
|
||||
this.secondSideCard = new MockCard(CardRepository.instance.findCardWPreferredSet(card.getSecondSideName(), card.getSetCode(), false));
|
||||
|
|
|
|||
|
|
@ -386,6 +386,26 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
|
|||
|
||||
void ventureIntoDungeon(UUID playerId);
|
||||
|
||||
/**
|
||||
* Tells whether the current game has day or night, defaults to false
|
||||
*/
|
||||
boolean hasDayNight();
|
||||
|
||||
/**
|
||||
* Sets game to day or night, sets hasDayNight to true
|
||||
*
|
||||
* @param daytime day is true, night is false
|
||||
*/
|
||||
void setDaytime(boolean daytime);
|
||||
|
||||
/**
|
||||
* Returns true if hasDayNight is true and parameter matches current day/night value
|
||||
* Returns false if hasDayNight is false
|
||||
*
|
||||
* @param daytime day is true, night is false
|
||||
*/
|
||||
boolean checkDayNight(boolean daytime);
|
||||
|
||||
/**
|
||||
* Adds a permanent to the battlefield
|
||||
*
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ import mage.abilities.effects.Effect;
|
|||
import mage.abilities.effects.PreventionEffectData;
|
||||
import mage.abilities.effects.common.CopyEffect;
|
||||
import mage.abilities.effects.common.InfoEffect;
|
||||
import mage.abilities.keyword.BestowAbility;
|
||||
import mage.abilities.keyword.CompanionAbility;
|
||||
import mage.abilities.keyword.MorphAbility;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.abilities.keyword.*;
|
||||
import mage.abilities.mana.DelayedTriggeredManaAbility;
|
||||
import mage.abilities.mana.TriggeredManaAbility;
|
||||
import mage.actions.impl.MageAction;
|
||||
|
|
@ -552,6 +549,35 @@ public abstract class GameImpl implements Game {
|
|||
fireEvent(GameEvent.getEvent(GameEvent.EventType.VENTURED, playerId, null, playerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDayNight() {
|
||||
return state.isHasDayNight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDaytime(boolean daytime) {
|
||||
if (!state.isHasDayNight()) {
|
||||
informPlayers("It has become " + (daytime ? "day" : "night"));
|
||||
}
|
||||
if (!state.setDaytime(daytime)) {
|
||||
return;
|
||||
}
|
||||
// TODO: add day/night sound effect
|
||||
informPlayers("It has become " + (daytime ? "day" : "night"));
|
||||
fireEvent(GameEvent.getEvent(GameEvent.EventType.BECOMES_DAY_NIGHT, null, null, null));
|
||||
for (Permanent permanent : state.getBattlefield().getAllPermanents()) {
|
||||
if ((daytime && permanent.getAbilities(this).containsClass(NightboundAbility.class))
|
||||
|| (!daytime && permanent.getAbilities(this).containsClass(DayboundAbility.class))) {
|
||||
permanent.transform(null, this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkDayNight(boolean daytime) {
|
||||
return state.isHasDayNight() && state.isDaytime() == daytime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getOwnerId(UUID objectId) {
|
||||
return getOwnerId(getObject(objectId));
|
||||
|
|
@ -1933,6 +1959,9 @@ public abstract class GameImpl implements Game {
|
|||
if (newAbility.getSourceObjectZoneChangeCounter() == 0) {
|
||||
newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
|
||||
}
|
||||
if (!(newAbility instanceof DelayedTriggeredAbility)) {
|
||||
newAbility.setSourcePermanentTransformCount(this);
|
||||
}
|
||||
newAbility.setTriggerEvent(triggeringEvent);
|
||||
state.addTriggeredAbility(newAbility);
|
||||
}
|
||||
|
|
@ -1949,6 +1978,7 @@ public abstract class GameImpl implements Game {
|
|||
newAbility.newId();
|
||||
if (source != null) {
|
||||
newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId()));
|
||||
newAbility.setSourcePermanentTransformCount(this);
|
||||
}
|
||||
newAbility.initOnAdding(this);
|
||||
// ability.init is called as the ability triggeres not now.
|
||||
|
|
@ -2585,6 +2615,17 @@ public abstract class GameImpl implements Game {
|
|||
}
|
||||
}
|
||||
|
||||
// Daybound/Nightbound permanents should be transformed according to day/night
|
||||
// This is not a state-based action but it's unclear where else to put it
|
||||
if (hasDayNight()) {
|
||||
for (Permanent permanent : getBattlefield().getAllActivePermanents()) {
|
||||
if ((permanent.getAbilities(this).containsClass(DayboundAbility.class) && !state.isDaytime())
|
||||
|| (permanent.getAbilities(this).containsClass(NightboundAbility.class) && state.isDaytime())) {
|
||||
somethingHappened = permanent.transform(null, this, true) || somethingHappened;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: implement the rest
|
||||
return somethingHappened;
|
||||
}
|
||||
|
|
@ -2757,6 +2798,8 @@ public abstract class GameImpl implements Game {
|
|||
|
||||
@Override
|
||||
public void informPlayers(String message) {
|
||||
// Uncomment to print game messages
|
||||
// System.out.println(message.replaceAll("\\<.*?\\>", ""));
|
||||
if (simulation) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private final Map<UUID, FilterCreaturePermanent> usePowerInsteadOfToughnessForDamageLethalityFilters = new HashMap<>();
|
||||
private Set<MageObjectReference> commandersToStay = new HashSet<>(); // commanders that do not go back to command zone
|
||||
private boolean manaBurn = false;
|
||||
private boolean hasDayNight = false;
|
||||
private boolean isDaytime = true;
|
||||
|
||||
private int applyEffectsCounter; // Upcounting number of each applyEffects execution
|
||||
|
||||
|
|
@ -193,6 +195,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
state.usePowerInsteadOfToughnessForDamageLethalityFilters.forEach((uuid, filter)
|
||||
-> this.usePowerInsteadOfToughnessForDamageLethalityFilters.put(uuid, filter.copy()));
|
||||
this.commandersToStay.addAll(state.commandersToStay);
|
||||
this.hasDayNight = state.hasDayNight;
|
||||
this.isDaytime = state.isDaytime;
|
||||
}
|
||||
|
||||
public void clearOnGameRestart() {
|
||||
|
|
@ -280,6 +284,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
state.usePowerInsteadOfToughnessForDamageLethalityFilters.forEach((uuid, filter)
|
||||
-> this.usePowerInsteadOfToughnessForDamageLethalityFilters.put(uuid, filter.copy()));
|
||||
this.commandersToStay = state.commandersToStay;
|
||||
this.hasDayNight = state.hasDayNight;
|
||||
this.isDaytime = state.isDaytime;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -872,7 +878,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
for (Map.Entry<ZoneChangeData, List<GameEvent>> entry : eventsByKey.entrySet()) {
|
||||
Set<Card> movedCards = new LinkedHashSet<>();
|
||||
Set<PermanentToken> movedTokens = new LinkedHashSet<>();
|
||||
for (Iterator<GameEvent> it = entry.getValue().iterator(); it.hasNext();) {
|
||||
for (Iterator<GameEvent> it = entry.getValue().iterator(); it.hasNext(); ) {
|
||||
GameEvent event = it.next();
|
||||
ZoneChangeEvent castEvent = (ZoneChangeEvent) event;
|
||||
UUID targetId = castEvent.getTargetId();
|
||||
|
|
@ -946,8 +952,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
* span
|
||||
*
|
||||
* @param ability
|
||||
* @param sourceId - if source object can be moved between zones then you
|
||||
* must set it here (each game cycle clear all source related triggers)
|
||||
* @param sourceId - if source object can be moved between zones then you
|
||||
* must set it here (each game cycle clear all source related triggers)
|
||||
* @param attachedTo
|
||||
*/
|
||||
public void addAbility(Ability ability, UUID sourceId, MageObject attachedTo) {
|
||||
|
|
@ -1153,8 +1159,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
* @param attachedTo
|
||||
* @param ability
|
||||
* @param copyAbility copies non MageSingleton abilities before adding to
|
||||
* state (allows to have multiple instances in one object, e.g. false param
|
||||
* will simulate keyword/singleton)
|
||||
* state (allows to have multiple instances in one object, e.g. false param
|
||||
* will simulate keyword/singleton)
|
||||
*/
|
||||
public void addOtherAbility(Card attachedTo, Ability ability, boolean copyAbility) {
|
||||
checkWrongDynamicAbilityUsage(attachedTo, ability);
|
||||
|
|
@ -1413,6 +1419,21 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
return manaBurn;
|
||||
}
|
||||
|
||||
boolean isHasDayNight() {
|
||||
return hasDayNight;
|
||||
}
|
||||
|
||||
boolean setDaytime(boolean daytime) {
|
||||
boolean flag = this.hasDayNight && this.isDaytime != daytime;
|
||||
this.hasDayNight = true;
|
||||
this.isDaytime = daytime;
|
||||
return flag;
|
||||
}
|
||||
|
||||
boolean isDaytime() {
|
||||
return isDaytime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return CardUtil.getTurnInfo(this);
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ public class GameEvent implements Serializable {
|
|||
UNTAP, UNTAPPED,
|
||||
FLIP, FLIPPED,
|
||||
UNFLIP, UNFLIPPED,
|
||||
TRANSFORM, TRANSFORMED,
|
||||
TRANSFORM, TRANSFORMING, TRANSFORMED,
|
||||
ADAPT,
|
||||
BECOMES_MONSTROUS,
|
||||
/* BECOMES_EXERTED
|
||||
|
|
@ -356,6 +356,7 @@ public class GameEvent implements Serializable {
|
|||
*/
|
||||
BECOME_MONARCH,
|
||||
BECOMES_MONARCH,
|
||||
BECOMES_DAY_NIGHT,
|
||||
MEDITATED,
|
||||
PHASE_OUT, PHASED_OUT,
|
||||
PHASE_IN, PHASED_IN,
|
||||
|
|
|
|||
|
|
@ -47,12 +47,16 @@ public interface Permanent extends Card, Controllable {
|
|||
|
||||
boolean flip(Game game);
|
||||
|
||||
boolean transform(Game game);
|
||||
boolean transform(Ability source, Game game);
|
||||
|
||||
boolean transform(Ability source, Game game, boolean ignoreDayNight);
|
||||
|
||||
boolean isTransformed();
|
||||
|
||||
void setTransformed(boolean value);
|
||||
|
||||
int getTransformCount();
|
||||
|
||||
boolean isPhasedIn();
|
||||
|
||||
boolean isPhasedOutIndirectly();
|
||||
|
|
@ -289,15 +293,6 @@ public interface Permanent extends Card, Controllable {
|
|||
*/
|
||||
boolean canUseActivatedAbilities(Game game);
|
||||
|
||||
/**
|
||||
* Checks by restriction effects if the permanent can transform
|
||||
*
|
||||
* @param ability the ability that causes the transform
|
||||
* @param game
|
||||
* @return true - permanent can transform
|
||||
*/
|
||||
boolean canTransform(Ability ability, Game game);
|
||||
|
||||
boolean removeFromCombat(Game game);
|
||||
|
||||
boolean removeFromCombat(Game game, boolean withInfo);
|
||||
|
|
@ -413,5 +408,4 @@ public interface Permanent extends Card, Controllable {
|
|||
}
|
||||
return getAttachedTo().equals(otherId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import mage.abilities.Abilities;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.keyword.NightboundAbility;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.LevelerCard;
|
||||
|
|
@ -70,7 +71,8 @@ public class PermanentCard extends PermanentImpl {
|
|||
maxLevelCounters = ((LevelerCard) card).getMaxLevelCounters();
|
||||
}
|
||||
if (isTransformable()) {
|
||||
if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId()) != null) {
|
||||
if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId()) != null
|
||||
|| NightboundAbility.checkCard(this, game)) {
|
||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId(), null);
|
||||
setTransformed(true);
|
||||
TransformAbility.transform(this, getSecondCardFace(), game, null);
|
||||
|
|
@ -132,14 +134,10 @@ public class PermanentCard extends PermanentImpl {
|
|||
this.cardNumber = card.getCardNumber();
|
||||
this.usesVariousArt = card.getUsesVariousArt();
|
||||
|
||||
this.transformable = card.isTransformable();
|
||||
if (this.transformable) {
|
||||
this.nightCard = card.isNightCard();
|
||||
if (!this.nightCard) {
|
||||
this.secondSideCard = card.getSecondCardFace();
|
||||
this.secondSideCardClazz = this.secondSideCard.getClass();
|
||||
}
|
||||
if (card.getSecondCardFace() != null) {
|
||||
this.secondSideCardClazz = card.getSecondCardFace().getClass();
|
||||
}
|
||||
this.nightCard = card.isNightCard();
|
||||
this.flipCard = card.isFlipCard();
|
||||
this.flipCardName = card.getFlipCardName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
protected List<MarkedDamageInfo> markedDamage;
|
||||
protected int markedLifelink;
|
||||
protected int timesLoyaltyUsed = 0;
|
||||
protected int transformCount = 0;
|
||||
protected Map<String, String> info;
|
||||
protected int createOrder;
|
||||
|
||||
|
|
@ -168,6 +169,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
this.pairedPermanent = permanent.pairedPermanent;
|
||||
this.bandedCards.addAll(permanent.bandedCards);
|
||||
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
|
||||
this.transformCount = permanent.transformCount;
|
||||
|
||||
this.morphed = permanent.morphed;
|
||||
this.manifested = permanent.manifested;
|
||||
|
|
@ -562,16 +564,46 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(Game game) {
|
||||
if (transformable) {
|
||||
if (!replaceEvent(EventType.TRANSFORM, game)) {
|
||||
setTransformed(!transformed);
|
||||
game.applyEffects();
|
||||
game.addSimultaneousEvent(GameEvent.getEvent(GameEvent.EventType.TRANSFORMED, getId(), getControllerId()));
|
||||
return true;
|
||||
}
|
||||
public boolean transform(Ability source, Game game) {
|
||||
return this.transform(source, game, false);
|
||||
}
|
||||
|
||||
private boolean checkDayNightBound() {
|
||||
return this.getAbilities().containsClass(DayboundAbility.class)
|
||||
|| this.getAbilities().containsClass(NightboundAbility.class);
|
||||
}
|
||||
|
||||
private Card getOtherFace() {
|
||||
return transformed ? this.getMainCard() : this.getMainCard().getSecondCardFace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(Ability source, Game game, boolean ignoreDayNight) {
|
||||
if (!this.isTransformable()
|
||||
|| (!ignoreDayNight && this.checkDayNightBound())
|
||||
|| this.getOtherFace().isInstantOrSorcery()
|
||||
|| (source != null && !source.checkTransformCount(this, game))
|
||||
|| this.replaceEvent(EventType.TRANSFORM, game)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
if (this.transformed) {
|
||||
Card orgCard = this.getMainCard();
|
||||
this.getPower().modifyBaseValue(orgCard.getPower().getValue());
|
||||
this.getToughness().modifyBaseValue(orgCard.getToughness().getValue());
|
||||
}
|
||||
game.informPlayers(this.getLogName() + " transforms into " + this.getOtherFace().getLogName()
|
||||
+ CardUtil.getSourceLogName(game, source, this.getId()));
|
||||
this.setTransformed(!this.transformed);
|
||||
this.transformCount++;
|
||||
game.applyEffects();
|
||||
this.replaceEvent(EventType.TRANSFORMING, game);
|
||||
game.addSimultaneousEvent(GameEvent.getEvent(EventType.TRANSFORMED, this.getId(), this.getControllerId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransformCount() {
|
||||
return transformCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1406,21 +1438,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTransform(Ability source, Game game) {
|
||||
if (transformable) {
|
||||
for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
|
||||
RestrictionEffect effect = entry.getKey();
|
||||
for (Ability ability : entry.getValue()) {
|
||||
if (!effect.canTransform(this, ability, game, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return transformable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttacking(boolean attacking) {
|
||||
this.attacking = attacking;
|
||||
|
|
@ -1750,5 +1767,4 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
detachAllAttachments(game);
|
||||
return successfullyMoved;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -907,11 +907,6 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
throw new UnsupportedOperationException("Unsupported operation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransformable(boolean value) {
|
||||
throw new UnsupportedOperationException("Unsupported operation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZoneChangeCounter(Game game) {
|
||||
// spell's zcc can't be changed after put to stack
|
||||
|
|
|
|||
|
|
@ -576,6 +576,16 @@ public class StackAbility extends StackObjectImpl implements Ability {
|
|||
return ability.getSourcePermanentOrLKI(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourcePermanentTransformCount(Game game) {
|
||||
ability.setSourcePermanentTransformCount(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTransformCount(Permanent permanent, Game game) {
|
||||
return ability.checkTransformCount(permanent, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZoneChangeCounter(Game game) {
|
||||
return game.getState().getZoneChangeCounter(getSourceId());
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
package mage.game.turn;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.TurnPhase;
|
||||
|
|
@ -17,6 +12,12 @@ import mage.game.stack.StackObject;
|
|||
import mage.players.Player;
|
||||
import mage.util.ThreadLocalStringBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -95,7 +96,7 @@ public class Turn implements Serializable {
|
|||
* @param activePlayer
|
||||
* @return true if turn is skipped
|
||||
*/
|
||||
public boolean play(Game game, Player activePlayer) {
|
||||
public boolean play(Game game, Player activePlayer) {
|
||||
// uncomment this to trace triggered abilities and/or continous effects
|
||||
// TraceUtil.traceTriggeredAbilities(game);
|
||||
// game.getState().getContinuousEffects().traceContinuousEffects(game);
|
||||
|
|
@ -121,24 +122,25 @@ public class Turn implements Serializable {
|
|||
if (game.isPaused() || game.checkIfGameIsOver()) {
|
||||
return false;
|
||||
}
|
||||
if (!isEndTurnRequested() || phase.getType() == TurnPhase.END) {
|
||||
currentPhase = phase;
|
||||
game.fireEvent(new PhaseChangedEvent(activePlayer.getId(), null));
|
||||
if (!game.getState().getTurnMods().skipPhase(activePlayer.getId(), currentPhase.getType())) {
|
||||
if (phase.play(game, activePlayer.getId())) {
|
||||
if (game.executingRollback()) {
|
||||
return false;
|
||||
}
|
||||
//20091005 - 500.4/703.4n
|
||||
game.emptyManaPools(null);
|
||||
game.saveState(false);
|
||||
|
||||
//20091005 - 500.8
|
||||
while (playExtraPhases(game, phase.getType())) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isEndTurnRequested() && phase.getType() != TurnPhase.END) {
|
||||
continue;
|
||||
}
|
||||
currentPhase = phase;
|
||||
game.fireEvent(new PhaseChangedEvent(activePlayer.getId(), null));
|
||||
if (game.getState().getTurnMods().skipPhase(
|
||||
activePlayer.getId(), currentPhase.getType()
|
||||
) || !phase.play(game, activePlayer.getId())) {
|
||||
continue;
|
||||
}
|
||||
if (game.executingRollback()) {
|
||||
return false;
|
||||
}
|
||||
//20091005 - 500.4/703.4n
|
||||
game.emptyManaPools(null);
|
||||
game.saveState(false);
|
||||
|
||||
//20091005 - 500.8
|
||||
while (playExtraPhases(game, phase.getType())) ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,15 @@
|
|||
|
||||
package mage.game.turn;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.CastSpellLastTurnWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class UntapStep extends Step {
|
||||
|
|
@ -28,6 +29,7 @@ public class UntapStep extends Step {
|
|||
@Override
|
||||
public void beginStep(Game game, UUID activePlayerId) {
|
||||
super.beginStep(game, activePlayerId);
|
||||
handleDayNight(game);
|
||||
Player activePlayer = game.getPlayer(activePlayerId);
|
||||
//20091005 - 502.1/703.4a
|
||||
activePlayer.phasing(game);
|
||||
|
|
@ -41,4 +43,18 @@ public class UntapStep extends Step {
|
|||
return new UntapStep(this);
|
||||
}
|
||||
|
||||
private void handleDayNight(Game game) {
|
||||
if (!game.hasDayNight() || game.getTurnNum() <= 1) {
|
||||
return;
|
||||
}
|
||||
int previousSpells = game
|
||||
.getState()
|
||||
.getWatcher(CastSpellLastTurnWatcher.class)
|
||||
.getActivePlayerPrevTurnCount();
|
||||
if (game.checkDayNight(true) && previousSpells == 0) {
|
||||
game.setDaytime(false);
|
||||
} else if (game.checkDayNight(false) && previousSpells >= 2) {
|
||||
game.setDaytime(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2063,11 +2063,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
game.informPlayers(this.getLogName() + " loses " + event.getAmount() + " life"
|
||||
+ (atCombat ? " at combat" : "") + CardUtil.getSourceLogName(game, " from ", needId, "", ""));
|
||||
}
|
||||
if (amount > 0) {
|
||||
if (event.getAmount() > 0) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.LOST_LIFE,
|
||||
playerId, source, playerId, amount, atCombat));
|
||||
playerId, source, playerId, event.getAmount(), atCombat));
|
||||
}
|
||||
return amount;
|
||||
return event.getAmount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1408,5 +1408,4 @@ public final class CardUtil {
|
|||
effect.apply(game, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ public class CastSpellLastTurnWatcher extends Watcher {
|
|||
private final Map<UUID, Integer> amountOfSpellsCastOnPrevTurn = new HashMap<>();
|
||||
private final Map<UUID, Integer> amountOfSpellsCastOnCurrentTurn = new HashMap<>();
|
||||
private final List<MageObjectReference> spellsCastThisTurnInOrder = new ArrayList<>();
|
||||
private int activePlayerPrevTurnCount = 0;
|
||||
private int activePlayerThisTurnCount = 0;
|
||||
|
||||
public CastSpellLastTurnWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
|
|
@ -29,7 +31,9 @@ public class CastSpellLastTurnWatcher extends Watcher {
|
|||
if (playerId != null) {
|
||||
amountOfSpellsCastOnCurrentTurn.putIfAbsent(playerId, 0);
|
||||
amountOfSpellsCastOnCurrentTurn.compute(playerId, (k, a) -> a + 1);
|
||||
|
||||
}
|
||||
if (game.isActivePlayer(playerId)) {
|
||||
activePlayerThisTurnCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +45,8 @@ public class CastSpellLastTurnWatcher extends Watcher {
|
|||
amountOfSpellsCastOnPrevTurn.putAll(amountOfSpellsCastOnCurrentTurn);
|
||||
amountOfSpellsCastOnCurrentTurn.clear();
|
||||
spellsCastThisTurnInOrder.clear();
|
||||
activePlayerPrevTurnCount = activePlayerThisTurnCount;
|
||||
activePlayerThisTurnCount = 0;
|
||||
}
|
||||
|
||||
public Map<UUID, Integer> getAmountOfSpellsCastOnPrevTurn() {
|
||||
|
|
@ -69,4 +75,12 @@ public class CastSpellLastTurnWatcher extends Watcher {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getActivePlayerPrevTurnCount() {
|
||||
return activePlayerPrevTurnCount;
|
||||
}
|
||||
|
||||
public int getActivePlayerThisTurnCount() {
|
||||
return activePlayerThisTurnCount;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue