void RunBattleSimulation() { // 2 states - Select Action and Execute Action // on select action set the actor to the current // show the UI for where the default action will place them switch (state) { case BossBattleState.EndOfTurn: break; case BossBattleState.NewTurn: // Clean up the list of dead actors List <BattleActor> removeList = new List <BattleActor>(); foreach (BattleActor actor in TurnOrder) { if (actor.Health <= 0f) { actor.StopCast(); battleInterface.RemoveActorPortrait(actor); removeList.Add(actor); deadActors.Add(actor); if (actor is BossActor) { ((BossActor)actor).handler.Die(); } else { ((HeroActor)actor).handler.Die(); } } } bool bossKilled = false; foreach (BattleActor actor in removeList) { if (actor is BossActor) { bossKilled = true; } TurnOrder.Remove(actor); } if (bossKilled) { // on allyDeathTrigger foreach (BattleActor actor in TurnOrder) { if (actor is BossActor) { ((BossActor)actor).OnAllyDeath(); } } } currentActor = TurnOrder[0]; selector.GoToTarget(currentActor.GetGameObject().transform.position); if (currentActor is HeroActor) { print(" --- [New Turn]\n Hero Turn: " + currentActor.Name); } else { print(" --- [New Turn]\n Boss Turn: " + currentActor.Name); } // Check if the current actor is stunned here and skip their turn if (currentActor.IsStunned()) { // Spawn text displaying this actor is stunned then return to restart this turn and choose a new actor currentActor.UpdateStatusEffects(StatusTriggerTime.StartOfTurn); currentActor.UpdateStatusEffects(StatusTriggerTime.EndOfTurn); return; } // this position allows stun transitions to be delayed when stunned, we can move this above the stun code block to change this if (currentActor is BossActor) { ((BossActor)currentActor).UpdateTurnCount(); } //Check for end of battle here if (IsBattleComplete()) { state = BossBattleState.EndOfBattle; } else { // Check if the actor has a skill waiting to be used if (currentActor.HasQueuedSkill()) { // Skip straight to the use the skill part of a turn SelectSkill(currentActor.QueuedSkill); ExecuteSkill(currentActor.QueuedSkillTarget, true); currentActor.QueuedSkill = null; currentActor.QueuedSkillTarget = null; } else { state = BossBattleState.SelectAction; } } break; case BossBattleState.SelectAction: battleInterface.SetCurrentTurn(currentActor); currentActor.UpdateStatusEffects(StatusTriggerTime.StartOfTurn); // Load UI for the hero or hide it on enemy if (currentActor is HeroActor) { // Reduce skill cooldowns by a turn foreach (Skill skill in ((HeroActor)currentActor).hero.Skills) { /*if (((HeroActor) currentActor).hero.Skills[skill] > 0) * ((HeroActor) currentActor).hero.Skills[skill] -= 1;*/ if (skill._cooldown > 0) { skill._cooldown--; } } battleInterface.ShowMemberArea((HeroActor)currentActor); SelectSkill(((HeroActor)currentActor).hero.Skills[((HeroActor)currentActor).hero.Skills.Count - 1]); // default skill selected bossTurn = false; } else { SelectSkill(((BossActor)currentActor).boss.Skills[0]); // Choose a skill based on how many targets int targetCount = 0; bool targetCasting = false; foreach (HeroActor actor in Party) { if (actor.Health > 0) { targetCount++; } if (actor.QueuedSkill != null) { targetCasting = true; } } Skill skillSelect = null; foreach (Skill skill in ((BossActor)currentActor).boss.Skills) { if (skill._cooldown < 1 && skill.CanInterrupt) { skillSelect = skill; } } // TODO put the interrupt AI chance on the boss data it self, current set to 25% of the time if (targetCasting && Random.Range(0f, 1f) < 0.25f && skillSelect != null) { // Choose the skill that can interrupt SelectSkill(skillSelect); } else if (targetCount > 2) { // It can be an AOE skill bool hasAOE = false; foreach (Skill skill in ((BossActor)currentActor).boss.Skills) { if (skill._cooldown < 1 && skill.TargetType != SkillTargetType.SingleTarget) { hasAOE = true; SelectSkill(skill); continue; } } if (!hasAOE) { foreach (Skill skill in ((BossActor)currentActor).boss.Skills) { if (skill._cooldown < 1) { SelectSkill(skill); continue; } } } } else { // Not AOE skill foreach (Skill skill in ((BossActor)currentActor).boss.Skills) { if (skill._cooldown < 1) { SelectSkill(skill); continue; } } } // if target count is >= 3 then you can use an AOE skill // otherwise use your best ability thats not an attack // if no other abilities then use an attack bossTurn = true; } state = BossBattleState.WaitForAction; break; case BossBattleState.ExecuteAction: //print("Execute Action"); // Do Queued Actions then (if there is a heal on multiple members or an attack that hits multiple targets etc) if (!PlayerPrefs.HasKey("tutorial_boss_battle_castable_skill")) { foreach (BattleActor actor in TurnOrder) { if (actor is BossActor && ((BossActor)actor).QueuedSkill != null) { StoryManager.Instance.DisplayStory("story_tutorial_boss_battle_interrupt"); PlayerPrefs.SetInt("tutorial_boss_battle_castable_skill", 1); } } } // go to the next actor currentActor.UpdateStatusEffects(StatusTriggerTime.EndOfTurn); //state = BossBattleState.NewTurn; StartEndOfTurn(); break; case BossBattleState.WaitForAction: // Update the turn order position based on selected skill if (bossTurn && bossActionRoutine == null) { AIActionSelect(); } // Select skill from UI // on target select add the ability to the queue and if (Input.GetMouseButtonDown(0) && !bossTurn && executeActionRoutine == null) { // see what we tapped, but for now just use the action RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero); //fctLocation = Camera.main.ScreenToWorldPoint(Input.mousePosition); if (hit.collider != null) { BattleActor target = null; //Debug.Log("Target Position: " + hit.collider.gameObject.transform.position + " | hit: " + hit.collider.gameObject.name); CharacterHandler h_handler = hit.collider.gameObject.GetComponent <CharacterHandler>(); if (h_handler != null) { print("Have CharacterHandler"); // Is a hero foreach (BattleActor hA in TurnOrder) { if (hA is HeroActor) { if (((HeroActor)hA).handler == h_handler) { target = hA; } } } print(target); if (target != null) { ExecuteSkill(target); } } MonsterHandler m_handler = hit.collider.gameObject.GetComponent <MonsterHandler>(); if (m_handler != null) { // Is a monster foreach (BattleActor bA in TurnOrder) { if (bA is BossActor) { if (((BossActor)bA).handler == m_handler) { target = bA; } } } //print(target); if (target != null) { ExecuteSkill(target); } } } } break; case BossBattleState.EndOfBattle: bool heroStillExists = false; bool bossStillExists = false; foreach (BattleActor actor in TurnOrder) { if (actor is HeroActor) { heroStillExists = true; } if (actor is BossActor) { bossStillExists = true; } } ActiveExploration activeZone = playerMan.SelectedBattle; if (!bossStillExists) { // Player won float chance = 0.2f + Mathf.Min((activeZone.TreasureFind / 3000f), 0.75f) * 0.8f; for (int i = 0; i < dataMan.globalData.GetGlobalAsInt(GlobalProps.ZONE_MONSTER_COUNT); i++) { if (Random.Range(0f, 1f) <= chance) { LootCrateScreenInterface.GenerateLootCrate(activeZone, MagicFindBoostMultiplier: playerMan.GetBoost(BoostType.MagicFind)); } } for (int i = 0; i < activeZone.ChestsEarned; i++) { LootCrateScreenInterface.GenerateLootCrate(activeZone, MagicFindBoostMultiplier: playerMan.GetBoost(BoostType.MagicFind)); } LootCrateScreenInterface.GenerateLootCrate(activeZone, TriggerInterfaceAfterLootCratesAdded, true, playerMan.GetBoost(BoostType.MagicFind)); } else if (!heroStillExists) { // Player was defeated StartCoroutine(ResurrectForGems(activeZone)); } playerMan.CurrentLeaderSkill = null; state = BossBattleState.ShowResults; break; case BossBattleState.ShowResults: break; } }