So in short, what I’m trying to accomplish is I have 6 monsters, 3 player mons, 3 enemy mons.
I want to put them in a list based on their individual Speed stats, and have them each take their turns 1 by 1. Picture it like Pokemon, all 6 monsters already know what they’re going to do beforehand, I just need them each to take only 1 turn.
The problem I keep running into is either it will use the incorrect mon’s speed value, or it will try to reference an index that doesn’t exist.
The way I have it setup is there’s a list of 7 monster stat blocks. 0 is an empty, uninitialized one that is just meant as a placeholder, that way indexes 1-3 are the players’ and indexes 4-6 are the enemies. I’ve tried setting up the turn order a bunch of different ways and just haven’t been able to get it right, so I’m coming here as a last-ditch effort before just going through and changing all the indexes and how I have the whole thing setup.
Here’s the parts of the script that are giving me problems.
public void CheckIfPlayerDone()
{
if (Mon1 != SlotAction.NULL)
{
Monsters[1].selectedAction = Mon1;
if (Mon2 != SlotAction.NULL)
{
Monsters[2].selectedAction = Mon2;
if (Mon3 != SlotAction.NULL)
{
Monsters[3].selectedAction = Mon3;
Monsters[4].selectedAction = Mon4;
Monsters[5].selectedAction = Mon5;
Monsters[6].selectedAction = Mon6;
state = BattleState.ACTION;
TurnOrder = new List<int>();
TurnOrder.Clear();
TurnOrder.Add(MM1.Speed);
TurnOrder.Add(MM2.Speed);
TurnOrder.Add(MM3.Speed);
TurnOrder.Add(MM4.Speed);
TurnOrder.Add(MM5.Speed);
TurnOrder.Add(MM6.Speed);
TurnOrder.Sort();
//TurnsTaken = 0;
ActionState();
}
}
}
}
public void ActionState()
{
foreach (int i in TurnOrder)
{
TakeAction(TurnOrder.IndexOf(i));
StartCoroutine(ActionSequence());
}
CheckForWin();
}
private IEnumerator ActionSequence()
{
// Create a copy of the TurnOrder list and sort it in descending order
List<int> sortedTurnOrder = new List<int>(TurnOrder);
sortedTurnOrder.Sort((a, b) => Monsters[b].Speed.CompareTo(Monsters[a].Speed));
foreach (int spotID in sortedTurnOrder)
{
// Take action for the current spotID
TakeAction(spotID);
// Wait for 3 seconds before executing the next action
yield return new WaitForSeconds(3);
}
CheckForWin();
}
public void TakeAction(int spotID)
{
// Adjust spotID to ensure it's within the range of valid indices
Debug.Log(spotID + " = Unmodified SpotID");
spotID = Mathf.Clamp(spotID, 1, 6);
Debug.Log(spotID + " = Modified SpotID");
// Retrieve the monster based on spotID and check if it's not null
MiniMonster monster = Monsters[spotID];
if (monster != null)
{
Debug.Log(monster.MonName + " - " + spotID + " takes action");
// Check which action to take based on the monster's SlotAction
switch (monster.selectedAction)
{
case SlotAction.AB1:
ABHandler.AB1(spotID + 1, AllyTarget, EnemyTarget);
break;
case SlotAction.AB2:
ABHandler.AB2(spotID + 1, AllyTarget, EnemyTarget);
break;
case SlotAction.ITEM:
ABHandler.ItemAB(spotID + 1, AllyTarget, EnemyTarget);
break;
default:
Debug.LogWarning("Invalid SlotAction for monster: " + monster.MonName);
break;
}
}
}
And here’s the entire script in case that isn’t enough.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public enum BattleState { START, PLAYERTURN, ACTION, WON, LOST }
public enum SlotAction { NULL, AB1, AB2, ITEM }
public class MiniMonManager : MonoBehaviour
{
public Player player;
public StatBlockMon[] MonIDList;
public ItemStatBlock[] itemIDList;
public GameObject MonGO0;
public GameObject MonGO1;
public GameObject MonGO2;
public GameObject MonGO3;
public GameObject MonGO4;
public GameObject MonGO5;
public GameObject MonGO6;
public TMP_Text Coinvaltext;
MiniMonster MM0;
MiniMonster MM1;
MiniMonster MM2;
MiniMonster MM3;
MiniMonster MM4;
MiniMonster MM5;
MiniMonster MM6;
ItemStatBlock M1I;
ItemStatBlock M2I;
ItemStatBlock M3I;
ItemStatBlock M4I;
ItemStatBlock M5I;
ItemStatBlock M6I;
public BattleState state;
public Image StatusBG;
public TMP_Text StatusTextObj;
public SlotAction Mon1 = SlotAction.NULL;
public SlotAction Mon2 = SlotAction.NULL;
public SlotAction Mon3 = SlotAction.NULL;
public SlotAction Mon4 = SlotAction.NULL;
public SlotAction Mon5 = SlotAction.NULL;
public SlotAction Mon6 = SlotAction.NULL;
public List<int> TurnOrder;
int TurnsTaken;
public int EnemyTarget;
public int AllyTarget;
public GameObject PlayerABUIGO;
public List<MiniMonster> Monsters;
public MiniMonAbilityHandler ABHandler;
public TMP_Text S1AB2CD;
public TMP_Text S2AB2CD;
public TMP_Text S3AB2CD;
public TMP_Text S1IABCD;
public TMP_Text S2IABCD;
public TMP_Text S3IABCD;
public int EnemyAITarget;
// Start is called before the first frame update
void Start()
{
Time.timeScale = 1f;
Monsters = new List<MiniMonster>();
state = BattleState.START;
player.LoadPlayer();
Coinvaltext.text = player.coins.ToString();
MonsterInit();
ItemInit();
Monsters.Add(MM0);
Monsters.Add(MM1); Monsters.Add(MM2); Monsters.Add(MM3); Monsters.Add(MM4); Monsters.Add(MM5); Monsters.Add(MM6);
state = BattleState.PLAYERTURN;
S1AB2CD.text = MM1.AB2CD.ToString(); S2AB2CD.text = MM2.AB2CD.ToString(); S3AB2CD.text = MM3.AB2CD.ToString();
S1IABCD.text = MM1.ItemCD.ToString(); S2IABCD.text = MM1.ItemCD.ToString(); S3IABCD.text = MM1.ItemCD.ToString();
if (MM1.ItemCD < 1) { S1IABCD.text = ""; } if (MM2.ItemCD < 1) { S2IABCD.text = ""; } if (MM3.ItemCD < 1) { S3IABCD.text = ""; }
SetTarget(4);
SetTarget(1);
PlayerTurn();
}
private void Update()
{
if (state == BattleState.PLAYERTURN)
{
PlayerABUIGO.SetActive(true);
} else PlayerABUIGO.SetActive(false);
if (EnemyTarget == 4) { MM4.TargetimgGO.SetActive(true);} else MM4.TargetimgGO.SetActive(false);
if (EnemyTarget == 5) { MM5.TargetimgGO.SetActive(true); } else MM5.TargetimgGO.SetActive(false);
if (EnemyTarget == 6) { MM6.TargetimgGO.SetActive(true); } else MM6.TargetimgGO.SetActive(false);
if (AllyTarget == 1) { MM1.TargetimgGO.SetActive(true); } else MM1.TargetimgGO.SetActive(false);
if (AllyTarget == 2) { MM2.TargetimgGO.SetActive(true); } else MM2.TargetimgGO.SetActive(false);
if (AllyTarget == 3) { MM3.TargetimgGO.SetActive(true); } else MM3.TargetimgGO.SetActive(false);
}
public void PlayerTurn()
{
if (!MM4.Targettable) { EnemyTarget = 4; }
if (!MM5.Targettable) { EnemyTarget = 5; }
if (!MM6.Targettable) { EnemyTarget = 6;}
if (!MM1.Targettable) { AllyTarget = 1;}
if (!MM2.Targettable) { AllyTarget = 2; }
if (!MM3.Targettable) { AllyTarget = 3; }
state = BattleState.PLAYERTURN;
Mon1 = SlotAction.NULL;
Mon2 = SlotAction.NULL;
Mon3 = SlotAction.NULL;
Mon4 = SlotAction.NULL;
Mon5 = SlotAction.NULL;
Mon6 = SlotAction.NULL;
EnemyTurn();
StatusUpdate("Select your Actions");
}
public void AB1(int Slot)
{
if (Slot == 1)
{
Mon1 = SlotAction.AB1;
}
if (Slot == 2)
{
Mon2 = SlotAction.AB1;
}
if (Slot == 3)
{
Mon3 = SlotAction.AB1;
}
CheckIfPlayerDone();
}
public void AB2(int Slot)
{
if (Slot == 1)
{
Mon1 = SlotAction.AB2;
}
if (Slot == 2)
{
Mon2 = SlotAction.AB2;
}
if (Slot == 3)
{
Mon3 = SlotAction.AB2;
}
CheckIfPlayerDone();
}
public void ItemAB(int Slot)
{
if (Slot == 1)
{
Mon1 = SlotAction.ITEM;
}
if (Slot == 2)
{
Mon2 = SlotAction.ITEM;
}
if (Slot == 3)
{
Mon3 = SlotAction.ITEM;
}
CheckIfPlayerDone();
}
public void CheckIfPlayerDone()
{
if (Mon1 != SlotAction.NULL)
{
Monsters[1].selectedAction = Mon1;
if (Mon2 != SlotAction.NULL)
{
Monsters[2].selectedAction = Mon2;
if (Mon3 != SlotAction.NULL)
{
Monsters[3].selectedAction = Mon3;
Monsters[4].selectedAction = Mon4;
Monsters[5].selectedAction = Mon5;
Monsters[6].selectedAction = Mon6;
state = BattleState.ACTION;
TurnOrder = new List<int>();
TurnOrder.Clear();
TurnOrder.Add(MM1.Speed);
TurnOrder.Add(MM2.Speed);
TurnOrder.Add(MM3.Speed);
TurnOrder.Add(MM4.Speed);
TurnOrder.Add(MM5.Speed);
TurnOrder.Add(MM6.Speed);
TurnOrder.Sort();
//TurnsTaken = 0;
ActionState();
}
}
}
}
public void ActionState()
{
foreach (int i in TurnOrder)
{
TakeAction(TurnOrder.IndexOf(i));
StartCoroutine(ActionSequence());
}
CheckForWin();
}
private IEnumerator ActionSequence()
{
// Create a copy of the TurnOrder list and sort it in descending order
List<int> sortedTurnOrder = new List<int>(TurnOrder);
sortedTurnOrder.Sort((a, b) => Monsters[b].Speed.CompareTo(Monsters[a].Speed));
foreach (int spotID in sortedTurnOrder)
{
// Take action for the current spotID
TakeAction(spotID);
// Wait for 3 seconds before executing the next action
yield return new WaitForSeconds(3);
}
CheckForWin();
}
public void TakeAction(int spotID)
{
// Adjust spotID to ensure it's within the range of valid indices
Debug.Log(spotID + " = Unmodified SpotID");
spotID = Mathf.Clamp(spotID, 1, 6);
Debug.Log(spotID + " = Modified SpotID");
// Retrieve the monster based on spotID and check if it's not null
MiniMonster monster = Monsters[spotID];
if (monster != null)
{
Debug.Log(monster.MonName + " - " + spotID + " takes action");
// Check which action to take based on the monster's SlotAction
switch (monster.selectedAction)
{
case SlotAction.AB1:
ABHandler.AB1(spotID + 1, AllyTarget, EnemyTarget);
break;
case SlotAction.AB2:
ABHandler.AB2(spotID + 1, AllyTarget, EnemyTarget);
break;
case SlotAction.ITEM:
ABHandler.ItemAB(spotID + 1, AllyTarget, EnemyTarget);
break;
default:
Debug.LogWarning("Invalid SlotAction for monster: " + monster.MonName);
break;
}
}
}
public void CheckForWin()
{
if (MM1.Dead)
{
if (MM2.Dead)
{
if (MM3.Dead)
{
Debug.Log("Loser!"); //YOU LOSE
return;
}
}
}
if (MM4.Dead)
{
if(MM5.Dead)
{
if (MM6.Dead)
{
Debug.Log("Winner!"); //YOU WIN
return;
}
}
}
RoundCount(); // DO ALL THE TURN TIMERS/CD reductions etc
S1AB2CD.text = MM1.AB2CD.ToString(); S2AB2CD.text = MM2.AB2CD.ToString(); S3AB2CD.text = MM3.AB2CD.ToString();
S1IABCD.text = MM1.ItemCD.ToString(); S2IABCD.text = MM1.ItemCD.ToString(); S3IABCD.text = MM1.ItemCD.ToString();
if (MM1.ItemCD < 1) { S1IABCD.text = " "; } if (MM2.ItemCD < 1) { S2IABCD.text = " "; } if (MM3.ItemCD < 1) { S3IABCD.text = " "; }
if (MM1.ItemCD < 1) { S1AB2CD.text = " "; } if (MM2.ItemCD < 1) { S2AB2CD.text = " "; } if (MM3.ItemCD < 1) { S3AB2CD.text = " "; }
PlayerTurn();
}
public void RoundCount()
{
MM1.ItemCD--; MM1.AB2CD--; MM1.AB2Disabled--; MM1.ItemDisabled--; MM1.Invulnerable--;
MM2.ItemCD--; MM2.AB2CD--; MM2.AB2Disabled--; MM2.ItemDisabled--; MM2.Invulnerable--;
MM3.ItemCD--; MM3.AB2CD--; MM3.AB2Disabled--; MM3.ItemDisabled--; MM3.Invulnerable--;
MM4.ItemCD--; MM4.AB2CD--; MM4.AB2Disabled--; MM4.ItemDisabled--; MM4.Invulnerable--;
MM5.ItemCD--; MM5.AB2CD--; MM5.AB2Disabled--; MM5.ItemDisabled--; MM5.Invulnerable--;
MM6.ItemCD--; MM6.AB2CD--; MM6.AB2Disabled--; MM6.ItemDisabled--; MM6.Invulnerable--;
}
public void SetTarget(int ID)
{
if (ID > 3)
{
if (Monsters[ID].Targettable) { EnemyTarget = ID; UpdateMonUI(); }
}
if (ID <= 3)
{
if (Monsters[ID].Targettable) { AllyTarget = ID; UpdateMonUI(); }
}
}
public int SetEnemyAITarget()
{
int targ = Random.Range(1, 3);
if (Monsters[targ].Targettable) { return targ; }
if (Monsters[1].Targettable) { return 1; }
if (Monsters[2].Targettable) { return 2; }
if (Monsters[3].Targettable) { return 3; }
Debug.Log("EnemyAITarget Failure, targetting ID Spot 0");
return 0;
}
public void UpdateMonUI()
{
MM1.UpdateUI(); MM2.UpdateUI(); MM3.UpdateUI(); MM4.UpdateUI(); MM5.UpdateUI(); MM6.UpdateUI();
}
public SlotAction AISlotAction(int ID)
{
if (ID == 4)
{
if (!MM4.Dead)
{
if (!MM4.isItemPassive)
{
if (MM4.ItemCD < 1)
{
return SlotAction.ITEM;
}
}
if (MM4.AB2CD < 1)
{
return SlotAction.AB2;
}
return SlotAction.AB1;
}
return SlotAction.NULL;
}
if (ID == 5)
{
if (!MM5.Dead)
{
if (!MM5.isItemPassive)
{
if (MM5.ItemCD < 1)
{
return SlotAction.ITEM;
}
}
if (MM5.AB2CD < 1)
{
return SlotAction.AB2;
}
return SlotAction.AB1;
}
return SlotAction.NULL;
}
if (ID == 6)
{
if (!MM6.Dead)
{
if (!MM6.isItemPassive)
{
if (MM6.ItemCD < 1)
{
return SlotAction.ITEM;
}
}
if (MM6.AB2CD < 1)
{
return SlotAction.AB2;
}
return SlotAction.AB1;
}
return SlotAction.NULL;
}
Debug.Log("AISlotAction function failed");
return SlotAction.NULL;
}
public void EnemyTurn()
{
EnemyAITarget = SetEnemyAITarget();
// If they can use their item, they do, then they see if they can use AB2, if not they use AB1
//Monster 4
Mon4 = AISlotAction(4);
//Monster 5
Mon5 = AISlotAction(5);
//Monster 6
Mon6 = AISlotAction(6);
}
public void StatusUpdate(string StatusText)
{
StatusBG.GetComponent<Animator>().Play("FadeInStatusBG");
StatusTextObj.text = StatusText;
}
void MonsterInit()
{
MM0 = MonGO0.GetComponentInChildren<MiniMonster>();
MM1 = MonGO1.GetComponentInChildren<MiniMonster>();
MM1.setupMon(GrabMonStat(player.MiniMonS1ID), 1);
MM2 = MonGO2.GetComponentInChildren<MiniMonster>();
MM2.setupMon(GrabMonStat(player.MiniMonS2ID), 2);
MM3 = MonGO3.GetComponentInChildren<MiniMonster>();
MM3.setupMon(GrabMonStat(player.MiniMonS3ID), 3);
MM4 = MonGO4.GetComponentInChildren<MiniMonster>();
MM4.setupMon(GrabMonStat((int)Random.Range(1, MonIDList.Length)), 4);
MM5 = MonGO5.GetComponentInChildren<MiniMonster>();
MM5.setupMon(GrabMonStat((int)Random.Range(1, MonIDList.Length)), 5);
MM6 = MonGO6.GetComponentInChildren<MiniMonster>();
MM6.setupMon(GrabMonStat((int)Random.Range(1, MonIDList.Length)), 6);
}
void ItemInit()
{
M1I = itemIDList[player.MMS1ItemID];
MM1.InitializeItem(itemIDList[M1I.ID]);
M2I = itemIDList[player.MMS2ItemID];
MM2.InitializeItem(itemIDList[M2I.ID]);
M3I = itemIDList[player.MMS3ItemID];
MM3.InitializeItem(itemIDList[M3I.ID]);
M4I = itemIDList[(int)Random.Range(1, itemIDList.Length)];
MM4.InitializeItem(itemIDList[M4I.ID]);
M5I = itemIDList[(int)Random.Range(1, itemIDList.Length)];
MM5.InitializeItem(itemIDList[M5I.ID]);
M6I = itemIDList[(int)Random.Range(1, itemIDList.Length)];
MM6.InitializeItem(itemIDList[M6I.ID]);
}
public StatBlockMon GrabMonStat(int monID)
{
if (monID <= MonIDList.Length)
{
return MonIDList[monID];
}
else return null;
}
public ItemStatBlock GrabItemStat(int itemID)
{
if (itemID <= itemIDList.Length)
{
return itemIDList[itemID];
}
else return null;
}
}
I will take any feedback on the script as a whole. I am still learning, this is a personal project that I’m trying to learn from. I’m sure there’s a lot that could be done better or more efficiently. The problem parts I’ve tried understanding with help from ChatGPT, but I’m getting different errors no matter how I try to do it.