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:
Evan Kranzler 2021-11-05 15:11:23 -04:00 committed by GitHub
parent 6d4e5672c3
commit 30afb11cd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
305 changed files with 2174 additions and 1064 deletions

View file

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