/** * @brief Run through all enemies and decide what actions to take. (Should only be called after the player has made their turn) * */ public void DecideEnemyTurns() { for (int i = 0; i < EnemyEntities.Count; ++i) { // Randomly pick a party member to attack PartyEntity targetPlayer = GetPartyEntityBySlot((ePartySlot)Random.Range(0, PartyMembers.Length)); // Invalid target, find first conscious party member instead if (targetPlayer.CurrentStatus == eStatusEffect.UNCONSCIOUS) { foreach (var party in PartyEntities) { if (party.CurrentStatus != eStatusEffect.UNCONSCIOUS) { targetPlayer = party; } } } EnemyEntity senderEnemy = EnemyEntities[i]; _commandList.Add(new TECF.EntityCommand { cmdType = TECF.eCommandType.ATTACK, sender = senderEnemy, target = targetPlayer }); } }
void OnRunThroughCommands(IEventInfo a_info) { // Sort list by sender turn order (highest to lowest) _commandList.Sort((a, b) => - (CalcTurnVal(a.sender.BattleProfile.Speed).CompareTo(CalcTurnVal(b.sender.BattleProfile.Speed)))); // Go through command list and execute appropriate actions foreach (var cmd in _commandList) { switch (cmd.cmdType) { case TECF.eCommandType.ATTACK: /// Get ready function PartyEntity party = cmd.sender as PartyEntity; UnityAction partyReadyFunc = null; // Party is attacking, ready them if (party != null) { partyReadyFunc = () => { EventManager.TriggerEvent("OnPartyReady", new PartyInfo { partySlot = party.partySlot }); }; } // Enemy is attacking, unready all other party members else { partyReadyFunc = () => { EventManager.TriggerEvent("PartyUnready", new PartyInfo { partySlot = ePartySlot.NONE }); }; } /// Attacking dialog DialogManager.Instance.AddToQueue(new DialogInfo { dialogType = eDialogType.ATTACKING, senderEntity = cmd.sender, targetEntity = cmd.target, endDialogFuncDelay = ActionLineSwitchRate, startDialogFunc = partyReadyFunc }); /// 1. Check for miss int missNum = Random.Range(0, 100); int missChance = Mathf.RoundToInt(ChanceToMiss * 100); // Missed attack if (missNum <= missChance) { DialogManager.Instance.AddToQueue(new DialogInfo { dialogType = TECF.eDialogType.MISS, senderEntity = cmd.sender, targetEntity = cmd.target, endDialogFuncDelay = ActionLineSwitchRate }); // No need to check other steps break; } /// 2. Check for dodge int dodgeNum = Random.Range(0, 100); int dodgeChance = Mathf.RoundToInt(((2 * cmd.target.BattleProfile.Speed - cmd.sender.BattleProfile.Speed) / 500f) * 100); // Dodge success if (dodgeNum <= dodgeChance) { DialogManager.Instance.AddToQueue(new DialogInfo { dialogType = TECF.eDialogType.DODGED, senderEntity = cmd.sender, targetEntity = cmd.target, endDialogFuncDelay = ActionLineSwitchRate }); // No need to check other steps break; } /// 3. Confirmed hit, calculate damage int attackDmg = Mathf.RoundToInt(CalcDmgVal(eStatusEffect.NORMAL, cmd.sender, cmd.target)); /// 4. Check for critical hit int critNum = Random.Range(0, 100); int firstCritChance = Mathf.RoundToInt((cmd.sender.BattleProfile.Guts / 500f) * 100); int secondCritChance = Mathf.RoundToInt((1f / 20f) * 100); int critChance = Mathf.Max(firstCritChance, secondCritChance); // Crit success if (critNum <= critChance) { DialogManager.Instance.AddToQueue(new DialogInfo { dialogType = TECF.eDialogType.CRITICAL_HIT, senderEntity = cmd.sender, targetEntity = cmd.target }); attackDmg *= CriticalHitModifier; } /// 5. Send damage to the target after dialog finishes DialogManager.Instance.AddToQueue(new DialogInfo { strData = attackDmg.ToString(), dialogType = TECF.eDialogType.DAMAGED, senderEntity = cmd.sender, targetEntity = cmd.target, startDialogFunc = () => { EventManager.TriggerEvent("TakeDamage", new DamageInfo { dmg = attackDmg, senderEntity = cmd.sender, targetEntity = cmd.target, statusEffect = eStatusEffect.NORMAL }); }, endDialogFuncDelay = ActionLineSwitchRate }); break; default: break; } } // Gone through all commands, clear the list _commandList.Clear(); // Activate action phase dialog EventManager.TriggerEvent("RunDialog", new DialogRunInfo { onDialogCompleteFunc = () => { EventManager.TriggerEvent("EndActionPhase"); } }); }
private void Start() { CurrPartySlot = ePartySlot.NONE; /// Priority enemy BattleProfile priorityEnemy = Enemies[0]; // Enemy in first slot influences visuals and audio of whole battle Debug.Assert(priorityEnemy, "BATTLEMANAGER::No enemies set!"); // Set enemy background ReferenceManager.Instance.enemyBG.sprite = priorityEnemy.BattleBackground; // Add enemy audio to main system and secondary systems ReferenceManager.Instance.mainAudio.AudioFiles.AddRange(priorityEnemy.BattleSFX); ReferenceManager.Instance.secondaryAudio.AudioFiles.AddRange(priorityEnemy.BattleSFX); // Start battle music, playing intro first if there is one AudioClip introClip = ReferenceManager.Instance.mainAudio.HasClip("INTRO"); if (introClip) { // Play intro and then play main loop after it ReferenceManager.Instance.mainAudio.SetLooping(false); ReferenceManager.Instance.mainAudio.PlayClip("{\"alias\":\"INTRO\",\"volume\":1}"); ReferenceManager.Instance.secondaryAudio.SetLooping(true); ReferenceManager.Instance.secondaryAudio.PlayClipWithDelay("{\"alias\":\"LOOP\",\"volume\":1}", introClip.length, true); } else if (ReferenceManager.Instance.mainAudio.HasClip("LOOP")) { ReferenceManager.Instance.mainAudio.SetLooping(true); ReferenceManager.Instance.mainAudio.PlayClip("{\"alias\":\"LOOP\",\"volume\":1}"); } /// Enemies for (int i = 0; i < Enemies.Length; ++i) { GameObject eObj = Instantiate(EnemyBlueprint); EnemyEntity eEe = eObj.GetComponent <EnemyEntity>(); // Set to relevant slot eEe.enemySlot = (eEnemySlot)i; // Set type eEe.EntityType = eEntityType.ENEMY; // Assign battle profile eEe.BattleProfile = Enemies[i]; // Keep track of enemy entity EnemyEntities.Add(eEe); eObj.transform.SetParent(ReferenceManager.Instance.enemyPanel.transform); } /// Party members for (int i = 0; i < PartyMembers.Length; ++i) { GameObject pmObj = Instantiate(PartyBlueprint); PartyEntity pmPe = pmObj.GetComponentInChildren <PartyEntity>(); // Assign battle profile pmPe.BattleProfile = PartyMembers[i]; // Set type pmPe.EntityType = eEntityType.PARTY; // Set to relevant slot pmPe.partySlot = (ePartySlot)i; // Keep track of party entity PartyEntities.Add(pmPe); pmObj.transform.SetParent(ReferenceManager.Instance.partyPanel.transform); } }