mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
- updates and fixes to damage prevention.
- Added the keyword Absorb. - More AI improvements to handle damage prevention. - Added Lymph Sliver.
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -2761,6 +2761,7 @@ res/cardsfolder/lure.txt -text svneol=native#text/plain
|
|||||||
res/cardsfolder/lurking_informant.txt -text svneol=native#text/plain
|
res/cardsfolder/lurking_informant.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lurking_nightstalker.txt -text svneol=native#text/plain
|
res/cardsfolder/lurking_nightstalker.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lux_cannon.txt -text svneol=native#text/plain
|
res/cardsfolder/lux_cannon.txt -text svneol=native#text/plain
|
||||||
|
res/cardsfolder/lymph_sliver.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lynx.txt -text svneol=native#text/plain
|
res/cardsfolder/lynx.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/lys_alana_huntmaster.txt -text svneol=native#text/plain
|
res/cardsfolder/lys_alana_huntmaster.txt -text svneol=native#text/plain
|
||||||
res/cardsfolder/ma_chao_western_warrior.txt -text svneol=native#text/plain
|
res/cardsfolder/ma_chao_western_warrior.txt -text svneol=native#text/plain
|
||||||
|
|||||||
9
res/cardsfolder/lymph_sliver.txt
Normal file
9
res/cardsfolder/lymph_sliver.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Lymph Sliver
|
||||||
|
ManaCost:4 W
|
||||||
|
Types:Creature Sliver
|
||||||
|
Text:no text
|
||||||
|
PT:3/3
|
||||||
|
K:stPumpAll:Creature.Sliver:0/0/Absorb 1:no Condition:All Sliver creatures have absorb 1. (If a source would deal damage to a Sliver, prevent 1 of that damage.)
|
||||||
|
SVar:Rarity:Common
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/lymph_sliver.jpg
|
||||||
|
End
|
||||||
@@ -175,9 +175,10 @@ import java.util.Random;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldTgtP(int d, final boolean noPrevention) {
|
private boolean shouldTgtP(int d, final boolean noPrevention) {
|
||||||
|
int restDamage = d;
|
||||||
|
|
||||||
if (AllZone.HumanPlayer.preventAllDamageToPlayer(AF.getHostCard(), false)
|
if (!noPrevention)
|
||||||
|| !AllZone.HumanPlayer.canTarget(AF.getHostCard())) return false;
|
restDamage = AllZone.HumanPlayer.staticDamagePrevention(restDamage,AF.getHostCard(),false);
|
||||||
|
|
||||||
PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, AllZone.ComputerPlayer);
|
PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, AllZone.ComputerPlayer);
|
||||||
CardList hand = new CardList(compHand.getCards());
|
CardList hand = new CardList(compHand.getCards());
|
||||||
@@ -197,10 +198,12 @@ import java.util.Random;
|
|||||||
CardList hPlay = new CardList(human.getCards());
|
CardList hPlay = new CardList(human.getCards());
|
||||||
hPlay = hPlay.filter(new CardListFilter() {
|
hPlay = hPlay.filter(new CardListFilter() {
|
||||||
public boolean addCard(Card c) {
|
public boolean addCard(Card c) {
|
||||||
|
int restDamage = d;
|
||||||
|
if (!noPrevention)
|
||||||
|
restDamage = c.staticDamagePrevention(d,AF.getHostCard(),false);
|
||||||
// will include creatures already dealt damage
|
// will include creatures already dealt damage
|
||||||
return c.isCreature() && (c.getKillDamage() <= d)
|
return c.isCreature() && (c.getKillDamage() <= restDamage)
|
||||||
&& CardFactoryUtil.canTarget(AF.getHostCard(), c)
|
&& CardFactoryUtil.canTarget(AF.getHostCard(), c)
|
||||||
&& !(c.preventAllDamageToCard(AF.getHostCard(),false) && !noPrevention)
|
|
||||||
&& !c.getKeyword().contains("Indestructible")
|
&& !c.getKeyword().contains("Indestructible")
|
||||||
&& !(c.getSVar("SacMe").length() > 0);
|
&& !(c.getSVar("SacMe").length() > 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2216,11 +2216,11 @@ public class Card extends MyObservable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is for keywords with a number like Bushido, Annihilator and Rampage. It returns the total.
|
// This is for keywords with a number like Bushido, Annihilator and Rampage. It returns the total.
|
||||||
public int getKeywordMagnitute(String k) {
|
public int getKeywordMagnitude(String k) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
ArrayList<String> keywords = getKeyword();
|
ArrayList<String> keywords = getKeyword();
|
||||||
for(String kw:keywords) {
|
for(String kw:keywords) {
|
||||||
if(kw.contains(k)) {
|
if(kw.startsWith(k)) {
|
||||||
String[] parse = kw.split(" ");
|
String[] parse = kw.split(" ");
|
||||||
String s = parse[1];
|
String s = parse[1];
|
||||||
count += Integer.parseInt(s);
|
count += Integer.parseInt(s);
|
||||||
@@ -2661,10 +2661,8 @@ public class Card extends MyObservable {
|
|||||||
return getNetDefense() + preventNextDamage - getDamage();
|
return getNetDefense() + preventNextDamage - getDamage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setDamage(int n) {
|
public void setDamage(int n) {
|
||||||
if(this.getKeyword().contains("Prevent all damage that would be dealt to CARDNAME.")) n = 0;
|
//if(this.getKeyword().contains("Prevent all damage that would be dealt to CARDNAME.")) n = 0;
|
||||||
damage = n;
|
damage = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2761,46 +2759,58 @@ public class Card extends MyObservable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean preventAllDamageToCard(Card source, boolean isCombat) {
|
//This should be also usable by the AI to forecast an effect (so it must not change the game state)
|
||||||
boolean reduce = false;
|
public int staticDamagePrevention(final int damage, final Card source, final boolean isCombat) {
|
||||||
|
int restDamage = damage;
|
||||||
|
|
||||||
if(isCombat) {
|
if(isCombat) {
|
||||||
reduce = reduce || getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME.");
|
if(getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."))return 0;
|
||||||
reduce = reduce || getKeyword().contains("Prevent all combat damage that would be dealt to CARDNAME.");
|
if(getKeyword().contains("Prevent all combat damage that would be dealt to CARDNAME."))return 0;
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME.");
|
if(source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."))return 0;
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME.");
|
if(source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME."))return 0;
|
||||||
|
}
|
||||||
|
if(getKeyword().contains("Prevent all damage that would be dealt to CARDNAME."))return 0;
|
||||||
|
if(getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."))return 0;
|
||||||
|
if(source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."))return 0;
|
||||||
|
if(source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME."))return 0;
|
||||||
|
|
||||||
|
if(hasStartOfKeyword("Absorb")) {
|
||||||
|
int absorbed = this.getKeywordMagnitude("Absorb");
|
||||||
|
if (restDamage > absorbed) restDamage = restDamage - absorbed;
|
||||||
|
else return 0;
|
||||||
}
|
}
|
||||||
reduce = reduce || getKeyword().contains("Prevent all damage that would be dealt to CARDNAME.");
|
|
||||||
reduce = reduce || getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME.");
|
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME.");
|
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME.");
|
|
||||||
|
|
||||||
//more specific prevents here:
|
//more specific prevents here:
|
||||||
reduce = reduce || (getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifact creatures.")
|
if((getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifact creatures.")
|
||||||
&& source.isCreature() && source.isArtifact());
|
&& source.isCreature() && source.isArtifact()))return 0;
|
||||||
reduce = reduce || (getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifacts.")
|
if((getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifacts.")
|
||||||
&& source.isArtifact());
|
&& source.isArtifact()))return 0;
|
||||||
reduce = reduce || (getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by creatures.")
|
if((getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by creatures.")
|
||||||
&& source.isCreature());
|
&& source.isCreature()))return 0;
|
||||||
|
|
||||||
// specific Cards
|
// specific Cards
|
||||||
reduce = reduce || (this.isCreature() && source.isCreature() &&
|
if(!isCreature()) { //and not a planeswalker
|
||||||
AllZoneUtil.isCardInPlay("Well-Laid Plans") && source.sharesColorWith(this));
|
if((this.isCreature() && source.isCreature() &&
|
||||||
reduce = reduce || (!isCombat && AllZoneUtil.isCardInPlay("Mark of Asylum", getController()));
|
AllZoneUtil.isCardInPlay("Well-Laid Plans") && source.sharesColorWith(this)))return 0;
|
||||||
reduce = reduce || (source.getController() == getController() && AllZoneUtil.isCardInPlay("Light of Sanction", getController()));
|
|
||||||
return reduce;
|
if((!isCombat && AllZoneUtil.isCardInPlay("Mark of Asylum", getController())))return 0;
|
||||||
|
|
||||||
|
if((source.getController().isPlayer(getController()) && AllZoneUtil.isCardInPlay("Light of Sanction", getController())))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (AllZoneUtil.isCardInPlay("Plated Pegasus") && source.isSpell()
|
||||||
|
&& restDamage > 0) restDamage = restDamage - 1;
|
||||||
|
} //Creature end
|
||||||
|
|
||||||
|
if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0;
|
||||||
|
|
||||||
|
return restDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int preventDamage(final int damage, Card source, boolean isCombat) {
|
public int preventDamage(final int damage, Card source, boolean isCombat) {
|
||||||
int restDamage = damage;
|
int restDamage = damage;
|
||||||
|
|
||||||
if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0;
|
restDamage = staticDamagePrevention(restDamage, source, isCombat);
|
||||||
|
|
||||||
if( preventAllDamageToCard(source, isCombat)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AllZoneUtil.isCardInPlay("Plated Pegasus") && source.isSpell()
|
|
||||||
&& restDamage > 0) restDamage = restDamage - 1;
|
|
||||||
|
|
||||||
if(restDamage >= preventNextDamage) {
|
if(restDamage >= preventNextDamage) {
|
||||||
restDamage = restDamage - preventNextDamage;
|
restDamage = restDamage - preventNextDamage;
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ public class CardFactoryUtil {
|
|||||||
|
|
||||||
//Battle stats increasing keywords
|
//Battle stats increasing keywords
|
||||||
if (c.hasKeyword("Double Strike")) value += power * 15;
|
if (c.hasKeyword("Double Strike")) value += power * 15;
|
||||||
value += c.getKeywordMagnitute("Bushido") * 20;
|
value += c.getKeywordMagnitude("Bushido") * 20;
|
||||||
value += c.getAmountOfKeyword("Flanking") * 20;
|
value += c.getAmountOfKeyword("Flanking") * 20;
|
||||||
|
|
||||||
//Other good keywords
|
//Other good keywords
|
||||||
@@ -465,8 +465,8 @@ public class CardFactoryUtil {
|
|||||||
if (c.hasKeyword("Trample")) value += power * 3;
|
if (c.hasKeyword("Trample")) value += power * 3;
|
||||||
if (c.hasKeyword("Vigilance")) value += power * 5 + toughness * 5;
|
if (c.hasKeyword("Vigilance")) value += power * 5 + toughness * 5;
|
||||||
if (c.hasKeyword("Wither")) value += power * 10;
|
if (c.hasKeyword("Wither")) value += power * 10;
|
||||||
value += c.getKeywordMagnitute("Rampage");
|
value += c.getKeywordMagnitude("Rampage");
|
||||||
value += c.getKeywordMagnitute("Annihilator") * 30;
|
value += c.getKeywordMagnitude("Annihilator") * 30;
|
||||||
if (c.hasKeyword("Changeling")) value += 5;
|
if (c.hasKeyword("Changeling")) value += 5;
|
||||||
if (c.hasKeyword("Whenever CARDNAME becomes blocked by a creature, destroy that creature at end of combat") && power > 0) value += 15;
|
if (c.hasKeyword("Whenever CARDNAME becomes blocked by a creature, destroy that creature at end of combat") && power > 0) value += 15;
|
||||||
if (c.hasKeyword("Whenever a creature dealt damage by CARDNAME this turn is put into a graveyard, put a +1/+1 counter on CARDNAME.") && power > 0) value += 2;
|
if (c.hasKeyword("Whenever a creature dealt damage by CARDNAME this turn is put into a graveyard, put a +1/+1 counter on CARDNAME.") && power > 0) value += 2;
|
||||||
@@ -4495,19 +4495,6 @@ public class CardFactoryUtil {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getTotalBushidoMagnitude(Card c) {
|
|
||||||
int count = 0;
|
|
||||||
ArrayList<String> keywords = c.getKeyword();
|
|
||||||
for(String kw:keywords) {
|
|
||||||
if(kw.contains("Bushido")) {
|
|
||||||
String[] parse = kw.split(" ");
|
|
||||||
String s = parse[1];
|
|
||||||
count += Integer.parseInt(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<Ability> getBushidoEffects(Card c) {
|
public static ArrayList<Ability> getBushidoEffects(Card c) {
|
||||||
ArrayList<String> keywords = c.getKeyword();
|
ArrayList<String> keywords = c.getKeyword();
|
||||||
ArrayList<Ability> list = new ArrayList<Ability>();
|
ArrayList<Ability> list = new ArrayList<Ability>();
|
||||||
|
|||||||
@@ -471,8 +471,8 @@ public class CombatUtil {
|
|||||||
|
|
||||||
if(!CardFactoryUtil.canDamage(defender, attacker)) return false;
|
if(!CardFactoryUtil.canDamage(defender, attacker)) return false;
|
||||||
|
|
||||||
int defBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(defender);
|
int defBushidoMagnitude = defender.getKeywordMagnitude("Bushido");
|
||||||
int attBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(attacker);
|
int attBushidoMagnitude = attacker.getKeywordMagnitude("Bushido");
|
||||||
|
|
||||||
int defenderDamage = defender.getNetAttack() - flankingMagnitude + defBushidoMagnitude;
|
int defenderDamage = defender.getNetAttack() - flankingMagnitude + defBushidoMagnitude;
|
||||||
int attackerDamage = attacker.getNetAttack() + attBushidoMagnitude;
|
int attackerDamage = attacker.getNetAttack() + attBushidoMagnitude;
|
||||||
@@ -576,8 +576,8 @@ public class CombatUtil {
|
|||||||
|
|
||||||
if(!CardFactoryUtil.canDamage(attacker,defender)) return false;
|
if(!CardFactoryUtil.canDamage(attacker,defender)) return false;
|
||||||
|
|
||||||
int defBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(defender);
|
int defBushidoMagnitude = defender.getKeywordMagnitude("Bushido");
|
||||||
int attBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(attacker);
|
int attBushidoMagnitude = attacker.getKeywordMagnitude("Bushido");
|
||||||
|
|
||||||
int defenderDamage = defender.getNetAttack() - flankingMagnitude + defBushidoMagnitude;
|
int defenderDamage = defender.getNetAttack() - flankingMagnitude + defBushidoMagnitude;
|
||||||
int attackerDamage = attacker.getNetAttack() + attBushidoMagnitude;
|
int attackerDamage = attacker.getNetAttack() + attBushidoMagnitude;
|
||||||
|
|||||||
@@ -218,42 +218,22 @@ public abstract class Player extends MyObservable{
|
|||||||
GameActionUtil.executePlayerDamageEffects(this, source, damageToDo, false);
|
GameActionUtil.executePlayerDamageEffects(this, source, damageToDo, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean preventAllDamageToPlayer(final Card source, final boolean isCombat) {
|
//This should be also usable by the AI to forecast an effect (so it must not change the game state)
|
||||||
boolean reduce = false;
|
public int staticDamagePrevention(final int damage, final Card source, final boolean isCombat) {
|
||||||
|
int restDamage = damage;
|
||||||
|
|
||||||
if(isCombat) {
|
if(isCombat) {
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME.");
|
if(source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")) return 0;
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME.");
|
if(source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME.")) return 0;
|
||||||
|
if (AllZoneUtil.isCardInPlay("Purity", this)) return 0;
|
||||||
}
|
}
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME.");
|
if(source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME.")) return 0;
|
||||||
reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME.");
|
if(source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME.")) return 0;
|
||||||
|
|
||||||
//Spirit of Resistance
|
|
||||||
if(AllZoneUtil.isCardInPlay("Spirit of Resistance", this)) {
|
|
||||||
if( AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Black).size() > 0
|
|
||||||
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Blue).size() > 0
|
|
||||||
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Green).size() > 0
|
|
||||||
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Red).size() > 0
|
|
||||||
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.White).size() > 0) {
|
|
||||||
reduce = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return reduce;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int preventDamage(final int damage, Card source, boolean isCombat) {
|
//specific cards
|
||||||
int restDamage = damage;
|
|
||||||
|
|
||||||
if (AllZoneUtil.isCardInPlay("Purity", this) && !isCombat) {
|
|
||||||
gainLife(restDamage,null);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0;
|
if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0;
|
||||||
|
|
||||||
if( preventAllDamageToPlayer(source, isCombat)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AllZoneUtil.isCardInPlay("Spirit of Resistance", this) && !source.getController().equals(this)
|
if (AllZoneUtil.isCardInPlay("Spirit of Resistance", this) && !source.getController().equals(this)
|
||||||
&& restDamage > 0) restDamage = restDamage - 1;
|
&& restDamage > 0) restDamage = restDamage - 1;
|
||||||
|
|
||||||
@@ -284,6 +264,29 @@ public abstract class Player extends MyObservable{
|
|||||||
}
|
}
|
||||||
if (AllZoneUtil.isCardInPlay("Urza's Armor", this) && restDamage > 0) restDamage = restDamage - 1;
|
if (AllZoneUtil.isCardInPlay("Urza's Armor", this) && restDamage > 0) restDamage = restDamage - 1;
|
||||||
|
|
||||||
|
if(AllZoneUtil.isCardInPlay("Spirit of Resistance", this)) {
|
||||||
|
if( AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Black).size() > 0
|
||||||
|
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Blue).size() > 0
|
||||||
|
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Green).size() > 0
|
||||||
|
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Red).size() > 0
|
||||||
|
&& AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.White).size() > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return restDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int preventDamage(final int damage, Card source, boolean isCombat) {
|
||||||
|
int restDamage = damage;
|
||||||
|
|
||||||
|
// Purity has to stay here because it changes the game state
|
||||||
|
if (AllZoneUtil.isCardInPlay("Purity", this) && !isCombat) {
|
||||||
|
gainLife(restDamage,null);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
restDamage = staticDamagePrevention(restDamage, source, isCombat);
|
||||||
|
|
||||||
|
|
||||||
if(restDamage >= preventNextDamage) {
|
if(restDamage >= preventNextDamage) {
|
||||||
restDamage = restDamage - preventNextDamage;
|
restDamage = restDamage - preventNextDamage;
|
||||||
|
|||||||
Reference in New Issue
Block a user