package net.demilich.metastone.game.entities; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import net.demilich.metastone.game.Attribute; import net.demilich.metastone.game.actions.BattlecryAction; import net.demilich.metastone.game.cards.Card; import net.demilich.metastone.game.cards.costmodifier.CardCostModifier; import net.demilich.metastone.game.entities.minions.Race; import net.demilich.metastone.game.logic.GameLogic; import net.demilich.metastone.game.spells.desc.SpellDesc; import net.demilich.metastone.game.spells.trigger.SpellTrigger; public abstract class Actor extends Entity { private Card sourceCard; private List<SpellTrigger> spellTriggers = new ArrayList<SpellTrigger>(); private CardCostModifier cardCostModifier; public Actor(Card sourceCard) { this.setName(sourceCard != null ? sourceCard.getName() : null); this.sourceCard = sourceCard; } public void addDeathrattle(SpellDesc deathrattleSpell) { if (!hasAttribute(Attribute.DEATHRATTLES)) { setAttribute(Attribute.DEATHRATTLES, new ArrayList<SpellDesc>()); } getDeathrattles().add(deathrattleSpell); } public void addSpellTrigger(SpellTrigger spellTrigger) { spellTriggers.add(spellTrigger); } public boolean canAttackThisTurn() { if (hasAttribute(Attribute.CANNOT_ATTACK)) { return false; } if (hasAttribute(Attribute.FROZEN)) { return false; } if (hasAttribute(Attribute.SUMMONING_SICKNESS) && !hasAttribute(Attribute.CHARGE)) { return false; } return getAttack() > 0 && ((getAttributeValue(Attribute.NUMBER_OF_ATTACKS) + getAttributeValue(Attribute.EXTRA_ATTACKS)) > 0 || hasAttribute(Attribute.UNLIMITED_ATTACKS)); } public void clearSpellTriggers() { this.spellTriggers = new ArrayList<SpellTrigger>(); } @Override public Actor clone() { Actor clone = (Actor) super.clone(); clone.attributes = new EnumMap<>(getAttributes()); clone.clearSpellTriggers(); for (SpellTrigger trigger : getSpellTriggers()) { clone.spellTriggers.add(trigger.clone()); } if (hasAttribute(Attribute.DEATHRATTLES)) { clone.removeAttribute(Attribute.DEATHRATTLES); for (SpellDesc deathrattleSpell : getDeathrattles()) { SpellDesc deathrattleClone = deathrattleSpell.clone(); clone.addDeathrattle(deathrattleClone); } } return clone; } protected boolean displayGameTag(Attribute tag) { return tag == Attribute.CHARGE || tag == Attribute.ENRAGED || tag == Attribute.FROZEN || tag == Attribute.DIVINE_SHIELD || tag == Attribute.WINDFURY || tag == Attribute.SPELL_DAMAGE || tag == Attribute.STEALTH || tag == Attribute.TAUNT || tag == Attribute.CANNOT_ATTACK || tag == Attribute.UNTARGETABLE_BY_SPELLS || tag == Attribute.AURA_UNTARGETABLE_BY_SPELLS || tag == Attribute.MEGA_WINDFURY; } public int getAttack() { int attack = getAttributeValue(Attribute.ATTACK) + getAttributeValue(Attribute.ATTACK_BONUS) + getAttributeValue(Attribute.AURA_ATTACK_BONUS) + getAttributeValue(Attribute.TEMPORARY_ATTACK_BONUS) + getAttributeValue(Attribute.CONDITIONAL_ATTACK_BONUS); return Math.max(0, attack); } public int getBaseAttack() { return getAttributeValue(Attribute.BASE_ATTACK); } public int getBaseHp() { return getAttributeValue(Attribute.BASE_HP); } public BattlecryAction getBattlecry() { return (BattlecryAction) getAttribute(Attribute.BATTLECRY); } public CardCostModifier getCardCostModifier() { return cardCostModifier; } @SuppressWarnings("unchecked") public List<SpellDesc> getDeathrattles() { return (List<SpellDesc>) getAttribute(Attribute.DEATHRATTLES); } public int getHp() { return getAttributeValue(Attribute.HP); } public int getMaxHp() { return getAttributeValue(Attribute.MAX_HP) + getAttributeValue(Attribute.HP_BONUS) + getAttributeValue(Attribute.AURA_HP_BONUS); } public Race getRace() { return (Race) getAttribute(Attribute.RACE); } public Card getSourceCard() { return sourceCard; } public List<SpellTrigger> getSpellTriggers() { return new ArrayList<SpellTrigger>(spellTriggers); } public boolean hasSpellTrigger() { return spellTriggers.size() != 0; } public int getMaxNumberOfAttacks() { if (hasAttribute(Attribute.MEGA_WINDFURY)) { return GameLogic.MEGA_WINDFURY_ATTACKS; } else if (hasAttribute(Attribute.WINDFURY)) { return GameLogic.WINDFURY_ATTACKS; } return 1; } @Override public boolean isDestroyed() { return getHp() < 1 || super.isDestroyed(); } public boolean isWounded() { return getHp() != getMaxHp(); } public void modifyAuraHpBonus(int value) { modifyAttribute(Attribute.AURA_HP_BONUS, value); if (value > 0) { modifyAttribute(Attribute.HP, value); } if (getHp() > getMaxHp()) { setHp(getMaxHp()); } } @Override public void modifyHpBonus(int value) { modifyAttribute(Attribute.HP_BONUS, value); if (value > 0) { modifyAttribute(Attribute.HP, value); } if (getHp() > getMaxHp()) { setHp(getMaxHp()); } } public void setAttack(int value) { setAttribute(Attribute.ATTACK, value); } public void setBaseAttack(int value) { setAttribute(Attribute.BASE_ATTACK, value); } public void setBaseHp(int value) { setAttribute(Attribute.BASE_HP, value); } public void setBattlecry(BattlecryAction battlecry) { setAttribute(Attribute.BATTLECRY, battlecry); } public void setCardCostModifier(CardCostModifier cardCostModifier) { this.cardCostModifier = cardCostModifier; } public void setHp(int value) { setAttribute(Attribute.HP, value); } public void setMaxHp(int value) { setAttribute(Attribute.MAX_HP, value); } @Override public void setOwner(int ownerIndex) { super.setOwner(ownerIndex); for (SpellTrigger trigger : spellTriggers) { trigger.setHost(this); } } public void setRace(Race race) { setAttribute(Attribute.RACE, race); } @Override public String toString() { String result = "[" + getEntityType() + " '" + getName() + "'id:" + getId() + " "; result += getAttack() + "/" + getHp(); String prefix = " "; for (Attribute tag : getAttributes().keySet()) { if (displayGameTag(tag)) { result += prefix + tag; prefix = ", "; } } result += " hashCode: " + hashCode(); result += "]"; return result; } }