mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
Merge branch '1372-used-memory-grows-quadratic-in-the-number-of-triggered-spells' into 'master'
Resolve "Used memory grows quadratic in the number of triggered spells" Closes #1372 See merge request core-developers/forge!2756
This commit is contained in:
@@ -1352,7 +1352,7 @@ public class ComputerUtil {
|
|||||||
if (valid.contains("Creature.YouCtrl")
|
if (valid.contains("Creature.YouCtrl")
|
||||||
|| valid.contains("Other+YouCtrl") ) {
|
|| valid.contains("Other+YouCtrl") ) {
|
||||||
|
|
||||||
final SpellAbility sa = t.getTriggeredSA();
|
final SpellAbility sa = t.getOverridingAbility();
|
||||||
if (sa != null && sa.getApi() == ApiType.Pump && sa.hasParam("KW")
|
if (sa != null && sa.getApi() == ApiType.Pump && sa.hasParam("KW")
|
||||||
&& sa.getParam("KW").contains("Haste")) {
|
&& sa.getParam("KW").contains("Haste")) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -894,6 +894,9 @@ public class Game {
|
|||||||
public void clearCaches() {
|
public void clearCaches() {
|
||||||
spabCache.clear();
|
spabCache.clear();
|
||||||
cardCache.clear();
|
cardCache.clear();
|
||||||
|
|
||||||
|
lastStateBattlefield.clear();
|
||||||
|
lastStateGraveyard.clear();
|
||||||
//playerCache.clear();
|
//playerCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1056,23 +1056,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Object getTriggeringObject(final AbilityKey typeIn) {
|
|
||||||
Object triggered = null;
|
|
||||||
if (!currentState.getTriggers().isEmpty()) {
|
|
||||||
for (final Trigger t : currentState.getTriggers()) {
|
|
||||||
final SpellAbility sa = t.getTriggeredSA();
|
|
||||||
if (sa == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
triggered = sa.hasTriggeringObject(typeIn) ? sa.getTriggeringObject(typeIn) : null;
|
|
||||||
if (triggered != null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return triggered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getSunburstValue() {
|
public final int getSunburstValue() {
|
||||||
return sunburstValue;
|
return sunburstValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -680,7 +680,6 @@ public class CardFactory {
|
|||||||
wrapperAbility.setTrigger(true);
|
wrapperAbility.setTrigger(true);
|
||||||
wrapperAbility.setMandatory(sa.isMandatory());
|
wrapperAbility.setMandatory(sa.isMandatory());
|
||||||
wrapperAbility.setDescription(wrapperAbility.getStackDescription());
|
wrapperAbility.setDescription(wrapperAbility.getStackDescription());
|
||||||
t.setTriggeredSA(wrapperAbility);
|
|
||||||
return wrapperAbility;
|
return wrapperAbility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import forge.game.GameEntity;
|
|||||||
import forge.game.GameEntityCounterTable;
|
import forge.game.GameEntityCounterTable;
|
||||||
import forge.game.GameLogEntryType;
|
import forge.game.GameLogEntryType;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.AbilityKey;
|
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
@@ -954,11 +953,6 @@ public class CardFactoryUtil {
|
|||||||
return doXMath(c.getRegeneratedThisTurn(), m, c);
|
return doXMath(c.getRegeneratedThisTurn(), m, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TriggeringObjects
|
|
||||||
if (sq[0].startsWith("Triggered")) {
|
|
||||||
return doXMath(xCount((Card) c.getTriggeringObject(AbilityKey.Card), sq[0].substring(9)), m, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sq[0].contains("YourStartingLife")) {
|
if (sq[0].contains("YourStartingLife")) {
|
||||||
return doXMath(cc.getStartingLife(), m, c);
|
return doXMath(cc.getStartingLife(), m, c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import forge.card.MagicColor;
|
|||||||
import forge.game.Direction;
|
import forge.game.Direction;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
@@ -15,7 +16,6 @@ import forge.game.keyword.Keyword;
|
|||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.OptionalCost;
|
import forge.game.spellability.OptionalCost;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.trigger.Trigger;
|
|
||||||
import forge.game.zone.Zone;
|
import forge.game.zone.Zone;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.Expressions;
|
import forge.util.Expressions;
|
||||||
@@ -392,30 +392,20 @@ public class CardProperty {
|
|||||||
}
|
}
|
||||||
} else if (property.startsWith("AttachedTo")) {
|
} else if (property.startsWith("AttachedTo")) {
|
||||||
final String restriction = property.split("AttachedTo ")[1];
|
final String restriction = property.split("AttachedTo ")[1];
|
||||||
if (restriction.equals("Targeted")) {
|
|
||||||
if (!source.getCurrentState().getTriggers().isEmpty()) {
|
if (card.getEntityAttachedTo() == null) {
|
||||||
for (final Trigger t : source.getCurrentState().getTriggers()) {
|
|
||||||
final SpellAbility sa = t.getTriggeredSA();
|
|
||||||
final CardCollectionView cards = AbilityUtils.getDefinedCards(source, "Targeted", sa);
|
|
||||||
for (final Card c : cards) {
|
|
||||||
if (card.getEquipping() != c && !c.equals(card.getEntityAttachedTo())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!card.getEntityAttachedTo().isValid(restriction, sourceController, source, spellAbility)) {
|
||||||
|
boolean found = false;
|
||||||
|
for (final GameObject o : AbilityUtils.getDefinedObjects(source, restriction, spellAbility)) {
|
||||||
|
if (o.equals(card.getEntityAttachedTo())) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (!found) {
|
||||||
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
|
|
||||||
final CardCollectionView cards = AbilityUtils.getDefinedCards(source, "Targeted", sa);
|
|
||||||
for (final Card c : cards) {
|
|
||||||
if (card.getEquipping() == c || c.equals(card.getEntityAttachedTo())) { // handle multiple targets
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((card.getEntityAttachedTo() == null || !card.getEntityAttachedTo().isValid(restriction, sourceController, source, spellAbility))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,15 +846,6 @@ public class CardProperty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case "TriggeredCard":
|
|
||||||
final Object triggeringObject = source.getTriggeringObject(AbilityKey.fromString(restriction.substring("Triggered".length())));
|
|
||||||
if (!(triggeringObject instanceof Card)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (card.sharesCardTypeWith((Card) triggeringObject)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
case "EachTopLibrary":
|
case "EachTopLibrary":
|
||||||
final CardCollection cards = new CardCollection();
|
final CardCollection cards = new CardCollection();
|
||||||
for (Player p : game.getPlayers()) {
|
for (Player p : game.getPlayers()) {
|
||||||
|
|||||||
@@ -1996,4 +1996,24 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
public void setXManaCostPaid(final Integer n) {
|
public void setXManaCostPaid(final Integer n) {
|
||||||
xManaCostPaid = n;
|
xManaCostPaid = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeFromGame() {
|
||||||
|
if (getHostCard() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHostCard().getGame().removeSpellAbility(this);
|
||||||
|
|
||||||
|
if (subAbility != null) {
|
||||||
|
subAbility.removeFromGame();
|
||||||
|
}
|
||||||
|
for (AbilitySub sa : additionalAbilities.values()) {
|
||||||
|
sa.removeFromGame();
|
||||||
|
}
|
||||||
|
for (List<AbilitySub> list : additionalAbilityLists.values()) {
|
||||||
|
for (AbilitySub sa : list) {
|
||||||
|
sa.removeFromGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import forge.game.card.CardState;
|
|||||||
import forge.game.phase.PhaseHandler;
|
import forge.game.phase.PhaseHandler;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.Ability;
|
|
||||||
import forge.game.spellability.OptionalCost;
|
import forge.game.spellability.OptionalCost;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
@@ -472,27 +471,6 @@ public abstract class Trigger extends TriggerReplacementBase {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Ability triggeredSA;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the triggered sa.
|
|
||||||
*
|
|
||||||
* @return the triggered sa
|
|
||||||
*/
|
|
||||||
public final Ability getTriggeredSA() {
|
|
||||||
return this.triggeredSA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the triggered sa.
|
|
||||||
*
|
|
||||||
* @param sa
|
|
||||||
* the triggered sa to set
|
|
||||||
*/
|
|
||||||
public void setTriggeredSA(final Ability sa) {
|
|
||||||
this.triggeredSA = sa;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRemembered(Object o) {
|
public void addRemembered(Object o) {
|
||||||
this.triggerRemembered.add(o);
|
this.triggerRemembered.add(o);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -628,7 +628,6 @@ public class TriggerHandler {
|
|||||||
else {
|
else {
|
||||||
game.getStack().addSimultaneousStackEntry(wrapperAbility);
|
game.getStack().addSimultaneousStackEntry(wrapperAbility);
|
||||||
}
|
}
|
||||||
regtrig.setTriggeredSA(wrapperAbility);
|
|
||||||
|
|
||||||
regtrig.triggerRun();
|
regtrig.triggerRun();
|
||||||
|
|
||||||
|
|||||||
@@ -563,4 +563,10 @@ public class WrappedAbility extends Ability {
|
|||||||
public void setXManaCostPaid(final Integer n) {
|
public void setXManaCostPaid(final Integer n) {
|
||||||
sa.setXManaCostPaid(n);
|
sa.setXManaCostPaid(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeFromGame() {
|
||||||
|
super.removeFromGame();
|
||||||
|
getHostCard().getGame().removeSpellAbility(this.getWrappedAbility());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -638,7 +638,13 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
frozenStack.remove(si);
|
frozenStack.remove(si);
|
||||||
game.updateStackForView();
|
game.updateStackForView();
|
||||||
SpellAbility sa = si.getSpellAbility(true);
|
SpellAbility sa = si.getSpellAbility(true);
|
||||||
|
sa.setLastStateBattlefield(CardCollection.EMPTY);
|
||||||
|
sa.setLastStateGraveyard(CardCollection.EMPTY);
|
||||||
game.fireEvent(new GameEventSpellRemovedFromStack(sa));
|
game.fireEvent(new GameEventSpellRemovedFromStack(sa));
|
||||||
|
|
||||||
|
if (sa.isTrigger()) {
|
||||||
|
sa.removeFromGame();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void remove(final Card c) {
|
public final void remove(final Card c) {
|
||||||
|
|||||||
Reference in New Issue
Block a user