package net.demilich.metastone.tests;
import java.util.ArrayList;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.Test;
import net.demilich.metastone.game.Attribute;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.actions.GameAction;
import net.demilich.metastone.game.actions.PhysicalAttackAction;
import net.demilich.metastone.game.behaviour.Behaviour;
import net.demilich.metastone.game.cards.Card;
import net.demilich.metastone.game.cards.CardCatalogue;
import net.demilich.metastone.game.cards.IChooseOneCard;
import net.demilich.metastone.game.cards.MinionCard;
import net.demilich.metastone.game.cards.SpellCard;
import net.demilich.metastone.game.entities.Actor;
import net.demilich.metastone.game.entities.Entity;
import net.demilich.metastone.game.entities.heroes.HeroClass;
import net.demilich.metastone.game.spells.SetHpSpell;
import net.demilich.metastone.game.spells.SilenceSpell;
import net.demilich.metastone.game.spells.desc.SpellDesc;
import net.demilich.metastone.game.targeting.TargetSelection;
public class AdvancedMechanicTests extends BasicTests {
@Test
public void testChooseOne() {
GameContext context = createContext(HeroClass.DRUID, HeroClass.WARRIOR);
Player player = context.getPlayer1();
Player opponent = context.getPlayer2();
context.endTurn();
TestMinionCard minionCard = new TestMinionCard(1, 4);
playCard(context, opponent, minionCard);
context.endTurn();
player.getHero().getHeroPower().markUsed();
for (Card card : player.getHand().toList()) {
context.getLogic().removeCard(player.getId(), card);
}
Card wrath = CardCatalogue.getCardById("spell_wrath");
IChooseOneCard wrathChooseOne = (IChooseOneCard) wrath;
context.getLogic().receiveCard(player.getId(), wrath);
player.setMana(wrath.getBaseManaCost() + 1);
List<GameAction> validActions = context.getLogic().getValidActions(player.getId());
Assert.assertEquals(player.getHand().getCount(), 1);
// player should have 3 valid actions: two from 'Choose One' card and 1 'End Turn'
Assert.assertEquals(validActions.size(), 3);
GameAction playWrath = wrathChooseOne.playOptions()[0];
playWrath.setTarget(getSingleMinion(opponent.getMinions()));
context.getLogic().performGameAction(player.getId(), playWrath);
validActions = context.getLogic().getValidActions(player.getId());
// This time it should just be the 'End Turn'
Assert.assertEquals(validActions.size(), 1);
Assert.assertEquals(player.getHand().getCount(), 0);
}
@Test
public void testCopyCards() {
GameContext context = createContext(HeroClass.PRIEST, HeroClass.WARRIOR);
Player player = context.getPlayer1();
Player opponent = context.getPlayer2();
player.getHand().removeAll();
int cardsInHand = player.getHand().getCount();
int cardsInOpponentsDeck = opponent.getDeck().getCount();
Card thoughtsteal = CardCatalogue.getCardById("spell_thoughtsteal");
context.getLogic().receiveCard(player.getId(), thoughtsteal);
context.getLogic().performGameAction(player.getId(), thoughtsteal.play());
Assert.assertEquals(opponent.getDeck().getCount(), cardsInOpponentsDeck);
Assert.assertEquals(player.getHand().getCount(), cardsInHand + 2);
}
@Test
public void testDivineShield() {
GameContext context = createContext(HeroClass.MAGE, HeroClass.WARRIOR);
Player mage = context.getPlayer1();
mage.setMana(10);
Player warrior = context.getPlayer2();
warrior.setMana(10);
MinionCard minionCard1 = new TestMinionCard(2, 2, Attribute.DIVINE_SHIELD);
context.getLogic().receiveCard(mage.getId(), minionCard1);
context.getLogic().performGameAction(mage.getId(), minionCard1.play());
MinionCard minionCard2 = new TestMinionCard(5, 5);
context.getLogic().receiveCard(warrior.getId(), minionCard2);
context.getLogic().performGameAction(warrior.getId(), minionCard2.play());
Actor attacker = getSingleMinion(mage.getMinions());
Actor defender = getSingleMinion(warrior.getMinions());
GameAction attackAction = new PhysicalAttackAction(attacker.getReference());
attackAction.setTarget(defender);
context.getLogic().performGameAction(mage.getId(), attackAction);
Assert.assertEquals(attacker.getHp(), attacker.getMaxHp());
Assert.assertEquals(defender.getHp(), defender.getMaxHp() - attacker.getAttack());
Assert.assertEquals(attacker.isDestroyed(), false);
context.getLogic().performGameAction(mage.getId(), attackAction);
Assert.assertEquals(attacker.getHp(), attacker.getMaxHp() - defender.getAttack());
Assert.assertEquals(defender.getHp(), defender.getMaxHp() - attacker.getAttack() * 2);
Assert.assertEquals(attacker.isDestroyed(), true);
}
@Test
public void testEnrage() {
GameContext context = createContext(HeroClass.MAGE, HeroClass.PRIEST);
Player mage = context.getPlayer1();
mage.setMana(10);
Player priest = context.getPlayer2();
priest.setMana(10);
final int BASE_ATTACK = 2;
final int ENRAGE_ATTACK_BONUS = 3;
playCard(context, priest, CardCatalogue.getCardById("minion_amani_berserker"));
playCard(context, mage, new TestMinionCard(1, 10));
Entity attacker = getSingleMinion(mage.getMinions());
Actor defender = getSingleMinion(priest.getMinions());
Assert.assertEquals(defender.getAttack(), BASE_ATTACK);
Assert.assertEquals(defender.hasAttribute(Attribute.ENRAGED), false);
// attack once, should apply the enrage attack bonus
GameAction attackAction = new PhysicalAttackAction(attacker.getReference());
attackAction.setTarget(defender);
context.getLogic().performGameAction(mage.getId(), attackAction);
Assert.assertEquals(defender.getAttack(), BASE_ATTACK + ENRAGE_ATTACK_BONUS);
Assert.assertEquals(defender.hasAttribute(Attribute.ENRAGED), true);
// attack second time, enrage bonus should not increase
context.getLogic().performGameAction(mage.getId(), attackAction);
Assert.assertEquals(defender.getAttack(), BASE_ATTACK + ENRAGE_ATTACK_BONUS);
// heal - enrage attack bonus should be gone
GameAction healAction = priest.getHero().getHeroPower().play();
healAction.setTarget(defender);
context.getLogic().performGameAction(priest.getId(), healAction);
Assert.assertEquals(defender.getAttack(), BASE_ATTACK);
Assert.assertEquals(defender.hasAttribute(Attribute.ENRAGED), false);
// attack once more - should enrage again
context.getLogic().performGameAction(mage.getId(), attackAction);
Assert.assertEquals(defender.getAttack(), BASE_ATTACK + ENRAGE_ATTACK_BONUS);
Assert.assertEquals(defender.hasAttribute(Attribute.ENRAGED), true);
// attack should be set to 1
playCardWithTarget(context, mage, CardCatalogue.getCardById("spell_humility"), defender);
Assert.assertEquals(defender.getAttack(), 1);
Assert.assertEquals(defender.hasAttribute(Attribute.ENRAGED), true);
}
@Test
public void testOverload() {
GameContext context = createContext(HeroClass.SHAMAN, HeroClass.WARRIOR);
Player player = context.getPlayer1();
int playerId = player.getId();
context.getLogic().startTurn(playerId);
Assert.assertEquals(player.getMana(), 1);
context.getLogic().endTurn(playerId);
context.getLogic().startTurn(playerId);
Assert.assertEquals(player.getMana(), 2);
Card overloadCard = new TestMinionCard(1, 1);
overloadCard.setAttribute(Attribute.OVERLOAD, 2);
context.getLogic().receiveCard(playerId, overloadCard);
context.getLogic().performGameAction(playerId, overloadCard.play());
context.getLogic().endTurn(playerId);
context.getLogic().startTurn(playerId);
Assert.assertEquals(player.getMana(), 1);
context.getLogic().endTurn(playerId);
context.getLogic().startTurn(playerId);
Assert.assertEquals(player.getMana(), 4);
}
@Test
public void testSetHpPlusSilence() {
GameContext context = createContext(HeroClass.HUNTER, HeroClass.WARRIOR);
Player player = context.getPlayer1();
Player opponent = context.getPlayer2();
int baseHp = 5;
// summon a minion and check the base hp
playCard(context, opponent, new TestMinionCard(4, baseHp));
Actor minion = getSingleMinion(opponent.getMinions());
Assert.assertEquals(minion.getHp(), baseHp);
int modifiedHp = 1;
// cast a spell on the minion which modifies the hp
SpellDesc setHpSpell = SetHpSpell.create(modifiedHp);
SpellCard spellCard = new TestSpellCard(setHpSpell);
spellCard.setTargetRequirement(TargetSelection.MINIONS);
context.getLogic().receiveCard(player.getId(), spellCard);
GameAction playSpellCard = spellCard.play();
playSpellCard.setTarget(minion);
context.getLogic().performGameAction(player.getId(), playSpellCard);
Assert.assertEquals(minion.getHp(), modifiedHp);
Assert.assertEquals(minion.getMaxHp(), modifiedHp);
// silence the creature - hp should be back to original value
SpellDesc silenceSpell = SilenceSpell.create();
spellCard = new TestSpellCard(silenceSpell);
spellCard.setTargetRequirement(TargetSelection.MINIONS);
context.getLogic().receiveCard(player.getId(), spellCard);
playSpellCard = spellCard.play();
playSpellCard.setTarget(minion);
context.getLogic().performGameAction(player.getId(), playSpellCard);
Assert.assertEquals(minion.getHp(), baseHp);
}
@Test
public void testShorttermBuffs() {
GameContext context = createContext(HeroClass.MAGE, HeroClass.WARRIOR);
Player mage = context.getPlayer1();
mage.setMana(10);
Player warrior = context.getPlayer2();
warrior.setMana(10);
int baseAttack = 1;
mage.setBehaviour(new Behaviour() {
@Override
public String getName() {
return "Select-First";
}
@Override
public List<Card> mulligan(GameContext context, Player player, List<Card> cards) {
return new ArrayList<Card>();
}
@Override
public GameAction requestAction(GameContext context, Player player, List<GameAction> validActions) {
return validActions.get(0);
}
});
playCard(context, mage, new TestMinionCard(baseAttack, 1));
Actor testSubject = getSingleMinion(mage.getMinions());
Assert.assertEquals(testSubject.getAttack(), baseAttack);
playCard(context, mage, CardCatalogue.getCardById("minion_abusive_sergeant"));
Assert.assertEquals(testSubject.getAttack(), baseAttack + 2);
context.getLogic().endTurn(mage.getId());
Assert.assertEquals(testSubject.getAttack(), baseAttack);
}
@Test
public void testSpellpower() {
GameContext context = createContext(HeroClass.MAGE, HeroClass.WARRIOR);
Player mage = context.getPlayer1();
mage.setMana(10);
Player warrior = context.getPlayer2();
warrior.setMana(10);
Assert.assertEquals(warrior.getHero().getHp(), warrior.getHero().getMaxHp());
Card damageSpell = CardCatalogue.getCardById("spell_mind_blast");
int mindBlastDamage = 5;
context.getLogic().receiveCard(mage.getId(), damageSpell);
context.getLogic().performGameAction(mage.getId(), damageSpell.play());
Assert.assertEquals(warrior.getHero().getHp(), warrior.getHero().getMaxHp() - mindBlastDamage);
MinionCard spellPowerMinionCard = (MinionCard) CardCatalogue.getCardById("minion_kobold_geomancer");
context.getLogic().receiveCard(mage.getId(), spellPowerMinionCard);
context.getLogic().performGameAction(mage.getId(), spellPowerMinionCard.play());
context.getLogic().receiveCard(mage.getId(), damageSpell);
context.getLogic().performGameAction(mage.getId(), damageSpell.play());
int spellPower = getSingleMinion(mage.getMinions()).getAttributeValue(Attribute.SPELL_DAMAGE);
Assert.assertEquals(warrior.getHero().getHp(), warrior.getHero().getMaxHp() - 2 * mindBlastDamage - spellPower);
int opponentHp = warrior.getHero().getHp();
GameAction useHeroPower = mage.getHero().getHeroPower().play();
useHeroPower.setTarget(warrior.getHero());
context.getLogic().performGameAction(mage.getId(), useHeroPower);
// mage hero power should not be affected by SPELL_DAMAGE, and thus deal 1 damage
Assert.assertEquals(warrior.getHero().getHp(), opponentHp - 1);
}
@Test
public void testBuffWithBoardWipe() {
GameContext context = createContext(HeroClass.MAGE, HeroClass.PRIEST);
Player mage = context.getPlayer1();
mage.setMana(10);
Player priest = context.getPlayer2();
priest.setMana(10);
Card darkCultist = CardCatalogue.getCardById("minion_dark_cultist");
playCard(context, priest, darkCultist);
Card darkIronDwarf = CardCatalogue.getCardById("minion_dark_iron_dwarf");
playCard(context, priest, darkIronDwarf);
Assert.assertEquals(priest.getMinions().size(), 2);
Card flamestrike = CardCatalogue.getCardById("spell_flamestrike");
playCard(context, mage, flamestrike);
// there should be no minions left after the Flamestrike
// the Dark Cultist Deathrattle shouldn't have any effect, as both minions are removed simultaneously
Assert.assertEquals(priest.getMinions().size(), 0);
}
}