Costs Tag Tracking part 2: Tag system and X values, reworked deep copy code (#11406)

* Implement Costs Tag Map system

* Use Costs Tag Map system to store X value for spells, abilities, and resolving permanents

* Store Bestow without target's tags
Change functions for getting tags and storing the tags of a new permanent

* Create and use deep copy function in CardUtil, add Copyable<T> to many classes

* Fix Hall Of the Bandit Lord infinite loop

* Add additional comments

* Don't store null/empty costs tags maps (saves memory)

* Fix two more Watchers with Ability variable

* Add check for exact collection types during deep copy

* Use generics instead of pure type erasure during deep copy

* convert more code to using deep copy helper, everything use Object copier, add EnumMap

* fix documentation

* Don't need the separate null checks anymore (handled in deepCopyObject)

* Minor cleanup
This commit is contained in:
ssk97 2023-11-16 11:12:32 -08:00 committed by GitHub
parent 72e30f1574
commit bea33c7493
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 458 additions and 338 deletions

View file

@ -83,6 +83,7 @@ public abstract class AbilityImpl implements Ability {
protected MageIdentifier identifier = MageIdentifier.Default; // used to identify specific ability (e.g. to match with corresponding watcher)
protected String appendToRule = null;
protected int sourcePermanentTransformCount = 0;
private Map<String, Object> costsTagMap = null;
protected AbilityImpl(AbilityType abilityType, Zone zone) {
this.id = UUID.randomUUID();
@ -107,16 +108,9 @@ public abstract class AbilityImpl implements Ability {
this.manaCosts = ability.manaCosts.copy();
this.manaCostsToPay = ability.manaCostsToPay.copy();
this.costs = ability.costs.copy();
for (Watcher watcher : ability.getWatchers()) {
watchers.add(watcher.copy());
}
this.watchers = CardUtil.deepCopyObject(ability.getWatchers());
if (ability.subAbilities != null) {
this.subAbilities = new ArrayList<>();
for (Ability subAbility : ability.subAbilities) {
subAbilities.add(subAbility.copy());
}
}
this.subAbilities = CardUtil.deepCopyObject(ability.subAbilities);
this.modes = ability.getModes().copy();
this.ruleAtTheTop = ability.ruleAtTheTop;
this.ruleVisible = ability.ruleVisible;
@ -129,17 +123,14 @@ public abstract class AbilityImpl implements Ability {
this.canFizzle = ability.canFizzle;
this.targetAdjuster = ability.targetAdjuster;
this.costAdjuster = ability.costAdjuster;
for (Hint hint : ability.getHints()) {
this.hints.add(hint.copy());
}
for (CardIcon icon : ability.getIcons()) {
this.icons.add(icon.copy());
}
this.hints = CardUtil.deepCopyObject(ability.getHints());
this.icons = CardUtil.deepCopyObject(ability.getIcons());
this.customOutcome = ability.customOutcome;
this.identifier = ability.identifier;
this.activated = ability.activated;
this.appendToRule = ability.appendToRule;
this.sourcePermanentTransformCount = ability.sourcePermanentTransformCount;
this.costsTagMap = CardUtil.deepCopyObject(ability.costsTagMap);
}
@Override
@ -527,6 +518,7 @@ public abstract class AbilityImpl implements Ability {
((Cost) variableCost).setPaid();
String message = controller.getLogName() + " announces a value of " + xValue + " (" + variableCost.getActionText() + ')';
announceString.append(message);
setCostsTag("X",xValue);
}
}
return announceString.toString();
@ -631,6 +623,7 @@ public abstract class AbilityImpl implements Ability {
}
addManaCostsToPay(new ManaCostsImpl<>(manaString.toString()));
getManaCostsToPay().setX(xValue * xValueMultiplier, amountMana);
setCostsTag("X",xValue * xValueMultiplier);
}
variableManaCost.setPaid();
}
@ -713,6 +706,28 @@ public abstract class AbilityImpl implements Ability {
return manaCostsToPay;
}
/**
* Accessed to see what was optional/variable costs were paid
*
* @return
*/
@Override
public Map<String, Object> getCostsTagMap() {
return costsTagMap;
}
public void setCostsTag(String tag, Object value){
if (costsTagMap == null){
costsTagMap = new HashMap<>();
}
costsTagMap.put(tag, value);
}
public Object getCostsTagOrDefault(String tag, Object defaultValue){
if (costsTagMap != null && costsTagMap.containsKey(tag)){
return costsTagMap.get(tag);
}
return defaultValue;
}
@Override
public Effects getEffects() {
return getModes().getMode().getEffects();