mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
- Added Drain Power
This commit is contained in:
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -29,6 +29,7 @@ forge-ai/src/main/java/forge/ai/LobbyPlayerAi.java -text
|
|||||||
forge-ai/src/main/java/forge/ai/PlayerControllerAi.java -text
|
forge-ai/src/main/java/forge/ai/PlayerControllerAi.java -text
|
||||||
forge-ai/src/main/java/forge/ai/SpellAbilityAi.java -text
|
forge-ai/src/main/java/forge/ai/SpellAbilityAi.java -text
|
||||||
forge-ai/src/main/java/forge/ai/SpellApiToAi.java -text
|
forge-ai/src/main/java/forge/ai/SpellApiToAi.java -text
|
||||||
|
forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java -text
|
||||||
forge-ai/src/main/java/forge/ai/ability/AddPhaseAi.java -text
|
forge-ai/src/main/java/forge/ai/ability/AddPhaseAi.java -text
|
||||||
forge-ai/src/main/java/forge/ai/ability/AddTurnAi.java svneol=native#text/plain
|
forge-ai/src/main/java/forge/ai/ability/AddTurnAi.java svneol=native#text/plain
|
||||||
forge-ai/src/main/java/forge/ai/ability/AlwaysPlayAi.java -text
|
forge-ai/src/main/java/forge/ai/ability/AlwaysPlayAi.java -text
|
||||||
@@ -292,6 +293,7 @@ forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java -text
|
|||||||
forge-game/src/main/java/forge/game/ability/SpellApiBased.java -text
|
forge-game/src/main/java/forge/game/ability/SpellApiBased.java -text
|
||||||
forge-game/src/main/java/forge/game/ability/StaticAbilityApiBased.java -text
|
forge-game/src/main/java/forge/game/ability/StaticAbilityApiBased.java -text
|
||||||
forge-game/src/main/java/forge/game/ability/effects/AbandonEffect.java -text
|
forge-game/src/main/java/forge/game/ability/effects/AbandonEffect.java -text
|
||||||
|
forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java -text
|
||||||
forge-game/src/main/java/forge/game/ability/effects/AddPhaseEffect.java -text
|
forge-game/src/main/java/forge/game/ability/effects/AddPhaseEffect.java -text
|
||||||
forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java -text
|
forge-game/src/main/java/forge/game/ability/effects/AddTurnEffect.java -text
|
||||||
forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java -text
|
forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java -text
|
||||||
@@ -4424,6 +4426,7 @@ forge-gui/res/cardsfolder/d/dragonspeaker_shaman.txt svneol=native#text/plain
|
|||||||
forge-gui/res/cardsfolder/d/dragonstalker.txt svneol=native#text/plain
|
forge-gui/res/cardsfolder/d/dragonstalker.txt svneol=native#text/plain
|
||||||
forge-gui/res/cardsfolder/d/dragonstorm.txt svneol=native#text/plain
|
forge-gui/res/cardsfolder/d/dragonstorm.txt svneol=native#text/plain
|
||||||
forge-gui/res/cardsfolder/d/drain_life.txt -text
|
forge-gui/res/cardsfolder/d/drain_life.txt -text
|
||||||
|
forge-gui/res/cardsfolder/d/drain_power.txt -text
|
||||||
forge-gui/res/cardsfolder/d/drain_the_well.txt svneol=native#text/plain
|
forge-gui/res/cardsfolder/d/drain_the_well.txt svneol=native#text/plain
|
||||||
forge-gui/res/cardsfolder/d/draining_whelk.txt -text
|
forge-gui/res/cardsfolder/d/draining_whelk.txt -text
|
||||||
forge-gui/res/cardsfolder/d/drainpipe_vermin.txt -text
|
forge-gui/res/cardsfolder/d/drainpipe_vermin.txt -text
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public enum SpellApiToAi {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
apiToClass.put(ApiType.Abandon, AlwaysPlayAi.class);
|
apiToClass.put(ApiType.Abandon, AlwaysPlayAi.class);
|
||||||
|
apiToClass.put(ApiType.ActivateAbility, ActivateAbilityAi.class);
|
||||||
apiToClass.put(ApiType.AddOrRemoveCounter, CountersPutOrRemoveAi.class);
|
apiToClass.put(ApiType.AddOrRemoveCounter, CountersPutOrRemoveAi.class);
|
||||||
apiToClass.put(ApiType.AddPhase, AddPhaseAi.class);
|
apiToClass.put(ApiType.AddPhase, AddPhaseAi.class);
|
||||||
apiToClass.put(ApiType.AddTurn, AddTurnAi.class);
|
apiToClass.put(ApiType.AddTurn, AddTurnAi.class);
|
||||||
|
|||||||
100
forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java
Normal file
100
forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package forge.ai.ability;
|
||||||
|
|
||||||
|
import forge.ai.SpellAbilityAi;
|
||||||
|
import forge.game.ability.AbilityUtils;
|
||||||
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardLists;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.TargetRestrictions;
|
||||||
|
import forge.game.zone.ZoneType;
|
||||||
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ActivateAbilityAi extends SpellAbilityAi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canPlayAI(Player ai, SpellAbility sa) {
|
||||||
|
// AI cannot use this properly until he can use SAs during Humans turn
|
||||||
|
|
||||||
|
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||||
|
final Card source = sa.getHostCard();
|
||||||
|
final Player opp = ai.getOpponent();
|
||||||
|
final Random r = MyRandom.getRandom();
|
||||||
|
boolean randomReturn = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
|
||||||
|
|
||||||
|
List<Card> list = CardLists.getType(opp.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card"));
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tgt == null) {
|
||||||
|
final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa);
|
||||||
|
|
||||||
|
if (!defined.contains(opp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sa.resetTargets();
|
||||||
|
sa.getTargets().add(opp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return randomReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||||
|
final Player opp = ai.getOpponent();
|
||||||
|
|
||||||
|
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||||
|
final Card source = sa.getHostCard();
|
||||||
|
|
||||||
|
if (null == tgt) {
|
||||||
|
if (mandatory) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa);
|
||||||
|
|
||||||
|
if (!defined.contains(opp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
sa.resetTargets();
|
||||||
|
sa.getTargets().add(opp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
||||||
|
// AI cannot use this properly until he can use SAs during Humans turn
|
||||||
|
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||||
|
final Card source = sa.getHostCard();
|
||||||
|
|
||||||
|
boolean randomReturn = true;
|
||||||
|
|
||||||
|
if (tgt == null) {
|
||||||
|
final List<Player> defined = AbilityUtils.getDefinedPlayers(source, sa.getParam("Defined"), sa);
|
||||||
|
|
||||||
|
if (defined.contains(ai)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sa.resetTargets();
|
||||||
|
sa.getTargets().add(ai.getOpponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
return randomReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List<SpellAbility> spells) {
|
||||||
|
return spells.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
|
|||||||
return canPlayAI(aiPlayer, sa);
|
return canPlayAI(aiPlayer, sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List<SpellAbility> spells) {
|
public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List<SpellAbility> spells) {
|
||||||
final String logic = sa.getParam("AILogic");
|
final String logic = sa.getParam("AILogic");
|
||||||
if ("Random".equals(logic)) {
|
if ("Random".equals(logic)) {
|
||||||
|
|||||||
@@ -60,5 +60,34 @@ public class LifeExchangeAi extends SpellAbilityAi {
|
|||||||
return ((r.nextFloat() < .6667) && chance);
|
return ((r.nextFloat() < .6667) && chance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* exchangeLifeDoTriggerAINoCost.
|
||||||
|
* </p>
|
||||||
|
* @param sa
|
||||||
|
* a {@link forge.game.spellability.SpellAbility} object.
|
||||||
|
* @param mandatory
|
||||||
|
* a boolean.
|
||||||
|
* @param af
|
||||||
|
* a {@link forge.game.ability.AbilityFactory} object.
|
||||||
|
*
|
||||||
|
* @return a boolean.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean doTriggerAINoCost(final Player ai, final SpellAbility sa,
|
||||||
|
final boolean mandatory) {
|
||||||
|
|
||||||
|
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||||
|
Player opp = ai.getOpponent();
|
||||||
|
if (tgt != null) {
|
||||||
|
sa.resetTargets();
|
||||||
|
if (sa.canTarget(opp) && (mandatory || ai.getLife() < opp.getLife())) {
|
||||||
|
sa.getTargets().add(opp);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.TreeMap;
|
|||||||
*/
|
*/
|
||||||
public enum ApiType {
|
public enum ApiType {
|
||||||
Abandon (AbandonEffect.class),
|
Abandon (AbandonEffect.class),
|
||||||
|
ActivateAbility (ActivateAbilityEffect.class),
|
||||||
AddOrRemoveCounter (CountersPutOrRemoveEffect.class),
|
AddOrRemoveCounter (CountersPutOrRemoveEffect.class),
|
||||||
AddPhase (AddPhaseEffect.class),
|
AddPhase (AddPhaseEffect.class),
|
||||||
AddTurn (AddTurnEffect.class),
|
AddTurn (AddTurnEffect.class),
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardLists;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.TargetRestrictions;
|
||||||
|
import forge.game.zone.ZoneType;
|
||||||
|
import forge.util.Lang;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ActivateAbilityEffect extends SpellAbilityEffect {
|
||||||
|
@Override
|
||||||
|
protected String getStackDescription(SpellAbility sa) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||||
|
|
||||||
|
sb.append(StringUtils.join(tgtPlayers, ", "));
|
||||||
|
sb.append(" activates ");
|
||||||
|
sb.append(Lang.nounWithAmount(1, sa.hasParam("ManaAbility") ? "mana ability" : "ability"));
|
||||||
|
sb.append(" of each ").append(sa.getParamOrDefault("Type", "Card"));
|
||||||
|
sb.append(" he or she controls.");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve(SpellAbility sa) {
|
||||||
|
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||||
|
final boolean isManaAb = sa.hasParam("ManaAbility");
|
||||||
|
// TODO: improve ai and fix corner cases
|
||||||
|
|
||||||
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
|
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||||
|
List<Card> list = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card"));
|
||||||
|
for (Card c : list) {
|
||||||
|
List<SpellAbility> possibleAb = Lists.newArrayList(c.getAllPossibleAbilities(p, true));
|
||||||
|
if (isManaAb) {
|
||||||
|
possibleAb.retainAll(c.getManaAbility());
|
||||||
|
}
|
||||||
|
if (possibleAb.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(possibleAb, sa, "Choose a mana ability:");
|
||||||
|
p.getController().playChosenSpellAbility(manaAb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
|
import forge.game.mana.Mana;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
import forge.game.spellability.TargetRestrictions;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -27,7 +29,12 @@ public class DrainManaEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||||
p.getManaPool().clearPool(false);
|
List<Mana> drained = p.getManaPool().clearPool(false);
|
||||||
|
if (sa.hasParam("DrainMana")) {
|
||||||
|
for (Mana mana : drained) {
|
||||||
|
sa.getActivatingPlayer().getManaPool().addMana(mana);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,15 +125,15 @@ public class ManaPool implements Iterable<Mana> {
|
|||||||
* @return - the amount of mana removed this way
|
* @return - the amount of mana removed this way
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public final int clearPool(boolean isEndOfPhase) {
|
public final List<Mana> clearPool(boolean isEndOfPhase) {
|
||||||
// isEndOfPhase parameter: true = end of phase, false = mana drain effect
|
// isEndOfPhase parameter: true = end of phase, false = mana drain effect
|
||||||
if (floatingMana.isEmpty()) { return 0; }
|
List<Mana> cleared = new ArrayList<Mana>();
|
||||||
|
if (floatingMana.isEmpty()) { return cleared; }
|
||||||
|
|
||||||
if (isEndOfPhase && owner.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.manapoolsDontEmpty)) {
|
if (isEndOfPhase && owner.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.manapoolsDontEmpty)) {
|
||||||
return 0;
|
return cleared;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numRemoved = 0;
|
|
||||||
boolean keepGreenMana = isEndOfPhase && owner.hasKeyword("Green mana doesn't empty from your mana pool as steps and phases end.");
|
boolean keepGreenMana = isEndOfPhase && owner.hasKeyword("Green mana doesn't empty from your mana pool as steps and phases end.");
|
||||||
boolean convertToColorless = owner.hasKeyword("Convert unused mana to Colorless");
|
boolean convertToColorless = owner.hasKeyword("Convert unused mana to Colorless");
|
||||||
|
|
||||||
@@ -153,11 +153,12 @@ public class ManaPool implements Iterable<Mana> {
|
|||||||
pMana.add(mana);
|
pMana.add(mana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
floatingMana.get(b).removeAll(pMana);
|
||||||
if (convertToColorless) {
|
if (convertToColorless) {
|
||||||
floatingMana.get(b).removeAll(pMana);
|
|
||||||
convertManaColor(b, MagicColor.COLORLESS);
|
convertManaColor(b, MagicColor.COLORLESS);
|
||||||
|
floatingMana.get(b).addAll(pMana);
|
||||||
} else {
|
} else {
|
||||||
numRemoved += floatingMana.get(b).size() - pMana.size();
|
cleared.addAll(floatingMana.get(b));
|
||||||
floatingMana.get(b).clear();
|
floatingMana.get(b).clear();
|
||||||
floatingMana.putAll(b, pMana);
|
floatingMana.putAll(b, pMana);
|
||||||
}
|
}
|
||||||
@@ -166,14 +167,14 @@ public class ManaPool implements Iterable<Mana> {
|
|||||||
if (convertToColorless) {
|
if (convertToColorless) {
|
||||||
convertManaColor(b, MagicColor.COLORLESS);
|
convertManaColor(b, MagicColor.COLORLESS);
|
||||||
} else {
|
} else {
|
||||||
numRemoved += floatingMana.get(b).size();
|
cleared.addAll(floatingMana.get(b));
|
||||||
floatingMana.get(b).clear();
|
floatingMana.get(b).clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
owner.getGame().fireEvent(new GameEventManaPool(owner, EventValueChangeType.Cleared, null));
|
owner.getGame().fireEvent(new GameEventManaPool(owner, EventValueChangeType.Cleared, null));
|
||||||
return numRemoved;
|
return cleared;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void convertManaColor(final byte originalColor, final byte toColor) {
|
private void convertManaColor(final byte originalColor, final byte toColor) {
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ public class PhaseHandler implements java.io.Serializable, IGameStateObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Player p : game.getPlayers()) {
|
for (Player p : game.getPlayers()) {
|
||||||
int burn = p.getManaPool().clearPool(true);
|
int burn = p.getManaPool().clearPool(true).size();
|
||||||
|
|
||||||
boolean manaBurns = game.getRules().hasManaBurn();
|
boolean manaBurns = game.getRules().hasManaBurn();
|
||||||
if (manaBurns) {
|
if (manaBurns) {
|
||||||
|
|||||||
7
forge-gui/res/cardsfolder/d/drain_power.txt
Normal file
7
forge-gui/res/cardsfolder/d/drain_power.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name:Drain Power
|
||||||
|
ManaCost:U U
|
||||||
|
Types:Sorcery
|
||||||
|
A:SP$ ActivateAbility | Cost$ U U | ValidTgts$ Player | Type$ Land | ManaAbility$ True | SubAbility$ DBDrainMana | SpellDescription$ Target player activates a mana ability of each land he or she controls. Then put all mana from that player's mana pool into yours.
|
||||||
|
SVar:DBDrainMana:DB$ DrainMana | Defined$ Targeted | DrainMana$ True
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/drain_power.jpg
|
||||||
|
Oracle:Target player activates a mana ability of each land he or she controls. Then put all mana from that player's mana pool into yours.
|
||||||
Reference in New Issue
Block a user