Create TurnIntentions

This commit is contained in:
henriquenakashima 2020-09-30 23:56:59 -04:00
parent 838c30af99
commit 94b3309bb7
9 changed files with 181 additions and 32 deletions

View file

@ -39,6 +39,7 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
private InsightLevel insightLevel;
private HandPlayability<HeroCard> heroHandPlayability;
private HandPlayability<MonsterCard> monsterHandPlayability;
private TurnIntentions<MonsterCard> monsterIntentions;
private delegate void BattleStateChangedAction();
private event BattleStateChangedAction OnBattleStateChanged;
@ -137,9 +138,12 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
this.state, this.monsterEnergy, TeamChoice.Monsters, this.monsterDeck);
this.OnBattleStateChanged += this.monsterHandPlayability.NotifyBattleStateChanged;
this.monsterIntentions = new TurnIntentions<MonsterCard>(
this.monsterDeck, this.monsterEnergy);
this.battlePlayerControls.Init(
this.heroDeck, this.monsterDeck, this.playArea, this.insightLevel,
this.heroHandPlayability, this.monsterHandPlayability,
this.heroHandPlayability, this.monsterHandPlayability, this.monsterIntentions,
this.uiCanvas.transform.localScale.x);
this.insightLevel.OnChanged += this.battlePlayerControls.NotifyInsightLevelChanged;
}
@ -147,9 +151,9 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
private void PositionSprite(TeamChoice team, GameObject sprite, int i) {
Vector3 pos;
if (team == TeamChoice.Heroes) {
pos = new Vector3(-1 + -3 + 3 * i, -1.8f, 0);
pos = new Vector3(-0.8f + -3 + 3 * i, -1.8f, 0);
} else {
pos = new Vector3(+1 + -3 + 3 * i, 1.2f, 0);
pos = new Vector3(+0.8f + -3 + 3 * i, 1.2f, 0);
}
sprite.transform.position = pos;
}
@ -211,6 +215,7 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
private IEnumerator RunHeroTurn() {
// Start of hero turn
OnBattleStateChanged();
this.monsterIntentions.ResumeIntentions();
foreach (BattleHero hero in this.heroes) {
hero.ResetBlock();
@ -242,6 +247,7 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
hero.TickStatuses();
}
OnBattleStateChanged();
this.monsterIntentions.PauseIntentions();
}
private IEnumerator RunMonsterTurn() {
@ -313,11 +319,11 @@ public class BattleController : MonoBehaviour, IBattleEffectApplier, IBattleEffe
}
public bool CanUseHeroCard(HeroCard card) {
return this.heroHandPlayability.IsPlayable(card);
return this.heroHandPlayability.IsPlayableImmediately(card);
}
public bool CanUseMonsterCard(MonsterCard card) {
return this.monsterHandPlayability.IsPlayable(card);
return this.monsterHandPlayability.IsPlayableImmediately(card);
}
public BattleDeck<HeroCard> GetHeroDeck() {

View file

@ -26,7 +26,8 @@ public class BattlePlayerControls : MonoBehaviour
public void Init(
BattleDeck<HeroCard> heroDeck, BattleDeck<MonsterCard> monsterDeck, PlayArea playArea,
InsightLevel insightLevel, HandPlayability<HeroCard> heroHandPlayability,
HandPlayability<MonsterCard> monsterHandPlayability, float scale) {
HandPlayability<MonsterCard> monsterHandPlayability,
TurnIntentions<MonsterCard> monsterIntentions, float scale) {
this.heroDeck = heroDeck;
this.monsterDeck = monsterDeck;
this.playArea = playArea;
@ -35,11 +36,12 @@ public class BattlePlayerControls : MonoBehaviour
this.heroHandControls = new HandControls<HeroCard>(
heroDeck, this.uiCanvas, this.cardPrefab, HandControlsPosition.Bottom,
TeamChoice.Heroes, int.MaxValue, heroHandPlayability, this.scale);
TeamChoice.Heroes, int.MaxValue, heroHandPlayability, null, this.scale);
this.heroHandControls.OnCardClicked += OnHeroCardClicked;
this.monsterHandControls = new HandControls<MonsterCard>(
monsterDeck, this.uiCanvas, this.cardPrefab, HandControlsPosition.Top,
TeamChoice.Monsters, insightLevel.Level, monsterHandPlayability, this.scale);
TeamChoice.Monsters, insightLevel.Level, monsterHandPlayability, monsterIntentions,
this.scale);
this.monsterHandControls.OnCardClicked += OnMonsterCardClicked;
this.cardsInPlayUIs = new Dictionary<BaseCard, GameObject>();

View file

@ -90,8 +90,10 @@ public class CheatBattle: MonoBehaviour
if (this.lastCommands.EndsWith("win")) {
this.OnWinCode();
this.lastCommands = "";
} else if (this.lastCommands.EndsWith("insight")) {
this.OnInsightCode();
this.lastCommands = "";
}
}
}

View file

@ -24,11 +24,13 @@ public class HandControls<BaseCardT> where BaseCardT : BaseCard
private TeamChoice team;
private int insightLevel;
private HandPlayability<BaseCardT> playability;
private TurnIntentions<BaseCardT> intentions;
private float scale;
public HandControls(BattleDeck<BaseCardT> deck, GameObject uiCanvas, GameObject cardPrefab,
HandControlsPosition position, TeamChoice team, int insightLevel,
HandPlayability<BaseCardT> playability, float scale) {
HandPlayability<BaseCardT> playability, TurnIntentions<BaseCardT> intentions,
float scale) {
this.deck = deck;
this.uiCanvas = uiCanvas;
this.cardPrefab = cardPrefab;
@ -36,6 +38,7 @@ public class HandControls<BaseCardT> where BaseCardT : BaseCard
this.team = team;
this.insightLevel = insightLevel;
this.playability = playability;
this.intentions = intentions;
this.scale = scale;
deck.OnHandPileChanged += this.UpdateState;
@ -43,6 +46,9 @@ public class HandControls<BaseCardT> where BaseCardT : BaseCard
if (playability != null) {
playability.OnPlayabilityChanged += this.UpdateState;
}
if (intentions != null) {
intentions.OnIntentionsChanged += this.UpdateState;
}
}
private Vector3 CalculateHandCardPosition(int index, int count) {
@ -96,18 +102,36 @@ public class HandControls<BaseCardT> where BaseCardT : BaseCard
private void UpdateState() {
this.hand = this.deck.GetHandPile().ToList();
RenderHand();
UpdateCardPlayability();
UpdateCardPlayabilityAndIntentions();
}
private void UpdateCardPlayability() {
if (this.hand == null || this.playability == null) {
private void UpdateCardPlayabilityAndIntentions() {
if (this.hand == null) {
return;
}
for (int i = 0; i < this.hand.Count; i++) {
BaseCardT card = this.hand[i];
CardUI cardUI = this.cardsInHandUIs[i].GetComponent<CardUI>();
cardUI.Playable = this.playability.IsPlayable(card);
PlayabilityState cardPlayability = this.playability.GetCardPlayability(card);
if (this.intentions == null) {
if (cardPlayability == PlayabilityState.PlayableImmediately) {
cardUI.State = PlayableState.Playable;
} else {
cardUI.State = PlayableState.Unplayable;
}
} else {
if (cardPlayability == PlayabilityState.PlayableImmediately
|| cardPlayability == PlayabilityState.PlayableInOwnTurn) {
if (this.intentions.WillUseCard(card)) {
cardUI.State = PlayableState.IntendedToPlay;
} else {
cardUI.State = PlayableState.Playable;
}
} else {
cardUI.State = PlayableState.Unplayable;
}
}
}
}
}

View file

@ -3,6 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public enum PlayabilityState {
None,
PlayableImmediately,
PlayableInOwnTurn,
Unplayable,
}
public class HandPlayability<BaseCardT> where BaseCardT : BaseCard {
public delegate void HandPlayabilityChangedAction();
public event HandPlayabilityChangedAction OnPlayabilityChanged;
@ -10,7 +17,8 @@ public class HandPlayability<BaseCardT> where BaseCardT : BaseCard {
private EnergyPool energyPool;
private TeamChoice team;
private BattleDeck<BaseCardT> deck;
private Dictionary<BaseCardT, bool> playable = new Dictionary<BaseCardT, bool>();
private Dictionary<BaseCardT, PlayabilityState> playable =
new Dictionary<BaseCardT, PlayabilityState>();
public HandPlayability(BattleState battleState, EnergyPool energyPool, TeamChoice team,
BattleDeck<BaseCardT> deck) {
@ -25,11 +33,15 @@ public class HandPlayability<BaseCardT> where BaseCardT : BaseCard {
UpdatePlayability();
}
public bool IsPlayable(BaseCardT card) {
bool value;
public bool IsPlayableImmediately(BaseCardT card) {
return GetCardPlayability(card) == PlayabilityState.PlayableImmediately;
}
public PlayabilityState GetCardPlayability(BaseCardT card) {
PlayabilityState value;
if (!this.playable.TryGetValue(card, out value)) {
Debug.Log("Card " + card.GetDisplayName() + " not playable because not in hand!");
return false;
return PlayabilityState.None;
}
return value;
}
@ -47,19 +59,23 @@ public class HandPlayability<BaseCardT> where BaseCardT : BaseCard {
private void UpdatePlayability() {
this.playable.Clear();
foreach (BaseCardT card in this.deck.GetHandPile()) {
bool canPlay;
if (card.Type == CardType.Emotion) {
canPlay = this.battleState.CanPlayEmotion(this.team);
} else {
canPlay = this.energyPool.CanPayForCard(card);
if (!card.Owner.CanUseCard(card)) {
this.playable[card] = PlayabilityState.Unplayable;
continue;
}
canPlay = canPlay
&& this.battleState.IsTeamsTurn(this.team)
&& card.Owner.CanUseCard(card);
this.playable[card] = canPlay;
bool canPlayNow = this.battleState.IsTeamsTurn(this.team);
if (card.Type == CardType.Emotion) {
canPlayNow = canPlayNow && this.battleState.CanPlayEmotion(this.team);
} else {
canPlayNow = canPlayNow && this.energyPool.CanPayForCard(card);
}
if (canPlayNow) {
this.playable[card] = PlayabilityState.PlayableImmediately;
} else {
this.playable[card] = PlayabilityState.PlayableInOwnTurn;
}
}
TriggerOnPlayabilityChanged();
}
}

View file

@ -0,0 +1,69 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TurnIntentions<BaseCardT> where BaseCardT: BaseCard
{
public delegate void IntentionsChangedAction();
public event IntentionsChangedAction OnIntentionsChanged;
private BattleDeck<BaseCardT> mDeck;
private EnergyPool mEnergyPool;
private bool mActive;
private List<BaseCardT> mCardsToUse = new List<BaseCardT>();
public TurnIntentions(BattleDeck<BaseCardT> deck, EnergyPool energyPool) {
mDeck = deck;
mEnergyPool = energyPool;
mActive = true;
mDeck.OnDrawPileChanged += OnDependencyChanged;
mEnergyPool.OnEnergyChanged += OnDependencyChanged;
}
public void ResumeIntentions() {
mActive = true;
UpdateState();
TriggerOnIntentionsChanged();
}
public void PauseIntentions() {
mActive = false;
mCardsToUse.Clear();
TriggerOnIntentionsChanged();
}
private void OnDependencyChanged() {
if (mActive) {
UpdateState();
TriggerOnIntentionsChanged();
}
}
public bool WillUseCard(BaseCardT card) {
return mCardsToUse.Contains(card);
}
private void UpdateState() {
int projectedEnergy = mEnergyPool.Energy;
// TODO: Account for emotions
mCardsToUse.Clear();
List<BaseCardT> hand = mDeck.GetHandPile();
for (int i = 0; i < hand.Count; i++) {
BaseCardT card = hand[i];
if (card.Owner.CanUseCard(card)
&& projectedEnergy >= card.GetCost()) {
projectedEnergy -= card.GetCost();
mCardsToUse.Add(card);
}
}
}
private void TriggerOnIntentionsChanged() {
if (OnIntentionsChanged != null) {
OnIntentionsChanged();
}
}
}

View file

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

View file

@ -3,6 +3,13 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public enum PlayableState {
Unplayable,
Playable,
IntendedToPlay,
}
public class CardUI : MonoBehaviour
{
public Text nameText;
@ -55,11 +62,21 @@ public class CardUI : MonoBehaviour
}
public bool Playable {
public PlayableState State {
set {
if (!this.hidden) {
this.GetComponent<Image>().color = value ? Color.white : Color.grey;
this.artImage.color = value ? Color.white : Color.grey;
if (this.hidden) return;
if (value == PlayableState.Unplayable) {
this.GetComponent<Image>().color = Color.grey;
this.artImage.color = Color.grey;
} else if (value == PlayableState.Playable) {
this.GetComponent<Image>().color = Color.white;
this.artImage.color = Color.white;
} else if (value == PlayableState.IntendedToPlay) {
this.GetComponent<Image>().color = Color.yellow;
this.artImage.color = Color.yellow;
} else {
throw new System.ArgumentException("Unknown PlayableState " + value);
}
}
}

View file

@ -1,7 +1,9 @@
Battle
- Animate rearrange hand after card is used
- Do not Highlight unusable cards
- Show which cards enemies will use
+ Make enemies play energy before anything else
+ Limit intentions to drop one energy
+ Account for one dropped energy in intentions
- Show on who enemies will use the cards
- Highlight which card is targeting
- Allow cancelling targeting