ColorlessDamageSource as StaticAbility (#6007)

* ColorlessDamageSource as StaticAbility
This commit is contained in:
Hans Mackowiak
2024-08-29 10:06:58 +02:00
committed by GitHub
parent 3111e73a63
commit 239e327f0b
4 changed files with 67 additions and 47 deletions

View File

@@ -2,6 +2,7 @@ package forge.game;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.card.CardTypeView;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaAtom; import forge.card.mana.ManaAtom;
@@ -20,6 +21,7 @@ import forge.game.spellability.SpellAbilityPredicates;
import forge.game.spellability.TargetChoices; import forge.game.spellability.TargetChoices;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityCastWithFlash; import forge.game.staticability.StaticAbilityCastWithFlash;
import forge.game.staticability.StaticAbilityColorlessDamageSource;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Expressions; import forge.util.Expressions;
@@ -33,16 +35,19 @@ public class ForgeScript {
public static boolean cardStateHasProperty(CardState cardState, String property, Player sourceController, public static boolean cardStateHasProperty(CardState cardState, String property, Player sourceController,
Card source, CardTraitBase spellAbility) { Card source, CardTraitBase spellAbility) {
final boolean isColorlessSource = cardState.getCard().hasKeyword("Colorless Damage Source", cardState);
final ColorSet colors = cardState.getCard().getColor(cardState); boolean withSource = property.endsWith("Source");
final ColorSet colors;
if (withSource && StaticAbilityColorlessDamageSource.colorlessDamageSource(cardState)) {
colors = ColorSet.getNullColor();
} else {
colors = cardState.getCard().getColor(cardState);
}
final CardTypeView type = cardState.getTypeWithChanges();
if (property.contains("White") || property.contains("Blue") || property.contains("Black") if (property.contains("White") || property.contains("Blue") || property.contains("Black")
|| property.contains("Red") || property.contains("Green")) { || property.contains("Red") || property.contains("Green")) {
boolean mustHave = !property.startsWith("non"); boolean mustHave = !property.startsWith("non");
boolean withSource = property.endsWith("Source");
if (withSource && isColorlessSource) {
return false;
}
final String colorName = property.substring(mustHave ? 0 : 3, property.length() - (withSource ? 6 : 0)); final String colorName = property.substring(mustHave ? 0 : 3, property.length() - (withSource ? 6 : 0));
int desiredColor = MagicColor.fromName(colorName); int desiredColor = MagicColor.fromName(colorName);
@@ -50,19 +55,11 @@ public class ForgeScript {
return mustHave == hasColor; return mustHave == hasColor;
} else if (property.contains("Colorless")) { // ... Card is colorless } else if (property.contains("Colorless")) { // ... Card is colorless
boolean non = property.startsWith("non"); boolean non = property.startsWith("non");
boolean withSource = property.endsWith("Source");
if (non && withSource && isColorlessSource) {
return false;
}
return non != colors.isColorless(); return non != colors.isColorless();
} else if (property.contains("MultiColor")) { } else if (property.startsWith("MultiColor")) {
// ... Card is multicolored // ... Card is multicolored
if (property.endsWith("Source") && isColorlessSource) return colors.isMulticolor();
return false; } else if (property.startsWith("EnemyColor")) {
return property.startsWith("non") != colors.isMulticolor();
} else if (property.contains("EnemyColor")) {
if (property.endsWith("Source") && isColorlessSource)
return false;
if (colors.countColors() != 2) { if (colors.countColors() != 2) {
return false; return false;
} }
@@ -73,44 +70,36 @@ public class ForgeScript {
} }
} }
return false; return false;
} else if (property.contains("AllColors")) { } else if (property.startsWith("AllColors")) {
if (property.endsWith("Source") && isColorlessSource) return colors.isAllColors();
return false; } else if (property.startsWith("MonoColor")) { // ... Card is monocolored
return property.startsWith("non") != colors.isAllColors(); return colors.isMonoColor();
} else if (property.contains("MonoColor")) { // ... Card is monocolored
if (property.endsWith("Source") && isColorlessSource)
return false;
return property.startsWith("non") != colors.isMonoColor();
} else if (property.startsWith("ChosenColor")) { } else if (property.startsWith("ChosenColor")) {
if (property.endsWith("Source") && isColorlessSource)
return false;
return source.hasChosenColor() && colors.hasAnyColor(MagicColor.fromName(source.getChosenColor())); return source.hasChosenColor() && colors.hasAnyColor(MagicColor.fromName(source.getChosenColor()));
} else if (property.startsWith("AnyChosenColor")) { } else if (property.startsWith("AnyChosenColor")) {
if (property.endsWith("Source") && isColorlessSource)
return false;
return source.hasChosenColor() return source.hasChosenColor()
&& colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor()); && colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor());
} else if (property.equals("AssociatedWithChosenColor")) { } else if (property.equals("AssociatedWithChosenColor")) {
final String color = source.getChosenColor(); final String color = source.getChosenColor();
switch (color) { switch (color) {
case "white": case "white":
return cardState.getTypeWithChanges().getLandTypes().contains("Plains"); return type.hasSubtype("Plains");
case "blue": case "blue":
return cardState.getTypeWithChanges().getLandTypes().contains("Island"); return type.hasSubtype("Island");
case "black": case "black":
return cardState.getTypeWithChanges().getLandTypes().contains("Swamp"); return type.hasSubtype("Swamp");
case "red": case "red":
return cardState.getTypeWithChanges().getLandTypes().contains("Mountain"); return type.hasSubtype("Mountain");
case "green": case "green":
return cardState.getTypeWithChanges().getLandTypes().contains("Forest"); return type.hasSubtype("Forest");
default: default:
return false; return false;
} }
} else if (property.equals("Outlaw")) { } else if (property.equals("Outlaw")) {
return cardState.getTypeWithChanges().isOutlaw(); return type.isOutlaw();
} else if (property.startsWith("non")) { } else if (property.startsWith("non")) {
// ... Other Card types // ... Other Card types
return !cardState.getTypeWithChanges().hasStringType(property.substring(3)); return !type.hasStringType(property.substring(3));
} else if (property.equals("CostsPhyrexianMana")) { } else if (property.equals("CostsPhyrexianMana")) {
return cardState.getManaCost().hasPhyrexian(); return cardState.getManaCost().hasPhyrexian();
} else if (property.startsWith("HasSVar")) { } else if (property.startsWith("HasSVar")) {
@@ -119,19 +108,19 @@ public class ForgeScript {
} else if (property.equals("ChosenType")) { } else if (property.equals("ChosenType")) {
String chosenType = source.getChosenType(); String chosenType = source.getChosenType();
if (chosenType.startsWith("Non")) { if (chosenType.startsWith("Non")) {
return !cardState.getTypeWithChanges().hasStringType(StringUtils.capitalize(chosenType.substring(3))); return !type.hasStringType(StringUtils.capitalize(chosenType.substring(3)));
} }
return cardState.getTypeWithChanges().hasStringType(chosenType); return type.hasStringType(chosenType);
} else if (property.equals("IsNotChosenType")) { } else if (property.equals("IsNotChosenType")) {
return !cardState.getTypeWithChanges().hasStringType(source.getChosenType()); return !type.hasStringType(source.getChosenType());
} else if (property.equals("ChosenType2")) { } else if (property.equals("ChosenType2")) {
return cardState.getTypeWithChanges().hasStringType(source.getChosenType2()); return type.hasStringType(source.getChosenType2());
} else if (property.equals("IsNotChosenType2")) { } else if (property.equals("IsNotChosenType2")) {
return !cardState.getTypeWithChanges().hasStringType(source.getChosenType2()); return !type.hasStringType(source.getChosenType2());
} else if (property.equals("NotedType")) { } else if (property.equals("NotedType")) {
boolean found = false; boolean found = false;
for (String s : source.getNotedTypes()) { for (String s : source.getNotedTypes()) {
if (cardState.getTypeWithChanges().hasStringType(s)) { if (type.hasStringType(s)) {
found = true; found = true;
break; break;
} }
@@ -187,7 +176,7 @@ public class ForgeScript {
int x = AbilityUtils.calculateAmount(source, rhs, spellAbility); int x = AbilityUtils.calculateAmount(source, rhs, spellAbility);
return Expressions.compare(y, property, x); return Expressions.compare(y, property, x);
} else return cardState.getTypeWithChanges().hasStringType(property); } else return type.hasStringType(property);
} }
public static boolean spellAbilityHasProperty(SpellAbility sa, String property, Player sourceController, public static boolean spellAbilityHasProperty(SpellAbility sa, String property, Player sourceController,

View File

@@ -0,0 +1,32 @@
package forge.game.staticability;
import forge.game.card.Card;
import forge.game.card.CardState;
import forge.game.zone.ZoneType;
public class StaticAbilityColorlessDamageSource {
static String MODE = "ColorlessDamageSource";
public static boolean colorlessDamageSource(final CardState state) {
final Card card = state.getCard();
for (final Card ca : card.getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(MODE)) {
continue;
}
if (applyColorlessDamageSource(stAb, card)) {
return true;
}
}
}
return false;
}
public static boolean applyColorlessDamageSource(final StaticAbility stAb, final Card card) {
if (!stAb.matchesValidParam("ValidCard", card)) {
return false;
}
return true;
}
}

View File

@@ -1,6 +1,6 @@
Name:Ghostly Flame Name:Ghostly Flame
ManaCost:B R ManaCost:B R
Types:Enchantment Types:Enchantment
S:Mode$ Continuous | Affected$ Permanent.Black,Permanent.Red,Spell.Red,Spell.Black | AffectedZone$ Stack,Battlefield | AddHiddenKeyword$ Colorless Damage Source | Description$ Black and/or red permanents and spells are colorless sources of damage. S:Mode$ ColorlessDamageSource | ValidCard$ Permanent.Black+inZoneBattlefield,Permanent.Red+inZoneBattlefield,Spell.Black+inZoneStack,Spell.Red+inZoneStack | Description$ Black and/or red permanents and spells are colorless sources of damage.
SVar:NonStackingEffect:True SVar:NonStackingEffect:True
Oracle:Black and/or red permanents and spells are colorless sources of damage. Oracle:Black and/or red permanents and spells are colorless sources of damage.

View File

@@ -440,8 +440,7 @@ public final class CardScriptParser {
"sameName", "namedCard", "NamedByRememberedPlayer", "Permanent", "sameName", "namedCard", "NamedByRememberedPlayer", "Permanent",
"ChosenCard", "nonChosenCard", "White", "Blue", "Black", "Red", "ChosenCard", "nonChosenCard", "White", "Blue", "Black", "Red",
"Green", "nonWhite", "nonBlue", "nonBlack", "nonRed", "nonGreen", "Green", "nonWhite", "nonBlue", "nonBlack", "nonRed", "nonGreen",
"Colorless", "nonColorless", "Multicolor", "nonMulticolor", "Colorless", "nonColorless", "Multicolor", "Monocolor", "ChosenColor", "AllChosenColors",
"Monocolor", "nonMonocolor", "ChosenColor", "AllChosenColors",
"AnyChosenColor", "DoubleFaced", "Flip", "YouCtrl", "YourTeamCtrl", "AnyChosenColor", "DoubleFaced", "Flip", "YouCtrl", "YourTeamCtrl",
"YouDontCtrl", "OppCtrl", "ChosenCtrl", "DefenderCtrl", "YouDontCtrl", "OppCtrl", "ChosenCtrl", "DefenderCtrl",
"DefenderCtrlForRemembered", "DefendingPlayerCtrl", "DefenderCtrlForRemembered", "DefendingPlayerCtrl",