Reworked cost adjuster logic for better support of X and cost modification effects:

Improves:
* refactor: split CostAdjuster logic in multiple parts - prepare X, prepare cost, increase cost, reduce cost;
* refactor: improved VariableManaCost to support min/max values, playable and AI calculations, test framework;
* refactor: improved EarlyTargetCost to support mana costs too (related to #13023);
* refactor: migrated some cards with CostAdjuster and X to EarlyTargetCost (Knollspine Invocation, etc - related to #13023);
* refactor: added shared code for "As an additional cost to cast this spell, discard X creature cards";
* refactor: added shared code for "X is the converted mana cost of the exiled card";
* tests: added dozens tests with cost adjusters;

Bug fixes:
* game: fixed that some cards with CostAdjuster ignore min/max limits for X (allow to choose any X, example: Scorched Earth, Open The Way);
* game: fixed that some cards ask to announce already defined X values (example: Bargaining Table);
* game: fixed that some cards with CostAdjuster do not support combo with other cost modification effects;
* game, gui: fixed missing game logs about predefined X values;
* game, gui: fixed wrong X icon for predefined X values;

Test framework:
* test framework: added X min/max check for wrong values;
* test framework: added X min/max info in miss X value announce;
* test framework: added check to find duplicated effect bugs (see assertNoDuplicatedEffects);

Cards:
* Open The Way - fixed that it allow to choose any X without limits (close #12810);
* Unbound Flourishing - improved combo support for activated abilities with predefined X mana costs like Bargaining Table;
This commit is contained in:
Oleg Agafonov 2025-04-08 22:39:10 +04:00
parent 13a832ae00
commit bae3089abb
100 changed files with 1519 additions and 449 deletions

View file

@ -688,6 +688,8 @@ public class ContinuousEffects implements Serializable {
* the battlefield for
* {@link CostModificationEffect cost modification effects} and applies them
* if necessary.
* <p>
* Warning, don't forget to call ability.adjustX before any cost modifications
*
* @param abilityToModify
* @param game
@ -695,6 +697,10 @@ public class ContinuousEffects implements Serializable {
public void costModification(Ability abilityToModify, Game game) {
List<CostModificationEffect> costEffects = getApplicableCostModificationEffects(game);
// add dynamic costs from X and other places
abilityToModify.adjustCostsPrepare(game);
abilityToModify.adjustCostsModify(game, CostModificationType.INCREASE_COST);
for (CostModificationEffect effect : costEffects) {
if (effect.getModificationType() == CostModificationType.INCREASE_COST) {
Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());
@ -706,6 +712,7 @@ public class ContinuousEffects implements Serializable {
}
}
abilityToModify.adjustCostsModify(game, CostModificationType.REDUCE_COST);
for (CostModificationEffect effect : costEffects) {
if (effect.getModificationType() == CostModificationType.REDUCE_COST) {
Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());
@ -717,6 +724,7 @@ public class ContinuousEffects implements Serializable {
}
}
abilityToModify.adjustCostsModify(game, CostModificationType.SET_COST);
for (CostModificationEffect effect : costEffects) {
if (effect.getModificationType() == CostModificationType.SET_COST) {
Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());