mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
Trigger & Replacement: ensure abilities
This commit is contained in:
@@ -23,7 +23,6 @@ import com.google.common.collect.Lists;
|
||||
import forge.ai.ability.AnimateAi;
|
||||
import forge.card.CardTypeView;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.effects.ProtectEffect;
|
||||
@@ -196,12 +195,12 @@ public class AiAttackController {
|
||||
for (Card c : ai.getOpponents().getCardsIn(ZoneType.Battlefield)) {
|
||||
for (Trigger t : c.getTriggers()) {
|
||||
if (t.getMode() == TriggerType.Attacks) {
|
||||
SpellAbility sa = t.getOverridingAbility();
|
||||
if (sa == null && t.hasParam("Execute")) {
|
||||
sa = AbilityFactory.getAbility(c, t.getParam("Execute"));
|
||||
SpellAbility sa = t.ensureAbility();
|
||||
if (sa == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa != null && sa.getApi() == ApiType.EachDamage && "TriggeredAttacker".equals(sa.getParam("DefinedPlayers"))) {
|
||||
if (sa.getApi() == ApiType.EachDamage && "TriggeredAttacker".equals(sa.getParam("DefinedPlayers"))) {
|
||||
List<Card> valid = CardLists.getValidCards(c.getController().getCreaturesInPlay(), sa.getParam("ValidCards"), c.getController(), c, sa);
|
||||
// TODO: this assumes that 1 damage is dealt per creature. Improve this to check the parameter/X to determine
|
||||
// how much damage is dealt by each of the creatures in the valid list.
|
||||
@@ -1349,9 +1348,9 @@ public class AiAttackController {
|
||||
if (!TriggerType.Exerted.equals(t.getMode())) {
|
||||
continue;
|
||||
}
|
||||
SpellAbility sa = t.getOverridingAbility();
|
||||
SpellAbility sa = t.ensureAbility();
|
||||
if (sa == null) {
|
||||
sa = AbilityFactory.getAbility(c, t.getParam("Execute"));
|
||||
continue;
|
||||
}
|
||||
if (sa.usesTargeting()) {
|
||||
sa.setActivatingPlayer(c.getController());
|
||||
|
||||
@@ -28,7 +28,6 @@ import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.*;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
@@ -1468,15 +1467,13 @@ public class ComputerUtil {
|
||||
// Triggered abilities
|
||||
if (c.isCreature() && c.isInZone(ZoneType.Battlefield) && CombatUtil.canAttack(c)) {
|
||||
for (final Trigger t : c.getTriggers()) {
|
||||
if ("Attacks".equals(t.getParam("Mode")) && t.hasParam("Execute")) {
|
||||
String exec = c.getSVar(t.getParam("Execute"));
|
||||
if (!exec.isEmpty()) {
|
||||
SpellAbility trigSa = AbilityFactory.getAbility(exec, c);
|
||||
if (trigSa != null && trigSa.getApi() == ApiType.LoseLife
|
||||
&& trigSa.getParamOrDefault("Defined", "").contains("Opponent")) {
|
||||
trigSa.setHostCard(c);
|
||||
damage += AbilityUtils.calculateAmount(trigSa.getHostCard(), trigSa.getParam("LifeAmount"), trigSa);
|
||||
}
|
||||
if (TriggerType.Attacks.equals(t.getMode())) {
|
||||
SpellAbility sa = t.ensureAbility();
|
||||
if (sa == null) {
|
||||
continue;
|
||||
}
|
||||
if (sa.getApi() == ApiType.LoseLife && sa.getParamOrDefault("Defined", "").contains("Opponent")) {
|
||||
damage += AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2612,7 +2609,6 @@ public class ComputerUtil {
|
||||
theTriggers.addAll(c.getTriggers());
|
||||
}
|
||||
for (Trigger trigger : theTriggers) {
|
||||
Map<String, String> trigParams = trigger.getMapParams();
|
||||
final Card source = trigger.getHostCard();
|
||||
|
||||
|
||||
@@ -2622,73 +2618,43 @@ public class ComputerUtil {
|
||||
if (!trigger.requirementsCheck(game)) {
|
||||
continue;
|
||||
}
|
||||
TriggerType mode = trigger.getMode();
|
||||
if (mode != TriggerType.SpellCast) {
|
||||
if (trigger.getMode() != TriggerType.SpellCast) {
|
||||
continue;
|
||||
}
|
||||
if (trigParams.containsKey("ValidCard")) {
|
||||
if (!card.isValid(trigParams.get("ValidCard"), source.getController(), source, sa)) {
|
||||
if (trigger.hasParam("ValidCard")) {
|
||||
if (!card.isValid(trigger.getParam("ValidCard"), source.getController(), source, sa)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (trigParams.containsKey("ValidActivatingPlayer")) {
|
||||
if (!player.isValid(trigParams.get("ValidActivatingPlayer"), source.getController(), source, sa)) {
|
||||
if (trigger.hasParam("ValidActivatingPlayer")) {
|
||||
if (!player.isValid(trigger.getParam("ValidActivatingPlayer"), source.getController(), source, sa)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!trigParams.containsKey("Execute")) {
|
||||
// fall back for OverridingAbility
|
||||
SpellAbility trigSa = trigger.getOverridingAbility();
|
||||
if (trigSa == null) {
|
||||
// fall back for OverridingAbility
|
||||
SpellAbility trigSa = trigger.ensureAbility();
|
||||
if (trigSa == null) {
|
||||
continue;
|
||||
}
|
||||
if (trigSa.getApi() == ApiType.DealDamage) {
|
||||
if (!"TriggeredActivator".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (trigSa.getApi() == ApiType.DealDamage) {
|
||||
if (!"TriggeredActivator".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!trigSa.hasParam("NumDmg")) {
|
||||
continue;
|
||||
}
|
||||
damage += ComputerUtilCombat.predictDamageTo(player,
|
||||
AbilityUtils.calculateAmount(source, trigSa.getParam("NumDmg"), trigSa), source, false);
|
||||
} else if (trigSa.getApi() == ApiType.LoseLife) {
|
||||
if (!"TriggeredActivator".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!trigSa.hasParam("LifeAmount")) {
|
||||
continue;
|
||||
}
|
||||
damage += AbilityUtils.calculateAmount(source, trigSa.getParam("LifeAmount"), trigSa);
|
||||
}
|
||||
} else {
|
||||
String ability = source.getSVar(trigParams.get("Execute"));
|
||||
if (ability.isEmpty()) {
|
||||
if (!trigSa.hasParam("NumDmg")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Map<String, String> abilityParams = AbilityFactory.getMapParams(ability);
|
||||
if ((abilityParams.containsKey("AB") && abilityParams.get("AB").equals("DealDamage"))
|
||||
|| (abilityParams.containsKey("DB") && abilityParams.get("DB").equals("DealDamage"))) {
|
||||
if (!"TriggeredActivator".equals(abilityParams.get("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!abilityParams.containsKey("NumDmg")) {
|
||||
continue;
|
||||
}
|
||||
damage += ComputerUtilCombat.predictDamageTo(player,
|
||||
AbilityUtils.calculateAmount(source, abilityParams.get("NumDmg"), null), source, false);
|
||||
} else if ((abilityParams.containsKey("AB") && abilityParams.get("AB").equals("LoseLife"))
|
||||
|| (abilityParams.containsKey("DB") && abilityParams.get("DB").equals("LoseLife"))) {
|
||||
if (!"TriggeredActivator".equals(abilityParams.get("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!abilityParams.containsKey("LifeAmount")) {
|
||||
continue;
|
||||
}
|
||||
damage += AbilityUtils.calculateAmount(source, abilityParams.get("LifeAmount"), null);
|
||||
damage += ComputerUtilCombat.predictDamageTo(player,
|
||||
AbilityUtils.calculateAmount(source, trigSa.getParam("NumDmg"), trigSa), source, false);
|
||||
} else if (trigSa.getApi() == ApiType.LoseLife) {
|
||||
if (!"TriggeredActivator".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!trigSa.hasParam("LifeAmount")) {
|
||||
continue;
|
||||
}
|
||||
damage += AbilityUtils.calculateAmount(source, trigSa.getParam("LifeAmount"), trigSa);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2704,7 +2670,6 @@ public class ComputerUtil {
|
||||
theTriggers.addAll(card.getTriggers());
|
||||
}
|
||||
for (Trigger trigger : theTriggers) {
|
||||
Map<String, String> trigParams = trigger.getMapParams();
|
||||
final Card source = trigger.getHostCard();
|
||||
|
||||
|
||||
@@ -2714,74 +2679,43 @@ public class ComputerUtil {
|
||||
if (!trigger.requirementsCheck(game)) {
|
||||
continue;
|
||||
}
|
||||
if (trigParams.containsKey("CheckOnTriggeredCard")
|
||||
&& AbilityUtils.getDefinedCards(permanent, source.getSVar(trigParams.get("CheckOnTriggeredCard").split(" ")[0]), null).isEmpty()) {
|
||||
if (trigger.hasParam("CheckOnTriggeredCard")
|
||||
&& AbilityUtils.getDefinedCards(permanent, source.getSVar(trigger.getParam("CheckOnTriggeredCard").split(" ")[0]), null).isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
TriggerType mode = trigger.getMode();
|
||||
if (mode != TriggerType.ChangesZone) {
|
||||
if (trigger.getMode() != TriggerType.ChangesZone) {
|
||||
continue;
|
||||
}
|
||||
if (!"Battlefield".equals(trigParams.get("Destination"))) {
|
||||
if (!"Battlefield".equals(trigger.getParam("Destination"))) {
|
||||
continue;
|
||||
}
|
||||
if (trigParams.containsKey("ValidCard")) {
|
||||
if (!permanent.isValid(trigParams.get("ValidCard"), source.getController(), source, null)) {
|
||||
if (trigger.hasParam("ValidCard")) {
|
||||
if (!permanent.isValid(trigger.getParam("ValidCard"), source.getController(), source, null)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!trigParams.containsKey("Execute")) {
|
||||
// fall back for OverridingAbility
|
||||
SpellAbility trigSa = trigger.getOverridingAbility();
|
||||
if (trigSa == null) {
|
||||
// fall back for OverridingAbility
|
||||
SpellAbility trigSa = trigger.ensureAbility();
|
||||
if (trigSa == null) {
|
||||
continue;
|
||||
}
|
||||
if (trigSa.getApi() == ApiType.DealDamage) {
|
||||
if (!"TriggeredCardController".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (trigSa.getApi() == ApiType.DealDamage) {
|
||||
if (!"TriggeredCardController".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!trigSa.hasParam("NumDmg")) {
|
||||
continue;
|
||||
}
|
||||
damage += ComputerUtilCombat.predictDamageTo(player,
|
||||
AbilityUtils.calculateAmount(source, trigSa.getParam("NumDmg"), trigSa), source, false);
|
||||
} else if (trigSa.getApi() == ApiType.LoseLife) {
|
||||
if (!"TriggeredCardController".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!trigSa.hasParam("LifeAmount")) {
|
||||
continue;
|
||||
}
|
||||
damage += AbilityUtils.calculateAmount(source, trigSa.getParam("LifeAmount"), trigSa);
|
||||
}
|
||||
} else {
|
||||
String ability = source.getSVar(trigParams.get("Execute"));
|
||||
if (ability.isEmpty()) {
|
||||
if (!trigSa.hasParam("NumDmg")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Map<String, String> abilityParams = AbilityFactory.getMapParams(ability);
|
||||
// Destroy triggers
|
||||
if ((abilityParams.containsKey("AB") && abilityParams.get("AB").equals("DealDamage"))
|
||||
|| (abilityParams.containsKey("DB") && abilityParams.get("DB").equals("DealDamage"))) {
|
||||
if (!"TriggeredCardController".equals(abilityParams.get("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!abilityParams.containsKey("NumDmg")) {
|
||||
continue;
|
||||
}
|
||||
damage += ComputerUtilCombat.predictDamageTo(player,
|
||||
AbilityUtils.calculateAmount(source, abilityParams.get("NumDmg"), null), source, false);
|
||||
} else if ((abilityParams.containsKey("AB") && abilityParams.get("AB").equals("LoseLife"))
|
||||
|| (abilityParams.containsKey("DB") && abilityParams.get("DB").equals("LoseLife"))) {
|
||||
if (!"TriggeredCardController".equals(abilityParams.get("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!abilityParams.containsKey("LifeAmount")) {
|
||||
continue;
|
||||
}
|
||||
damage += AbilityUtils.calculateAmount(source, abilityParams.get("LifeAmount"), null);
|
||||
damage += ComputerUtilCombat.predictDamageTo(player,
|
||||
AbilityUtils.calculateAmount(source, trigSa.getParam("NumDmg"), trigSa), source, false);
|
||||
} else if (trigSa.getApi() == ApiType.LoseLife) {
|
||||
if (!"TriggeredCardController".equals(trigSa.getParam("Defined"))) {
|
||||
continue;
|
||||
}
|
||||
if (!trigSa.hasParam("LifeAmount")) {
|
||||
continue;
|
||||
}
|
||||
damage += AbilityUtils.calculateAmount(source, trigSa.getParam("LifeAmount"), trigSa);
|
||||
}
|
||||
}
|
||||
return damage;
|
||||
|
||||
@@ -14,7 +14,6 @@ import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.*;
|
||||
@@ -697,39 +696,21 @@ public class ComputerUtilCard {
|
||||
}
|
||||
// same for Trigger that does make Tokens
|
||||
for(Trigger t:c.getTriggers()){
|
||||
SpellAbility sa = t.getOverridingAbility();
|
||||
String sTokenTypes = null;
|
||||
SpellAbility sa = t.ensureAbility();
|
||||
if (sa != null) {
|
||||
if (sa.getApi() != ApiType.Token || !sa.hasParam("TokenTypes")) {
|
||||
continue;
|
||||
}
|
||||
sTokenTypes = sa.getParam("TokenTypes");
|
||||
} else if (t.hasParam("Execute")) {
|
||||
String name = t.getParam("Execute");
|
||||
if (!c.hasSVar(name)) {
|
||||
continue;
|
||||
for (String var : sa.getParam("TokenTypes").split(",")) {
|
||||
if (!CardType.isACreatureType(var)) {
|
||||
continue;
|
||||
}
|
||||
Integer count = typesInDeck.get(var);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
typesInDeck.put(var, count + 1);
|
||||
}
|
||||
|
||||
Map<String, String> params = AbilityFactory.getMapParams(c.getSVar(name));
|
||||
if (!params.containsKey("TokenTypes")) {
|
||||
continue;
|
||||
}
|
||||
sTokenTypes = params.get("TokenTypes");
|
||||
}
|
||||
|
||||
if (sTokenTypes == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String var : sTokenTypes.split(",")) {
|
||||
if (!CardType.isACreatureType(var)) {
|
||||
continue;
|
||||
}
|
||||
Integer count = typesInDeck.get(var);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
typesInDeck.put(var, count + 1);
|
||||
}
|
||||
}
|
||||
// special rule for Fabricate and Servo
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.google.common.collect.Maps;
|
||||
import forge.game.CardTraitBase;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
@@ -46,7 +45,6 @@ import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.MyRandom;
|
||||
@@ -1274,44 +1272,26 @@ public class ComputerUtilCombat {
|
||||
}
|
||||
|
||||
for (final Trigger trigger : theTriggers) {
|
||||
final Map<String, String> trigParams = trigger.getMapParams();
|
||||
final Card source = trigger.getHostCard();
|
||||
|
||||
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, combat)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, String> abilityParams = null;
|
||||
if (trigger.getOverridingAbility() != null) {
|
||||
abilityParams = trigger.getOverridingAbility().getMapParams();
|
||||
} else if (trigParams.containsKey("Execute")) {
|
||||
final String ability = source.getSVar(trigParams.get("Execute"));
|
||||
abilityParams = AbilityFactory.getMapParams(ability);
|
||||
} else {
|
||||
SpellAbility sa = trigger.ensureAbility();
|
||||
if (sa == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abilityParams.containsKey("ValidTgts") || abilityParams.containsKey("Tgt")) {
|
||||
if (sa.usesTargeting()) {
|
||||
continue; // targeted pumping not supported
|
||||
}
|
||||
if (abilityParams.containsKey("AB") && !abilityParams.get("AB").equals("Pump")
|
||||
&& !abilityParams.get("AB").equals("PumpAll")) {
|
||||
continue;
|
||||
}
|
||||
if (abilityParams.containsKey("DB") && !abilityParams.get("DB").equals("Pump")
|
||||
&& !abilityParams.get("DB").equals("PumpAll")) {
|
||||
|
||||
if (!ApiType.Pump.equals(sa.getApi()) && !ApiType.PumpAll.equals(sa.getApi())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abilityParams.containsKey("Cost")) {
|
||||
SpellAbility sa = null;
|
||||
if (trigger.getOverridingAbility() != null) {
|
||||
sa = trigger.getOverridingAbility();
|
||||
} else {
|
||||
final String ability = source.getSVar(trigParams.get("Execute"));
|
||||
sa = AbilityFactory.getAbility(ability, source);
|
||||
}
|
||||
|
||||
if (sa.hasParam("Cost")) {
|
||||
sa.setActivatingPlayer(source.getController());
|
||||
if (!CostPayment.canPayAdditionalCosts(sa.getPayCosts(), sa)) {
|
||||
continue;
|
||||
@@ -1319,15 +1299,15 @@ public class ComputerUtilCombat {
|
||||
}
|
||||
|
||||
List<Card> list = Lists.newArrayList();
|
||||
if (!abilityParams.containsKey("ValidCards")) {
|
||||
list = AbilityUtils.getDefinedCards(source, abilityParams.get("Defined"), null);
|
||||
if (!sa.hasParam("ValidCards")) {
|
||||
list = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), null);
|
||||
}
|
||||
if (abilityParams.containsKey("Defined") && abilityParams.get("Defined").equals("TriggeredAttacker")) {
|
||||
if (sa.hasParam("Defined") && sa.getParam("Defined").equals("TriggeredAttacker")) {
|
||||
list.add(attacker);
|
||||
}
|
||||
if (abilityParams.containsKey("ValidCards")) {
|
||||
if (attacker.isValid(abilityParams.get("ValidCards").split(","), source.getController(), source, null)
|
||||
|| attacker.isValid(abilityParams.get("ValidCards").replace("attacking+", "").split(","),
|
||||
if (sa.hasParam("ValidCards")) {
|
||||
if (attacker.isValid(sa.getParam("ValidCards").split(","), source.getController(), source, null)
|
||||
|| attacker.isValid(sa.getParam("ValidCards").replace("attacking+", "").split(","),
|
||||
source.getController(), source, null)) {
|
||||
list.add(attacker);
|
||||
}
|
||||
@@ -1338,11 +1318,11 @@ public class ComputerUtilCombat {
|
||||
if (!list.contains(attacker)) {
|
||||
continue;
|
||||
}
|
||||
if (!abilityParams.containsKey("NumAtt")) {
|
||||
if (!sa.hasParam("NumAtt")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String att = abilityParams.get("NumAtt");
|
||||
String att = sa.getParam("NumAtt");
|
||||
if (att.startsWith("+")) {
|
||||
att = att.substring(1);
|
||||
}
|
||||
@@ -1657,35 +1637,26 @@ public class ComputerUtilCombat {
|
||||
theTriggers.addAll(card.getTriggers());
|
||||
}
|
||||
for (Trigger trigger : theTriggers) {
|
||||
Map<String, String> trigParams = trigger.getMapParams();
|
||||
final Card source = trigger.getHostCard();
|
||||
|
||||
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
|
||||
continue;
|
||||
}
|
||||
//consider delayed triggers
|
||||
if (trigParams.containsKey("DelayedTrigger")) {
|
||||
String sVarName = trigParams.get("DelayedTrigger");
|
||||
trigger = TriggerHandler.parseTrigger(source.getSVar(sVarName), trigger.getHostCard(), true);
|
||||
trigParams = trigger.getMapParams();
|
||||
}
|
||||
if (!trigParams.containsKey("Execute")) {
|
||||
SpellAbility sa = trigger.ensureAbility();
|
||||
if (sa == null) {
|
||||
continue;
|
||||
}
|
||||
String ability = source.getSVar(trigParams.get("Execute"));
|
||||
final Map<String, String> abilityParams = AbilityFactory.getMapParams(ability);
|
||||
if ((abilityParams.containsKey("AB") && abilityParams.get("AB").equals("Destroy"))
|
||||
|| (abilityParams.containsKey("DB") && abilityParams.get("DB").equals("Destroy"))) {
|
||||
if (!abilityParams.containsKey("Defined")) {
|
||||
if (ApiType.Destroy.equals(sa.getApi())) {
|
||||
if (!sa.hasParam("Defined")) {
|
||||
continue;
|
||||
}
|
||||
if (abilityParams.get("Defined").equals("TriggeredAttacker")) {
|
||||
if (sa.getParam("Defined").equals("TriggeredAttacker")) {
|
||||
return true;
|
||||
}
|
||||
if (abilityParams.get("Defined").equals("Self") && source.equals(attacker)) {
|
||||
if (sa.getParam("Defined").equals("Self") && source.equals(attacker)) {
|
||||
return true;
|
||||
}
|
||||
if (abilityParams.get("Defined").equals("TriggeredTarget") && source.equals(blocker)) {
|
||||
if (sa.getParam("Defined").equals("TriggeredTarget") && source.equals(blocker)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1935,36 +1906,27 @@ public class ComputerUtilCombat {
|
||||
theTriggers.addAll(card.getTriggers());
|
||||
}
|
||||
for (Trigger trigger : theTriggers) {
|
||||
Map<String, String> trigParams = trigger.getMapParams();
|
||||
final Card source = trigger.getHostCard();
|
||||
|
||||
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
|
||||
continue;
|
||||
}
|
||||
//consider delayed triggers
|
||||
if (trigParams.containsKey("DelayedTrigger")) {
|
||||
String sVarName = trigParams.get("DelayedTrigger");
|
||||
trigger = TriggerHandler.parseTrigger(source.getSVar(sVarName), trigger.getHostCard(), true);
|
||||
trigParams = trigger.getMapParams();
|
||||
}
|
||||
if (!trigParams.containsKey("Execute")) {
|
||||
SpellAbility sa = trigger.ensureAbility();
|
||||
if (sa == null) {
|
||||
continue;
|
||||
}
|
||||
String ability = source.getSVar(trigParams.get("Execute"));
|
||||
final Map<String, String> abilityParams = AbilityFactory.getMapParams(ability);
|
||||
// Destroy triggers
|
||||
if ((abilityParams.containsKey("AB") && abilityParams.get("AB").equals("Destroy"))
|
||||
|| (abilityParams.containsKey("DB") && abilityParams.get("DB").equals("Destroy"))) {
|
||||
if (!abilityParams.containsKey("Defined")) {
|
||||
if (ApiType.Destroy.equals(sa.getApi())) {
|
||||
if (!sa.hasParam("Defined")) {
|
||||
continue;
|
||||
}
|
||||
if (abilityParams.get("Defined").equals("TriggeredBlocker")) {
|
||||
if (sa.getParam("Defined").equals("TriggeredBlocker")) {
|
||||
return true;
|
||||
}
|
||||
if (abilityParams.get("Defined").equals("Self") && source.equals(blocker)) {
|
||||
if (sa.getParam("Defined").equals("Self") && source.equals(blocker)) {
|
||||
return true;
|
||||
}
|
||||
if (abilityParams.get("Defined").equals("TriggeredTarget") && source.equals(attacker)) {
|
||||
if (sa.getParam("Defined").equals("TriggeredTarget") && source.equals(attacker)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2578,26 +2540,24 @@ public class ComputerUtilCombat {
|
||||
|
||||
// Test for some special triggers that can change the creature in combat
|
||||
for (Trigger t : attacker.getTriggers()) {
|
||||
if (t.getMode() == TriggerType.Attacks && t.hasParam("Execute")) {
|
||||
if (!attacker.hasSVar(t.getParam("Execute"))) {
|
||||
if (t.getMode() == TriggerType.Attacks) {
|
||||
SpellAbility exec = t.ensureAbility();
|
||||
if (exec == null) {
|
||||
continue;
|
||||
}
|
||||
SpellAbility exec = AbilityFactory.getAbility(attacker, t.getParam("Execute"));
|
||||
if (exec != null) {
|
||||
if (exec.getApi() == ApiType.Clone && "Self".equals(exec.getParam("CloneTarget"))
|
||||
&& exec.hasParam("ValidTgts") && exec.getParam("ValidTgts").contains("Creature")
|
||||
&& exec.getParam("ValidTgts").contains("attacking")) {
|
||||
// Tilonalli's Skinshifter and potentially other similar cards that can clone other stuff
|
||||
// while attacking
|
||||
if (exec.getParam("ValidTgts").contains("nonLegendary") && attacker.getType().isLegendary()) {
|
||||
continue;
|
||||
}
|
||||
int maxPwr = 0;
|
||||
for (Card c : attacker.getController().getCreaturesInPlay()) {
|
||||
if (c.getNetPower() > maxPwr || (c.getNetPower() == maxPwr && ComputerUtilCard.evaluateCreature(c) > ComputerUtilCard.evaluateCreature(attackerAfterTrigs))) {
|
||||
maxPwr = c.getNetPower();
|
||||
attackerAfterTrigs = c;
|
||||
}
|
||||
if (exec.getApi() == ApiType.Clone && "Self".equals(exec.getParam("CloneTarget"))
|
||||
&& exec.hasParam("ValidTgts") && exec.getParam("ValidTgts").contains("Creature")
|
||||
&& exec.getParam("ValidTgts").contains("attacking")) {
|
||||
// Tilonalli's Skinshifter and potentially other similar cards that can clone other stuff
|
||||
// while attacking
|
||||
if (exec.getParam("ValidTgts").contains("nonLegendary") && attacker.getType().isLegendary()) {
|
||||
continue;
|
||||
}
|
||||
int maxPwr = 0;
|
||||
for (Card c : attacker.getController().getCreaturesInPlay()) {
|
||||
if (c.getNetPower() > maxPwr || (c.getNetPower() == maxPwr && ComputerUtilCard.evaluateCreature(c) > ComputerUtilCard.evaluateCreature(attackerAfterTrigs))) {
|
||||
maxPwr = c.getNetPower();
|
||||
attackerAfterTrigs = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameType;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.*;
|
||||
@@ -636,10 +635,7 @@ public class SpecialCardAi {
|
||||
boolean canRetFromGrave = false;
|
||||
String name = c.getName().replace(',', ';');
|
||||
for (Trigger t : c.getTriggers()) {
|
||||
SpellAbility ab = null;
|
||||
if (t.hasParam("Execute")) {
|
||||
ab = AbilityFactory.getAbility(c.getSVar(t.getParam("Execute")), c);
|
||||
}
|
||||
SpellAbility ab = t.ensureAbility();
|
||||
if (ab == null) { continue; }
|
||||
|
||||
if (ab.getApi() == ApiType.ChangeZone
|
||||
|
||||
@@ -1086,12 +1086,7 @@ public class AttachAi extends SpellAbilityAi {
|
||||
final Map<String, String> params = t.getMapParams();
|
||||
if ("Card.Self".equals(params.get("ValidCard"))
|
||||
&& "Battlefield".equals(params.get("Destination"))) {
|
||||
SpellAbility trigSa = null;
|
||||
if (t.hasParam("Execute") && attachSource.hasSVar(t.getParam("Execute"))) {
|
||||
trigSa = AbilityFactory.getAbility(attachSource.getSVar(params.get("Execute")), attachSource);
|
||||
} else if (t.getOverridingAbility() != null) {
|
||||
trigSa = t.getOverridingAbility();
|
||||
}
|
||||
SpellAbility trigSa = t.ensureAbility();
|
||||
if (trigSa != null && trigSa.getApi() == ApiType.DealDamage && "Enchanted".equals(trigSa.getParam("Defined"))) {
|
||||
for (Card target : list) {
|
||||
if (!target.getController().isOpponentOf(ai)) {
|
||||
|
||||
@@ -1811,7 +1811,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
} else // This is an intrinsic effect that blinks the card (e.g. Obzedat, Ghost Council), no need to
|
||||
// return the commander to the Command zone.
|
||||
if (subApi == ApiType.DelayedTrigger) {
|
||||
SpellAbility exec = causeSub.getAdditionalAbility("Execute");
|
||||
SpellAbility exec = causeSub.getAdditionalAbility("Execute");
|
||||
if (exec != null && exec.getApi() == ApiType.ChangeZone) {
|
||||
// A blink effect implemented using a delayed trigger
|
||||
return !"Exile".equals(exec.getParam("Origin")) || !"Battlefield".equals(exec.getParam("Destination"));
|
||||
|
||||
@@ -3,7 +3,6 @@ package forge.ai.ability;
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.ai.*;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardLists;
|
||||
@@ -22,11 +21,9 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
// TODO: improve ai
|
||||
return true;
|
||||
}
|
||||
SpellAbility trigsa = null;
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
trigsa = sa.getAdditionalAbility("Execute");
|
||||
} else {
|
||||
trigsa = AbilityFactory.getAbility(sa.getHostCard(), sa.getParam("Execute"));
|
||||
SpellAbility trigsa = sa.getAdditionalAbility("Execute");
|
||||
if (trigsa == null) {
|
||||
return false;
|
||||
}
|
||||
trigsa.setActivatingPlayer(ai);
|
||||
|
||||
@@ -39,12 +36,11 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||
SpellAbility trigsa = null;
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
trigsa = sa.getAdditionalAbility("Execute");
|
||||
} else {
|
||||
trigsa = AbilityFactory.getAbility(sa.getHostCard(), sa.getParam("Execute"));
|
||||
SpellAbility trigsa = sa.getAdditionalAbility("Execute");
|
||||
if (trigsa == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
|
||||
trigsa.setActivatingPlayer(ai);
|
||||
|
||||
@@ -143,11 +139,9 @@ public class DelayedTriggerAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// Generic logic
|
||||
SpellAbility trigsa = null;
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
trigsa = sa.getAdditionalAbility("Execute");
|
||||
} else {
|
||||
trigsa = AbilityFactory.getAbility(sa.getHostCard(), sa.getParam("Execute"));
|
||||
SpellAbility trigsa = sa.getAdditionalAbility("Execute");
|
||||
if (trigsa == null) {
|
||||
return false;
|
||||
}
|
||||
trigsa.setActivatingPlayer(ai);
|
||||
return AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(trigsa);
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.ai.ability;
|
||||
import forge.ai.*;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
@@ -193,7 +194,7 @@ public class FightAi extends SpellAbilityAi {
|
||||
for (Card humanCreature : humCreatures) {
|
||||
for (Card aiCreature : aiCreatures) {
|
||||
if (source.isSpell()) { // heroic triggers adding counters and prowess
|
||||
final int bonus = getSpellBonus(aiCreature);
|
||||
final int bonus = getSpellBonus(aiCreature);
|
||||
power += bonus;
|
||||
toughness += bonus;
|
||||
}
|
||||
@@ -247,28 +248,32 @@ public class FightAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the bonus from Heroic +1/+1 counters or Prowess
|
||||
*/
|
||||
private static int getSpellBonus(final Card aiCreature) {
|
||||
for (Trigger t : aiCreature.getTriggers()) {
|
||||
if (t.getMode() == TriggerType.SpellCast) {
|
||||
final Map<String, String> params = t.getMapParams();
|
||||
if ("Card.Self".equals(params.get("TargetsValid")) && "You".equals(params.get("ValidActivatingPlayer"))
|
||||
&& params.containsKey("Execute")) {
|
||||
SpellAbility heroic = AbilityFactory.getAbility(aiCreature.getSVar(params.get("Execute")),aiCreature);
|
||||
if ("Self".equals(heroic.getParam("Defined")) && "P1P1".equals(heroic.getParam("CounterType"))) {
|
||||
return AbilityUtils.calculateAmount(aiCreature, heroic.getParam("CounterNum"), heroic);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ("ProwessPump".equals(params.get("Execute"))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Compute the bonus from Heroic +1/+1 counters or Prowess
|
||||
*/
|
||||
private static int getSpellBonus(final Card aiCreature) {
|
||||
for (Trigger t : aiCreature.getTriggers()) {
|
||||
if (t.getMode() == TriggerType.SpellCast) {
|
||||
SpellAbility sa = t.ensureAbility();
|
||||
final Map<String, String> params = t.getMapParams();
|
||||
if (sa == null) {
|
||||
continue;
|
||||
}
|
||||
if (ApiType.PutCounter.equals(sa.getApi())) {
|
||||
if ("Card.Self".equals(params.get("TargetsValid")) && "You".equals(params.get("ValidActivatingPlayer"))) {
|
||||
SpellAbility heroic = AbilityFactory.getAbility(aiCreature.getSVar(params.get("Execute")),aiCreature);
|
||||
if ("Self".equals(heroic.getParam("Defined")) && "P1P1".equals(heroic.getParam("CounterType"))) {
|
||||
return AbilityUtils.calculateAmount(aiCreature, heroic.getParam("CounterNum"), heroic);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (ApiType.Pump.equals(sa.getApi())) {
|
||||
// TODO add prowess boost
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean shouldFight(Card fighter, Card opponent, int pumpAttack, int pumpDefense) {
|
||||
if (canKill(fighter, opponent, pumpAttack)) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import forge.ai.*;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -16,12 +15,11 @@ public class ImmediateTriggerAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
|
||||
SpellAbility trigsa = null;
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
trigsa = sa.getAdditionalAbility("Execute");
|
||||
} else {
|
||||
trigsa = AbilityFactory.getAbility(sa.getHostCard(), sa.getParam("Execute"));
|
||||
SpellAbility trigsa = sa.getAdditionalAbility("Execute");
|
||||
if (trigsa == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
trigsa.setActivatingPlayer(ai);
|
||||
|
||||
if (trigsa instanceof AbilitySub) {
|
||||
@@ -33,12 +31,11 @@ public class ImmediateTriggerAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||
SpellAbility trigsa = null;
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
trigsa = sa.getAdditionalAbility("Execute");
|
||||
} else {
|
||||
trigsa = AbilityFactory.getAbility(sa.getHostCard(), sa.getParam("Execute"));
|
||||
SpellAbility trigsa = sa.getAdditionalAbility("Execute");
|
||||
if (trigsa == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
|
||||
trigsa.setActivatingPlayer(ai);
|
||||
|
||||
@@ -56,12 +53,11 @@ public class ImmediateTriggerAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
|
||||
SpellAbility trigsa = null;
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
trigsa = sa.getAdditionalAbility("Execute");
|
||||
} else {
|
||||
trigsa = AbilityFactory.getAbility(sa.getHostCard(), sa.getParam("Execute"));
|
||||
SpellAbility trigsa = sa.getAdditionalAbility("Execute");
|
||||
if (trigsa == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
trigsa.setActivatingPlayer(ai);
|
||||
return AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(trigsa);
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ public final class AbilityFactory {
|
||||
}
|
||||
}
|
||||
|
||||
if (api == ApiType.DelayedTrigger && mapParams.containsKey("Execute")) {
|
||||
if ((api == ApiType.DelayedTrigger || api == ApiType.ImmediateTrigger) && mapParams.containsKey("Execute")) {
|
||||
spellAbility.setSVar(mapParams.get("Execute"), sVarHolder.getSVar(mapParams.get("Execute")));
|
||||
}
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ public abstract class SpellAbilityEffect {
|
||||
+ " exile it instead of putting it anywhere else.";
|
||||
String effect = "DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ " + zone;
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true, null);
|
||||
re.setLayer(ReplacementLayer.Other);
|
||||
|
||||
re.setOverridingAbility(AbilityFactory.getAbility(effect, eff));
|
||||
|
||||
@@ -159,8 +159,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
|
||||
// Grant triggers
|
||||
final List<Trigger> addedTriggers = Lists.newArrayList();
|
||||
for (final String s : triggers) {
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), c, false);
|
||||
parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(c, parsedTrigger.getParam("Execute"), sa));
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), c, false, sa);
|
||||
parsedTrigger.setOriginalHost(source);
|
||||
addedTriggers.add(parsedTrigger);
|
||||
}
|
||||
@@ -168,7 +167,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
|
||||
// give replacement effects
|
||||
final List<ReplacementEffect> addedReplacements = Lists.newArrayList();
|
||||
for (final String s : replacements) {
|
||||
addedReplacements.add(ReplacementHandler.parseReplacement(AbilityUtils.getSVar(sa, s), c, false));
|
||||
addedReplacements.add(ReplacementHandler.parseReplacement(AbilityUtils.getSVar(sa, s), c, false, sa));
|
||||
}
|
||||
|
||||
// give static abilities (should only be used by cards to give
|
||||
|
||||
@@ -58,7 +58,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
Card lki = CardUtil.getLKICopy(gameCard);
|
||||
lki.clearControllers();
|
||||
lki.setOwner(sa.getActivatingPlayer());
|
||||
final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic());
|
||||
final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic(), null);
|
||||
delTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true));
|
||||
|
||||
if (triggerRemembered != null) {
|
||||
@@ -81,7 +81,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) {
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
|
||||
// need to reset the parent, additionalAbility does set it to this
|
||||
overridingSA.setParent(null);
|
||||
@@ -96,7 +96,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
|
||||
delTrig.setOverridingAbility(overridingSA);
|
||||
}
|
||||
final TriggerHandler trigHandler = sa.getActivatingPlayer().getGame().getTriggerHandler();
|
||||
final TriggerHandler trigHandler = game.getTriggerHandler();
|
||||
if (mapParams.containsKey("DelayedTriggerDefinedPlayer")) { // on sb's next turn
|
||||
Player p = Iterables.getFirst(AbilityUtils.getDefinedPlayers(sa.getHostCard(), mapParams.get("DelayedTriggerDefinedPlayer"), sa), null);
|
||||
trigHandler.registerPlayerDefinedDelayedTrigger(p, delTrig);
|
||||
|
||||
@@ -189,7 +189,7 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
for (final String s : effectReplacementEffects) {
|
||||
final String actualReplacement = AbilityUtils.getSVar(sa, s);
|
||||
|
||||
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, eff, true);
|
||||
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, eff, true, sa);
|
||||
parsedReplacement.setActiveZone(EnumSet.of(ZoneType.Command));
|
||||
parsedReplacement.setIntrinsic(true);
|
||||
eff.addReplacementEffect(parsedReplacement);
|
||||
|
||||
@@ -57,7 +57,7 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
Card lki = CardUtil.getLKICopy(gameCard);
|
||||
lki.clearControllers();
|
||||
lki.setOwner(sa.getActivatingPlayer());
|
||||
final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic());
|
||||
final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic(), null);
|
||||
immediateTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true));
|
||||
|
||||
// Need to copy paid costs
|
||||
@@ -74,7 +74,7 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) {
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
|
||||
// need to set Parent to null, otherwise it might have wrong root ability
|
||||
overridingSA.setParent(null);
|
||||
@@ -85,9 +85,8 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
|
||||
immediateTrig.setOverridingAbility(overridingSA);
|
||||
}
|
||||
final TriggerHandler trigHandler = sa.getActivatingPlayer().getGame().getTriggerHandler();
|
||||
|
||||
// Instead of registering this, add to the delayed triggers as an immediate trigger type? Which means it'll fire as soon as possible
|
||||
trigHandler.registerDelayedTrigger(immediateTrig);
|
||||
game.getTriggerHandler().registerDelayedTrigger(immediateTrig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5932,21 +5932,20 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
public boolean hasETBTrigger(final boolean drawbackOnly) {
|
||||
for (final Trigger tr : getTriggers()) {
|
||||
final Map<String, String> params = tr.getMapParams();
|
||||
if (tr.getMode() != TriggerType.ChangesZone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!params.get("Destination").equals(ZoneType.Battlefield.toString())) {
|
||||
if (!tr.getParam("Destination").equals(ZoneType.Battlefield.toString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (params.containsKey("ValidCard") && !params.get("ValidCard").contains("Self")) {
|
||||
if (tr.hasParam("ValidCard") && !tr.getParam("ValidCard").contains("Self")) {
|
||||
continue;
|
||||
}
|
||||
if (drawbackOnly && params.containsKey("Execute")){
|
||||
String exec = this.getSVar(params.get("Execute"));
|
||||
if (exec.contains("AB$")) {
|
||||
if (drawbackOnly) {
|
||||
SpellAbility sa = tr.ensureAbility();
|
||||
if (sa == null || sa.isActivatedAbility()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,6 +664,7 @@ public class CardFactory {
|
||||
if (origSVars.containsKey(s)) {
|
||||
final String actualTrigger = origSVars.get(s);
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, out, true);
|
||||
parsedTrigger.setOriginalHost(host);
|
||||
state.addTrigger(parsedTrigger);
|
||||
}
|
||||
}
|
||||
@@ -687,6 +688,7 @@ public class CardFactory {
|
||||
if (origSVars.containsKey(s)) {
|
||||
final String actualAbility = origSVars.get(s);
|
||||
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, out);
|
||||
grantedAbility.setOriginalHost(host);
|
||||
grantedAbility.setIntrinsic(true);
|
||||
state.addSpellAbility(grantedAbility);
|
||||
}
|
||||
@@ -700,6 +702,7 @@ public class CardFactory {
|
||||
if (origSVars.containsKey(s)) {
|
||||
final String actualStatic = origSVars.get(s);
|
||||
final StaticAbility grantedStatic = new StaticAbility(actualStatic, out);
|
||||
grantedStatic.setOriginalHost(host);
|
||||
grantedStatic.setIntrinsic(true);
|
||||
state.addStaticAbility(grantedStatic);
|
||||
}
|
||||
|
||||
@@ -2227,7 +2227,7 @@ public class CardFactoryUtil {
|
||||
final String abStringAfflict = "DB$ LoseLife | Defined$ TriggeredDefendingPlayer" +
|
||||
" | LifeAmount$ " + n;
|
||||
|
||||
final Trigger afflictTrigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
|
||||
final Trigger afflictTrigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic, null);
|
||||
afflictTrigger.setOverridingAbility(AbilityFactory.getAbility(abStringAfflict, card));
|
||||
|
||||
inst.addTrigger(afflictTrigger);
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.replacement;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -370,7 +371,10 @@ public class ReplacementHandler {
|
||||
* @return A finished instance
|
||||
*/
|
||||
public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic) {
|
||||
return ReplacementHandler.parseReplacement(parseParams(repParse), host, intrinsic);
|
||||
return parseReplacement(repParse, host, intrinsic, host);
|
||||
}
|
||||
public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
return ReplacementHandler.parseReplacement(parseParams(repParse), host, intrinsic, sVarHolder);
|
||||
}
|
||||
|
||||
public static Map<String, String> parseParams(final String repParse) {
|
||||
@@ -388,7 +392,7 @@ public class ReplacementHandler {
|
||||
* The card that hosts the replacement effect
|
||||
* @return The finished instance
|
||||
*/
|
||||
private static ReplacementEffect parseReplacement(final Map<String, String> mapParams, final Card host, final boolean intrinsic) {
|
||||
private static ReplacementEffect parseReplacement(final Map<String, String> mapParams, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
final ReplacementType rt = ReplacementType.smartValueOf(mapParams.get("Event"));
|
||||
ReplacementEffect ret = rt.createReplacement(mapParams, host, intrinsic);
|
||||
|
||||
@@ -397,8 +401,8 @@ public class ReplacementHandler {
|
||||
ret.setActiveZone(EnumSet.copyOf(ZoneType.listValueOf(activeZones)));
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("ReplaceWith")) {
|
||||
ret.setOverridingAbility(AbilityFactory.getAbility(host, mapParams.get("ReplaceWith"), ret));
|
||||
if (mapParams.containsKey("ReplaceWith") && sVarHolder != null) {
|
||||
ret.setOverridingAbility(AbilityFactory.getAbility(host, mapParams.get("ReplaceWith"), sVarHolder));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -781,8 +781,7 @@ public final class StaticAbilityContinuous {
|
||||
// add Replacement effects
|
||||
if (addReplacements != null) {
|
||||
for (String rep : addReplacements) {
|
||||
final ReplacementEffect actualRep = ReplacementHandler.parseReplacement(rep, affectedCard, false);
|
||||
actualRep.setIntrinsic(false);
|
||||
final ReplacementEffect actualRep = ReplacementHandler.parseReplacement(rep, affectedCard, false, stAb);
|
||||
addedReplacementEffects.add(actualRep);
|
||||
}
|
||||
}
|
||||
@@ -790,17 +789,12 @@ public final class StaticAbilityContinuous {
|
||||
// add triggers
|
||||
if (addTriggers != null) {
|
||||
for (final String trigger : addTriggers) {
|
||||
final Trigger actualTrigger = TriggerHandler.parseTrigger(trigger, affectedCard, false);
|
||||
final Trigger actualTrigger = TriggerHandler.parseTrigger(trigger, affectedCard, false, stAb);
|
||||
// if the trigger has Execute param, which most trigger gained by Static Abilties should have
|
||||
// turn them into SpellAbility object before adding to card
|
||||
// with that the TargetedCard does not need the Svars added to them anymore
|
||||
// but only do it if the trigger doesn't already have a overriding ability
|
||||
if (actualTrigger.hasParam("Execute") && actualTrigger.getOverridingAbility() == null) {
|
||||
// set overriding ability to the trigger
|
||||
actualTrigger.setOverridingAbility(AbilityFactory.getAbility(affectedCard, actualTrigger.getParam("Execute"), stAb));
|
||||
}
|
||||
actualTrigger.setOriginalHost(hostCard);
|
||||
actualTrigger.setIntrinsic(false);
|
||||
addedTrigger.add(actualTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.trigger;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.TriggerReplacementBase;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
@@ -562,12 +563,16 @@ public abstract class Trigger extends TriggerReplacementBase {
|
||||
}
|
||||
}
|
||||
|
||||
public SpellAbility ensureAbility() {
|
||||
public SpellAbility ensureAbility(final IHasSVars sVarHolder) {
|
||||
SpellAbility sa = getOverridingAbility();
|
||||
if (sa == null && hasParam("Execute")) {
|
||||
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"));
|
||||
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"), sVarHolder);
|
||||
setOverridingAbility(sa);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
public SpellAbility ensureAbility() {
|
||||
return ensureAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.trigger;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
@@ -123,9 +124,13 @@ public class TriggerHandler {
|
||||
}
|
||||
|
||||
public static Trigger parseTrigger(final String trigParse, final Card host, final boolean intrinsic) {
|
||||
return parseTrigger(trigParse, host, intrinsic, host);
|
||||
}
|
||||
|
||||
public static Trigger parseTrigger(final String trigParse, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
try {
|
||||
final Map<String, String> mapParams = TriggerHandler.parseParams(trigParse);
|
||||
return TriggerHandler.parseTrigger(mapParams, host, intrinsic);
|
||||
return TriggerHandler.parseTrigger(mapParams, host, intrinsic, sVarHolder);
|
||||
} catch (Exception e) {
|
||||
String msg = "TriggerHandler:parseTrigger failed to parse";
|
||||
Sentry.getContext().recordBreadcrumb(
|
||||
@@ -137,12 +142,15 @@ public class TriggerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static Trigger parseTrigger(final Map<String, String> mapParams, final Card host, final boolean intrinsic) {
|
||||
public static Trigger parseTrigger(final Map<String, String> mapParams, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
Trigger ret = null;
|
||||
|
||||
try {
|
||||
final TriggerType type = TriggerType.smartValueOf(mapParams.get("Mode"));
|
||||
ret = type.createTrigger(mapParams, host, intrinsic);
|
||||
if (sVarHolder != null) {
|
||||
ret.ensureAbility(sVarHolder);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "TriggerHandler:parseTrigger failed to parse";
|
||||
Sentry.getContext().recordBreadcrumb(
|
||||
|
||||
@@ -26,7 +26,7 @@ public final class CardRelationMatrixGenerator {
|
||||
|
||||
public static HashMap<String,HashMap<String,List<Map.Entry<PaperCard,Integer>>>> cardPools = new HashMap<>();
|
||||
|
||||
public static Map<String, Map<String,List<List<String>>>> ldaPools = new HashMap();
|
||||
public static Map<String, Map<String,List<List<String>>>> ldaPools = new HashMap<>();
|
||||
/**
|
||||
To ensure that only cards with at least 14 connections (as 14*4+4=60) are included in the card based deck
|
||||
generation pools
|
||||
|
||||
Reference in New Issue
Block a user