Implement emotions

This commit is contained in:
henriquenakashima 2020-09-26 18:24:46 -04:00
parent 08c395cf51
commit 11df4f1164
25 changed files with 369 additions and 40 deletions

View file

@ -25,6 +25,8 @@ public abstract class BaseCard
public int GetCost() {return this.cost;}
public string GetDisplayType() {
switch (this.type) {
case CardType.Emotion:
return "Emotion";
case CardType.Attack:
return "Attack";
case CardType.Skill:
@ -41,7 +43,15 @@ public abstract class BaseCard
return this.type == CardType.Enchantment;
}
public bool IsEphemeral() {
return this.type == CardType.Emotion;
}
public string StringId {
get => this.stringId;
}
public CardType Type {
get => this.type;
}
}

View file

@ -46,15 +46,16 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
HeroId.NPCGuard,
};
HCardId[] cardIds = new HCardId[10] {
HCardId.IronskinDraught,
HCardId[] cardIds = new HCardId[11] {
HCardId.Eagerness,
HCardId.Eagerness,
HCardId.LeadShot,
HCardId.LeadShot,
HCardId.SmokeBomb,
HCardId.SwordSlash,
HCardId.SwordSlash,
HCardId.Eagerness,
HCardId.SwordSlash,
HCardId.ShieldBlock,
HCardId.Eagerness,
HCardId.SwordSlash,
HCardId.ShieldBlock,
};
@ -265,10 +266,6 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
// Start of hero turn
OnBattleStateChanged();
// TODO: Play emotions from hand
if (this.heroEnergy.MaxEnergy < 9) {
this.heroEnergy.DropOneEmotion();
}
foreach (BattleHero hero in this.heroes) {
hero.ResetBlock();
}
@ -293,6 +290,7 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
yield return new WaitForSeconds(0.5f);
// Start of monster turn
// TODO: Play emotions from hand
if (this.monsterEnergy.MaxEnergy < 9) {
this.monsterEnergy.DropOneEmotion();
}
@ -332,11 +330,12 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
yield return card.Use(this, this, battlePlayerControls);
if (card.IsPermanent()) {
this.playArea.AddPlayedHeroPermanent(card);
} else if (card.IsEphemeral()) {
this.heroDeck.MoveCardToOblivion(card);
} else {
this.heroDeck.MoveCardToDiscard(card);
}
yield return new WaitForSeconds(0.5f);
OnBattleStateChanged();
CheckState();
}
@ -347,6 +346,8 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
yield return card.Use(this, this);
if (card.IsPermanent()) {
this.playArea.AddPlayedMonsterPermanent(card);
} else if (card.IsEphemeral()) {
this.monsterDeck.MoveCardToOblivion(card);
} else {
this.monsterDeck.MoveCardToDiscard(card);
}
@ -421,8 +422,22 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
}
// IBattleEffectResolver
public void DropEmotion(DropEmotionEffect effect) {
if (!this.state.CanPlayEmotion(effect.Team)) {
throw new System.InvalidOperationException("Cannot play emotion");
}
this.state.NotifyPlayedEmotion(effect.Team);
EnergyPool pool = (effect.Team == TeamChoice.Heroes ? this.heroEnergy : this.monsterEnergy);
pool.MaxEnergy += effect.Amount;
pool.Energy += effect.Amount;
}
public void IncreaseHeroMaxEnergy(IncreaseMaxEnergyEffect effect) {
this.heroEnergy.MaxEnergy += effect.Amount;
if (effect.Immediate) {
this.heroEnergy.Energy += effect.Amount;
}
}
public void IncreaseMaxHP(IncreaseMaxHPEffect effect) {

View file

@ -16,11 +16,13 @@ public class BattleDeck<BaseCardT> where BaseCardT : BaseCard
private List<BaseCardT> drawPile;
private List<BaseCardT> handPile;
private List<BaseCardT> discardPile;
private List<BaseCardT> oblivionPile;
public BattleDeck(CardDatabase<BaseCardT> cardDatabase, int[] cardIds, BattleParticipant[] cardOwners) {
this.drawPile = new List<BaseCardT>();
this.handPile = new List<BaseCardT>();
this.discardPile = new List<BaseCardT>();
this.oblivionPile = new List<BaseCardT>();
for (int i = 0; i < cardIds.Length; i++) {
BaseCardT newCard = cardDatabase.CreateCard(cardIds[i], cardOwners[i]);
@ -110,6 +112,10 @@ public class BattleDeck<BaseCardT> where BaseCardT : BaseCard
TriggerDrawPileChanged();
TriggerDiscardPileChanged();
}
public void MoveCardToOblivion(BaseCardT card) {
this.oblivionPile.Insert(0, card);
}
private void TriggerDrawPileChanged() {
if (OnDrawPileChanged != null) OnDrawPileChanged();

View file

@ -8,6 +8,7 @@ public class BattleState
// public delegate void BattleStateChangedAction();
// public event BattleStateChangedAction OnBattleStateChanged;
private bool heroTurn;
private bool playedEmotion;
public bool IsTeamsTurn(TeamChoice team) {
if (team == TeamChoice.Heroes) {
@ -17,5 +18,24 @@ public class BattleState
}
}
public bool HeroTurn {get => this.heroTurn; set => this.heroTurn = value;}
public bool CanPlayEmotion(TeamChoice team) {
return !this.playedEmotion && IsTeamsTurn(team);
}
public void NotifyPlayedEmotion(TeamChoice team) {
if (!this.CanPlayEmotion(team)) {
throw new System.InvalidOperationException("BattleState received NotifyPlayedEmotion but "
+ "cannot play emotion");
}
this.playedEmotion = true;
}
public bool HeroTurn {
get => this.heroTurn;
set {
this.heroTurn = value;
this.playedEmotion = false;
}
}
}

View file

@ -1,4 +1,5 @@
public enum CardType {
Emotion,
Attack,
Skill,
Enchantment,

View file

@ -0,0 +1,17 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EagernessHCard : HeroCard
{
public EagernessHCard(BattleParticipant owner)
: base(owner, HCardId.Eagerness, "Eagerness", 0, CardType.Emotion,
"1 Energy") {
}
public override IEnumerator Use(IBattleEffectApplier effectApplier,
MonsterViewpoint viewpoint, BattlePlayerControls playerControls) {
effectApplier.Apply(new DropEmotionEffect(1, this.owner.Team));
yield break;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3460f4183463754694d2195cd86821b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -13,7 +13,7 @@ public class LeadShotHCard : HeroCard
MonsterViewpoint viewpoint, BattlePlayerControls playerControls) {
SingleTargeting singleTargeting = new SingleTargeting(new OtherTargetPolicy(this.owner));
yield return playerControls.StartCoroutine(playerControls.ChooseTarget(singleTargeting));
yield return new WaitForSeconds(0.8f);
yield return new WaitForSeconds(0.4f);
BattleParticipant target = singleTargeting.GetTarget();
effectApplier.Apply(new DealDamageEffect(target, 2));
yield return new WaitForSeconds(0.8f);

View file

@ -14,7 +14,7 @@ public class ShieldBlockHCard : HeroCard
MonsterViewpoint viewpoint, BattlePlayerControls playerControls) {
SingleTargeting singleTargeting = new SingleTargeting(new AnyHeroTargetPolicy());
yield return playerControls.StartCoroutine(playerControls.ChooseTarget(singleTargeting));
yield return new WaitForSeconds(0.8f);
yield return new WaitForSeconds(0.4f);
BattleParticipant target = singleTargeting.GetTarget();
effectApplier.Apply(new BlockEffect(target, 2));
yield return new WaitForSeconds(0.8f);

View file

@ -13,7 +13,7 @@ public class SwordSlashHCard : HeroCard
MonsterViewpoint viewpoint, BattlePlayerControls playerControls) {
SingleTargeting singleTargeting = new SingleTargeting(new AnyTargetPolicy());
yield return playerControls.StartCoroutine(playerControls.ChooseTarget(singleTargeting));
yield return new WaitForSeconds(0.8f);
yield return new WaitForSeconds(0.4f);
BattleParticipant target = singleTargeting.GetTarget();
effectApplier.Apply(new DealDamageEffect(target, 1));
yield return new WaitForSeconds(0.8f);

View file

@ -11,7 +11,7 @@ public class ThunderstormHCard : HeroCard
public override IEnumerator Use(IBattleEffectApplier effectApplier,
MonsterViewpoint viewpoint, BattlePlayerControls playerControls) {
effectApplier.Apply(new IncreaseMaxEnergyEffect(1));
effectApplier.Apply(new IncreaseMaxEnergyEffect(1, false));
effectApplier.Apply(new AcquireCardsEffect(
new HCardId[] {HCardId.LightningStrike, HCardId.LightningStrike},
BattleZone.DrawPile, this.owner));

View file

@ -0,0 +1,21 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DropEmotionEffect : IBattleEffect
{
private int amount;
private TeamChoice team;
public DropEmotionEffect(int amount, TeamChoice team) {
this.amount = amount;
this.team = team;
}
public void Apply(IBattleEffectResolver resolver) {
resolver.DropEmotion(this);
}
public int Amount {get => this.amount;}
public TeamChoice Team {get => this.team;}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8030217c9c617f49898976464cb13a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -5,9 +5,11 @@ using UnityEngine;
public class IncreaseMaxEnergyEffect : IBattleEffect
{
private int amount;
private bool immediate;
public IncreaseMaxEnergyEffect(int amount) {
public IncreaseMaxEnergyEffect(int amount, bool immediate) {
this.amount = amount;
this.immediate = immediate;
}
public void Apply(IBattleEffectResolver resolver) {
@ -15,4 +17,5 @@ public class IncreaseMaxEnergyEffect : IBattleEffect
}
public int Amount {get => this.amount;}
public bool Immediate {get => this.immediate;}
}

View file

@ -36,6 +36,16 @@ public class EnergyPool
}
}
public int MaxEnergy {get => this.maxEnergy; set => this.maxEnergy = value;}
public int Energy {get => this.energy;}
public int MaxEnergy {get => this.maxEnergy;
set {
this.maxEnergy = value;
TriggerOnEnergyChanged();
}
}
public int Energy {get => this.energy;
set {
this.energy = value;
TriggerOnEnergyChanged();
}
}
}

View file

@ -47,10 +47,17 @@ public class HandPlayability<BaseCardT> where BaseCardT : BaseCard {
private void UpdatePlayability() {
this.playable.Clear();
foreach (BaseCardT card in this.deck.GetHandPile()) {
this.playable[card] =
this.battleState.IsTeamsTurn(this.team)
&& card.Owner.CanUseCard(card)
&& this.energyPool.CanPayForCard(card);
bool canPlay;
if (card.Type == CardType.Emotion) {
canPlay = this.battleState.CanPlayEmotion(this.team);
} else {
canPlay = this.energyPool.CanPayForCard(card);
}
canPlay = canPlay
&& this.battleState.IsTeamsTurn(this.team)
&& card.Owner.CanUseCard(card);
this.playable[card] = canPlay;
}
TriggerOnPlayabilityChanged();

View file

@ -23,10 +23,12 @@ public enum HCardId {
ShieldBlock,
LeadShot,
SmokeBomb,
Eagerness,
}
public class HeroCardDatabase : CardDatabase<HeroCard>
{
// TODO: Get rid of this and instead input who owns each card.
private static Dictionary<HCardId, HeroId> CARD_TO_HERO = new Dictionary<HCardId, HeroId>() {
{HCardId.CrashingPunch, HeroId.Brute},
{HCardId.Cover, HeroId.Brute},
@ -41,6 +43,7 @@ public class HeroCardDatabase : CardDatabase<HeroCard>
{HCardId.ShieldBlock, HeroId.NPCGuard},
{HCardId.LeadShot, HeroId.Alchemist},
{HCardId.SmokeBomb, HeroId.Alchemist},
{HCardId.Eagerness, HeroId.Alchemist},
};
public override HeroCard CreateCard(int id, BattleParticipant owner) {
@ -73,6 +76,8 @@ public class HeroCardDatabase : CardDatabase<HeroCard>
return new LeadShotHCard(owner);
case HCardId.SmokeBomb:
return new SmokeBombHCard(owner);
case HCardId.Eagerness:
return new EagernessHCard(owner);
default:
throw new System.ArgumentException("HCardId unknown", "id");
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using UnityEngine;
public interface IBattleEffectResolver {
void DropEmotion(DropEmotionEffect effect);
int DealDamage(DealDamageEffect effect);
int DealMassDamage(MassDamageEffect effect);
int Heal(HealEffect effect);

View file

@ -14,7 +14,11 @@ public class CardUI : MonoBehaviour
public void Init(BaseCard card) {
this.nameText.text = card.GetDisplayName();
this.typeText.text = card.GetDisplayType();
this.costText.text = "" + card.GetCost();
if (card.Type != CardType.Emotion) {
this.costText.text = "" + card.GetCost();
} else {
this.costText.text = "";
}
this.effectText.text = card.GetEffectText();
Sprite sprite = Resources.Load<Sprite>(GetCardArtResourcePath(card));
this.artImage.sprite = sprite;

View file

@ -58,7 +58,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_Color: {r: 0, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_Maskable: 1
m_OnCullStateChanged:
@ -253,8 +253,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -48.86}
m_SizeDelta: {x: -8, y: -105.724106}
m_AnchoredPosition: {x: -0.22777939, y: -48.438}
m_SizeDelta: {x: -8, y: -103.21904}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2477879197027808367
CanvasRenderer:
@ -277,7 +277,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_Color: {r: 0, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_Maskable: 1
m_OnCullStateChanged:
@ -285,12 +285,12 @@ MonoBehaviour:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 10
m_FontSize: 11
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 1
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
@ -331,8 +331,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -0.11389, y: 11.333}
m_SizeDelta: {x: 114.22778, y: 64.87021}
m_AnchoredPosition: {x: -0.11389, y: 12.589}
m_SizeDelta: {x: 114.22778, y: 70.49167}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2144677943642500384
CanvasRenderer:
@ -405,8 +405,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 40.35, y: 50}
m_SizeDelta: {x: -88.7, y: -136}
m_AnchoredPosition: {x: 38.1, y: 65}
m_SizeDelta: {x: -88.7, y: -140.14691}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7591601241322559362
CanvasRenderer:
@ -429,7 +429,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_Color: {r: 0, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_Maskable: 1
m_OnCullStateChanged:
@ -448,7 +448,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 1WW
m_Text: 3
--- !u!1 &6525514904971610804
GameObject:
m_ObjectHideFlags: 0
@ -483,8 +483,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -19.96, y: 50}
m_SizeDelta: {x: -47.914093, y: -136}
m_AnchoredPosition: {x: -19.957, y: 52.84}
m_SizeDelta: {x: -47.914093, y: -144.77003}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4222329136353876023
CanvasRenderer:
@ -507,7 +507,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_Color: {r: 0, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_Maskable: 1
m_OnCullStateChanged:
@ -515,12 +515,12 @@ MonoBehaviour:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 10
m_FontSize: 9
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 3
m_Alignment: 0
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 4955c4f57b7ec0e42a0a4d603cf8745c
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 73414501ec4c7b2468a3a423d086361e
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -3,4 +3,7 @@
- Do not Highlight unusable cards
- Show which cards enemies will use
- Show on who enemies will use the cards
- Extend BattleState to be more than hero turn true/false
- Extend BattleState to be more than hero turn true/false
- Remove UI from dead participants
- Dead participants do not get block
- GolemCharge art