Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b7e1f3a
ContinuousEffects: Update timestamping
Jmlundeen May 24, 2025
083bb47
ContinuousEffects: Refactor apply and add dependency checking logic
Jmlundeen May 28, 2025
e3d147e
ContinuousEffect: Add methods for dynamic dependency checks
Jmlundeen May 28, 2025
9dd2656
GameImpl: add null check on playerList when trying to restore state i…
Jmlundeen May 28, 2025
1f89cb2
MageObjectReference: Add method to return generic MageObject
Jmlundeen May 28, 2025
c4508e7
Dependency: Add jgrapht to determine continuous effect dependency cycles
Jmlundeen May 28, 2025
7bd2100
Update March of the Machines, Humility, Mycosynth Lattice and their l…
Jmlundeen May 28, 2025
8a35b7a
Update Blood Moon, (Urborg) AddBasicLandTypeAllLandsEffect and their …
Jmlundeen May 28, 2025
5411166
Update Necrotic Ooze and yixlid Jailer
Jmlundeen May 28, 2025
a564176
Move TODO for calculateResult to method
Jmlundeen May 28, 2025
a565c93
Revert dependency changes
Jmlundeen May 29, 2025
48b9a6b
Merge branch 'master' into rework/continuous-effects-layers
Jmlundeen May 29, 2025
7cc245c
ContinuousEffects: Add queryAffectedObjects and applyToObjects methods
Jmlundeen May 29, 2025
f679b87
refactor common effects
Jmlundeen May 29, 2025
c5baa4a
refactor more common effects
Jmlundeen May 31, 2025
0d7246a
refactor more common effects
Jmlundeen May 31, 2025
0e6661c
refactor more common effects
Jmlundeen Jun 1, 2025
36fd6d2
refactor more common effects
Jmlundeen Jun 1, 2025
02d1d27
refactor more common effects
Jmlundeen Jun 1, 2025
a8b0c8d
ContinuousEffect: Update query and apply to use List<MageItem> since …
Jmlundeen Jun 1, 2025
efd717b
refactor more common effects
Jmlundeen Jun 2, 2025
bb37304
refactor more common effects
Jmlundeen Jun 2, 2025
34b0e5f
Merge branch 'master' into rework/continuous-effects-layers
Jmlundeen Jun 2, 2025
3d30999
Revert incorrect changes
Jmlundeen Jun 3, 2025
38c0a08
Update continuous effects with applyToObjects and queryAffectedObjects
Jmlundeen Jun 3, 2025
b6112e7
Refactor some continuous effects
Jmlundeen Jun 3, 2025
99673c7
Add test for EnduringGlimmerTriggeredAbility
Jmlundeen Jun 4, 2025
59012a8
fix affectedObjectsMap checking for single layer effects
Jmlundeen Jun 4, 2025
26aa703
fix ConditionalContinuousEffect to correctly clear affectedObjectMap …
Jmlundeen Jun 5, 2025
19f22f1
Refactor some more effects
Jmlundeen Jun 5, 2025
1487559
Fix affectedObjectMap wrongly assigning instead of adding keys/values…
Jmlundeen Jun 6, 2025
6851dc1
Merge branch 'refs/heads/master' into rework/continuous-effects-layers
Jmlundeen Jun 8, 2025
09af4b6
Readjust query+applyTo logic
Jmlundeen Jun 8, 2025
bc2db46
Refactor more effects
Jmlundeen Jun 9, 2025
3eb9d24
Refactor more effects
Jmlundeen Jun 11, 2025
102c18d
A little more refactoring
Jmlundeen Jun 13, 2025
0c7df6f
I "C" more refactors ahead
Jmlundeen Jul 8, 2025
e64a10b
Merge branch 'master' into rework/continuous-effects-layers
Jmlundeen Jul 9, 2025
64401be
"D"on't stop refactoring
Jmlundeen Jul 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 16 additions & 25 deletions Mage.Sets/src/mage/cards/b/BloodMoon.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package mage.cards.b;

import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
Expand Down Expand Up @@ -44,47 +45,37 @@ static class BloodMoonEffect extends ContinuousEffectImpl {
}

BloodMoonEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment);
this.staticText = "Nonbasic lands are Mountains";
this.dependencyTypes.add(DependencyType.BecomeMountain);
this.dependendToTypes.add(DependencyType.BecomeNonbasicLand);
this.affectedPermanentFilter = filter;
this.effectCardZones.add(Zone.BATTLEFIELD);
}

private BloodMoonEffect(final BloodMoonEffect effect) {
super(effect);
}

@Override
public boolean apply(Game game, Ability source) {
return false;
}

@Override
public BloodMoonEffect copy() {
return new BloodMoonEffect(this);
}

@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
for (Permanent land : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) {
switch (layer) {
case TypeChangingEffects_4:
// 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects
// So the ability removing has to be done before Layer 6
// Lands have their mana ability intrinsically, so that is added in layer 4
land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType);
land.addSubType(game, SubType.MOUNTAIN);
land.removeAllAbilities(source.getSourceId(), game);
land.addAbility(new RedManaAbility(), source.getSourceId(), game);
break;
public boolean apply(Game game, Ability source) {
for (MageObjectReference mor : affectedObjectList) {
// 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects
// So the ability removing has to be done before Layer 6
// Lands have their mana ability intrinsically, so that is added in layer 4
Permanent land = mor.getPermanent(game);
if (land == null) {
continue;
}
land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType);
land.addSubType(game, SubType.MOUNTAIN);
land.removeAllAbilities(source.getSourceId(), game);
land.addAbility(new RedManaAbility(), source.getSourceId(), game);
}
return true;
}

@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4;
}
}
}
21 changes: 15 additions & 6 deletions Mage.Sets/src/mage/cards/h/Humility.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mage.cards.h;

import java.util.UUID;

import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
Expand Down Expand Up @@ -47,6 +49,8 @@ static class HumilityEffect extends ContinuousEffectImpl {
public HumilityEffect(Duration duration) {
super(duration, Outcome.LoseAbility);
staticText = "All creatures lose all abilities and have base power and toughness 1/1";
this.effectCardZones.add(Zone.BATTLEFIELD);
this.affectedPermanentFilter = StaticFilters.FILTER_PERMANENT_CREATURE;
}

private HumilityEffect(final HumilityEffect effect) {
Expand All @@ -60,12 +64,11 @@ public HumilityEffect copy() {

@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(
StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) {
for (MageObjectReference mageObjectReference : affectedObjectList) {
Permanent permanent = mageObjectReference.getPermanent(game);
if (permanent == null) {
continue;
}
switch (layer) {
case AbilityAddingRemovingEffects_6:
permanent.removeAllAbilities(source.getSourceId(), game);
Expand All @@ -90,5 +93,11 @@ public boolean hasLayer(Layer layer) {
return layer == Layer.AbilityAddingRemovingEffects_6
|| layer == Layer.PTChangingEffects_7;
}

@Override
public boolean hasSubLayer(SubLayer sublayer) {
return sublayer == SubLayer.NA
|| sublayer == SubLayer.SetPT_7b;
}
}
}
20 changes: 12 additions & 8 deletions Mage.Sets/src/mage/cards/m/MarchOfTheMachines.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@ class MarchOfTheMachinesEffect extends ContinuousEffectImpl {
public MarchOfTheMachinesEffect() {
super(Duration.WhileOnBattlefield, Outcome.BecomeCreature);
staticText = "Each noncreature artifact is an artifact creature with power and toughness each equal to its mana value";
dependendToTypes.add(DependencyType.ArtifactAddingRemoving);

dependencyTypes.add(DependencyType.BecomeCreature);
this.effectCardZones.add(Zone.BATTLEFIELD);
this.affectedPermanentFilter = filter;
}

private MarchOfTheMachinesEffect(final MarchOfTheMachinesEffect effect) {
Expand All @@ -68,10 +67,9 @@ public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game)
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
affectedObjectList.clear();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
for (MageObjectReference mageObjectReference : affectedObjectList) {
Permanent permanent = mageObjectReference.getPermanent(game);
if (permanent != null) {
affectedObjectList.add(new MageObjectReference(permanent, game));
permanent.addCardType(game, CardType.CREATURE);
}
}
Expand All @@ -80,8 +78,8 @@ public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game)

case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext();) {
Permanent permanent = it.next().getPermanent(game);
for (MageObjectReference mageObjectReference : affectedObjectList) {
Permanent permanent = mageObjectReference.getPermanent(game);
if (permanent != null) {
int manaCost = permanent.getManaValue();
permanent.getPower().setModifiedBaseValue(manaCost);
Expand All @@ -103,4 +101,10 @@ public boolean hasLayer(Layer layer) {
return layer == Layer.PTChangingEffects_7 || layer == Layer.TypeChangingEffects_4;
}

@Override
public boolean hasSubLayer(SubLayer subLayer) {
return subLayer == SubLayer.NA
|| subLayer == SubLayer.SetPT_7b;
}

}
89 changes: 21 additions & 68 deletions Mage.Sets/src/mage/cards/m/MycosynthLattice.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mage.cards.m;

import mage.MageObject;
import mage.MageObjectReference;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
Expand Down Expand Up @@ -55,6 +56,7 @@ class PermanentsAreArtifactsEffect extends ContinuousEffectImpl {
PermanentsAreArtifactsEffect() {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral);
staticText = "All permanents are artifacts in addition to their other types";
this.effectCardZones.add(Zone.BATTLEFIELD);
this.dependencyTypes.add(DependencyType.ArtifactAddingRemoving); // March of the Machines
}

Expand All @@ -81,83 +83,34 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl {
EverythingIsColorlessEffect() {
super(Duration.WhileOnBattlefield, Layer.ColorChangingEffects_5, SubLayer.NA, Outcome.Neutral);
staticText = "All cards that aren't on the battlefield, spells, and permanents are colorless";
this.effectCardZones.add(Zone.ALL);
this.playersToCheck = TargetController.EACH_PLAYER;
}

@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
ObjectColor colorless = new ObjectColor();

// permaments
for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) {
perm.getColor(game).setColor(colorless);
}

List<Card> affectedCards = new ArrayList<>();

// spells
for (MageObject object : game.getStack()) {
if (object instanceof Spell) {
game.getState().getCreateMageObjectAttribute(object, game).getColor().setColor(colorless);

Card card = ((Spell) object).getCard();
affectedCards.add(card);
if (affectedObjectList.isEmpty()) {
return false;
}
ObjectColor colorless = new ObjectColor();

for (MageObjectReference mor : affectedObjectList) {
if (mor.getPermanent(game) != null) {
mor.getPermanent(game).getColor(game).setColor(colorless);
} else {
MageObject affectedObject = mor.getSpell(game);
if (affectedObject == null) {
affectedObject = mor.getCard(game);
}
}

// exile
affectedCards.addAll(game.getExile().getAllCardsByRange(game, controller.getId()));


for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player == null) {
if (affectedObject == null) {
continue;
}

// command
affectedCards.addAll(game.getCommanderCardsFromCommandZone(player, CommanderCardType.ANY));

// hand
affectedCards.addAll(player.getHand().getCards(game));

// library
affectedCards.addAll(player.getLibrary().getCards(game));

// graveyard
affectedCards.addAll(player.getGraveyard().getCards(game));
game.getState().getCreateMageObjectAttribute(affectedObject, game)
.getColor()
.setColor(ObjectColor.COLORLESS);
}


// apply colors to all cards
affectedCards.forEach(card -> {
game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless);

// mdf cards
if (card instanceof ModalDoubleFacedCard) {
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().setColor(colorless);
game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().setColor(colorless);
}

// split cards
if (card instanceof SplitCard) {
SplitCardHalf leftHalfCard = ((SplitCard) card).getLeftHalfCard();
SplitCardHalf rightHalfCard = ((SplitCard) card).getRightHalfCard();
game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().setColor(colorless);
game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().setColor(colorless);
}

// double faces cards
if (card.getSecondCardFace() != null) {
game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless);
}
});
return true;
}
return false;
return true;
}

@Override
Expand Down
27 changes: 17 additions & 10 deletions Mage.Sets/src/mage/cards/n/NecroticOoze.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mage.cards.n;

import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
Expand All @@ -12,10 +13,7 @@
import mage.game.permanent.Permanent;
import mage.players.Player;

import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -51,7 +49,7 @@ class NecroticOozeEffect extends ContinuousEffectImpl {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "As long as {this} is on the battlefield, "
+ "it has all activated abilities of all creature cards in all graveyards";
this.dependendToTypes.add(DependencyType.AddingAbility); // Yixlid Jailer
this.affectsSourceOnly = true;
}

private NecroticOozeEffect(final NecroticOozeEffect effect) {
Expand All @@ -64,7 +62,20 @@ public boolean apply(Game game, Ability source) {
if (permanent == null) {
return false;
}
Set<Ability> abilities = game
Set<Ability> abilities = getAbilities(game, source);
for (Ability ability : abilities) {
permanent.addAbility(ability, source.getSourceId(), game, true);
}
return true;
}

@Override
public int calculateResult(Game game, Ability source, List<MageObject> affectedObjects) {
return getAbilities(game, source).size();
}

private static Set<Ability> getAbilities(Game game, Ability source) {
return game
.getState()
.getPlayersInRange(source.getControllerId(), game)
.stream()
Expand All @@ -77,10 +88,6 @@ public boolean apply(Game game, Ability source) {
.flatMap(Collection::stream)
.filter(Ability::isActivatedAbility)
.collect(Collectors.toSet());
for (Ability ability : abilities) {
permanent.addAbility(ability, source.getSourceId(), game, true);
}
return true;
}

@Override
Expand Down
Loading