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

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