/// <summary> /// Gets a list with the monsters available on the AIs field sorted into /// strongest to weakest. /// </summary> /// <returns>The strongest to weakest monsters.</returns> /// <param name="ml">Monsterzone list to sort</param> protected List <DuelMonsterZoneScript> GetStrongestToWeakestMonsters( DuelMonsterZoneScript[] ml) { bool flag = true; for (int o = 1; (o < ml.Length) && flag; o++) //Do an outer loop //around the array { flag = false; for (int i = 0; i < ml.Length - 1; i++) { //Foreach of the numbers next to the outer loop point if (((Monster)ml [i + 1].ZoneCard).Attack > ((Monster)ml [i].ZoneCard).Attack) //Compare the attacks //Swap the monsters in the array { DuelMonsterZoneScript temp = ml [i]; ml [i] = ml [i + 1]; ml [i + 1] = temp; flag = true; } } } return(ml.ToList()); //Return the array back as list }
/// <summary> /// Button to cancel the attack and close the overlay. Will also reset any /// variables that have been effected during the attack process /// </summary> public void btn_CloseOverlay() { attackingMonster.hasAttacked = false; //Fixed a bug here! attackingMonster = null; defendingMonster = null; gameObject.SetActive(false); }
/// <summary> /// Coroutine to conduct the animation and logic for a direct attack battle /// between the attacking monster and the defending monsters life points /// </summary> /// <returns>void</returns> /// <param name="attackingMonster">Attacking monster.</param> /// <param name="againstPlayer">If set to <c>true</c> against player.</param> public IEnumerator IMakeAttack(DuelMonsterZoneScript attackingMonster, bool againstPlayer) { yield return(new WaitForSeconds(1.0f)); //This is when a direct attack has been made int attackersScore = ((Monster)attackingMonster.ZoneCard).Attack; int defendersScore = 0; int damage = defendersScore - attackersScore; ui_attackersPicture.sprite = ((Monster)attackingMonster.ZoneCard).Image; ui_defendersPicture.sprite = null; ui_defendersPicture.color = Color.black; ui_attackersDamage.text = ""; ui_defendersDamage.text = damage.ToString(); ui_attackingOverlay.SetActive(true); glob_audiomanager.SendMessage("PlayDuelDirectHit"); yield return(new WaitForSeconds(2.1f)); ui_attackingOverlay.SetActive(false); if (againstPlayer) { //This means the AI is attacking the player player_liveLifePoints -= attackersScore; } else { //The player is attacking the AI directly duel_ai.ai_liveLifePoints -= attackersScore; } }
/// <summary> /// Coroutine to begin a battle between an attacking monster and a direct /// attack against the opponent /// </summary> /// <returns>void</returns> /// <param name="attackingMonster">Attacking monster.</param> /// <param name="againstPlayer">If set to <c>true</c> against player.</param> public IEnumerator IPlayerBattle(DuelMonsterZoneScript attackingMonster, bool againstPlayer) { yield return(StartCoroutine(IMakeAttack(attackingMonster, false))); yield return(new WaitForSeconds(1.0f)); yield return(StartCoroutine(IReduceLifePoints())); }
/// <summary> /// Logic for the AI setting a monster /// </summary> /// <returns>void</returns> /// <param name="emptyZone">Empty monster zone to set the card too</param> /// <param name="cardToSet">Card to set</param> protected IEnumerator ISetMonster(DuelMonsterZoneScript emptyZone, Monster cardToSet) { Debug.Log("AI: Setting " + cardToSet.Name); duel_controller.ShowMessageFromAI(ai_details.ai_image, ai_details.speech_SetCard); //Display message emptyZone.PlaceCardOnZone(cardToSet, true); ai_hand.Remove(cardToSet); //Remove card from the AI's hand yield return(new WaitForSeconds(1.3f)); }
/// <summary> /// Logic for the AI to summon a monster /// </summary> /// <returns>void</returns> /// <param name="emptyZone">Empty monster zone to summon the card too</param> /// <param name="cardToSummon">Card to summon to the empty zone</param> protected IEnumerator ISummonMonster(DuelMonsterZoneScript emptyZone, Monster cardToSummon) { Debug.Log("AI: Summoning " + cardToSummon.Name); //Show summoning message duel_controller.ShowMessageFromAI(ai_details.ai_image, ai_details.speech_SummonCard + cardToSummon.Name); //Start the summoning sequence and animation in the DuelMonsterZoneScript emptyZone.PlaceCardOnZone(cardToSummon, false); //Since the card has been played onto the field, we can //now remove it from the AIs hand ai_hand.Remove(cardToSummon); yield return(new WaitForSeconds(1.3f)); }
/// <summary> /// Called when the user presses one of the UI buttons over the AI monster /// zone. Gets the defending monsters details depending on which button it /// was that was pressed. /// </summary> /// <param name="positionOnField">Position of targeted monster</param> public void btn_Selected(int positionOnField) { //Get the defending monster details defendingMonster = duelControllerScript.ui_ai_monsterZones [positionOnField]; //Start the battle sequence/animation duelControllerScript.StartCoroutine( duelControllerScript.IPlayerBattle( attackingMonster, defendingMonster, false)); //Close down this overlay attackingMonster = null; defendingMonster = null; gameObject.SetActive(false); }
/// <summary> /// Logic for making a direct attack /// </summary> /// <returns>void</returns> /// <param name="cardToAttack">Card zone attacking with</param> protected IEnumerator IDirectAttack(DuelMonsterZoneScript cardToAttack) { duel_controller.ShowMessageFromAI(ai_details.ai_image, ai_details.speech_DirectAttack + cardToAttack.ZoneCard.Name); //Output message yield return(new WaitForSeconds(1.3f)); yield return(StartCoroutine(duel_controller. IMakeAttack(cardToAttack, true))); //Start the animation/sequence yield return(new WaitForSeconds(0.7f)); //Reduce the life points of either the Player or AI depending on who //took what damage yield return(StartCoroutine(duel_controller.IReduceLifePoints())); }
/// <summary> /// Method for getting the first avaialble Monster Zone of the players /// field /// </summary> /// <returns>The empty monster zone script</returns> private DuelMonsterZoneScript getEmptyMonsterZone() { DuelMonsterZoneScript returnScript = null; if (!isMonsterZonesFull()) //No point continuing if the zones are full { foreach (DuelMonsterZoneScript zone in duelController.ui_playerMonsterZones) { if (zone.ZoneCard == null) { returnScript = zone; break; } } } return(returnScript); }
/// <summary> /// Logic for the AI attackin a monster with one of its own /// </summary> /// <returns>void</returns> /// <param name="attackingMonster">Attacking monster.</param> /// <param name="defendingMonster">Defending monster.</param> protected IEnumerator IMakeAttack(DuelMonsterZoneScript attackingMonster, DuelMonsterZoneScript defendingMonster) { duel_controller.ShowMessageFromAI(ai_details.ai_image, ai_details.speech_NormalAttack + attackingMonster.ZoneCard.Name); //Output message and wait yield return(new WaitForSeconds(1.3f)); yield return(StartCoroutine(duel_controller. IMakeAttack(attackingMonster, defendingMonster, true))); //Start //the attacking sequence/animation yield return(new WaitForSeconds(0.7f)); //Wait //Reduce the Life Points of either the Player or AI depending on who //took the damage yield return(StartCoroutine(duel_controller.IReduceLifePoints())); }
/// <summary> /// Gets the first empty monster zone on the AI's side of the field /// </summary> /// <returns>The first empty monster zone.</returns> protected DuelMonsterZoneScript GetFirstEmptyMonsterZone() { DuelMonsterZoneScript returnScript = null; //The returned zone if (!isMonsterZonesFull()) //If the monster zones are all full //then no point in even going into the loop { foreach (DuelMonsterZoneScript zone in ai_monsterzones) { if (zone.ZoneCard == null) //Check if the zonecard is null //If it is null then it means a monster doesn't occupy //that space and we can return it { returnScript = zone; break; } } } return(returnScript); }
/// <summary> /// Gets the strongest monster on player field. /// </summary> /// <returns>The strongest monster on player field.</returns> public DuelMonsterZoneScript GetStrongestMonsterOnPlayerField() { DuelMonsterZoneScript returnCard = null; int flaggedStrongest = 0; foreach (DuelMonsterZoneScript mon in ui_playerMonsterZones) { //foreach monster card in the monster card zone if (mon.ZoneCard != null) //If it's not empty { DuelMonsterZoneScript temp = mon; //Compare the monsters attack with the previously found attack if (((Monster)mon.ZoneCard).Attack > flaggedStrongest) { //Assign it flaggedStrongest = ((Monster)mon.ZoneCard).Attack; returnCard = temp; } } } return(returnCard); //Return }
/// <summary> /// Command executed when the UI button in the Monster position selection /// menu is pressed. Depending if facedown is selected or not will /// depend on how the game places the card onto the screen/field /// </summary> /// <param name="facedown">If set to <c>true</c> facedown.</param> public void btn_PlaceMonsterCard(bool facedown) { glob_audiomanager.SendMessage("PlayClickB"); if (temp != null && temp is Monster) //Only do this if it is a monster! { Monster monster = (Monster)temp; DuelMonsterZoneScript dz = getEmptyMonsterZone(); //Get empty zone //to assign this card to if (dz != null) { Debug.Log("DuelCardScannerScript: Player summoning " + monster.Name); //Play the animation/sequence for displaying the card dz.PlaceCardOnZone(monster, facedown); CloseSafely(); } else { Debug.Log("DuelCardScannerScript: Monster Zones full"); //Display error message } } }
/// <summary> /// Coroutine to conduct the animation and logic for a battle involving /// an attacking monster and the defending monster. /// </summary> /// <returns>void</returns> /// <param name="attackingMonster">Attacking monster.</param> /// <param name="defendingMonster">Defending monster.</param> /// <param name="againstPlayer">If set to <c>true</c> against player.</param> public IEnumerator IMakeAttack(DuelMonsterZoneScript attackingMonster, DuelMonsterZoneScript defendingMonster, bool againstPlayer) { yield return(new WaitForSeconds(1.0f)); int attackersScore = ((Monster)attackingMonster.ZoneCard).Attack; int defendersScore = 0; //Decided whether we are using the defenders Defence or Attack score if (defendingMonster.isDefenceMode) { //Use defence mode score defendersScore = ((Monster)defendingMonster.ZoneCard).Defence; } else { //Use attack mode score defendersScore = ((Monster)defendingMonster.ZoneCard).Attack; } //Workout the damage int damage = defendersScore - attackersScore; int lifePointsToReduceBy = 0; //Assign monster images ui_attackersPicture.sprite = ((Monster)attackingMonster.ZoneCard).Image; ui_defendersPicture.color = Color.white; //Reset incase a direct //attack as happened as the black with hide the picutre we set ui_defendersPicture.sprite = ((Monster)defendingMonster.ZoneCard).Image; //Check what damage is done to what card if (damage <= 0) { ui_attackersDamage.text = ""; ui_defendersDamage.text = damage.ToString(); } else { ui_attackersDamage.text = (-damage).ToString(); ui_defendersDamage.text = ""; } //Display the Attackers overlay ui_attackingOverlay.SetActive(true); glob_audiomanager.SendMessage("PlayDuelDirectHit"); yield return(new WaitForSeconds(2.1f)); ui_attackingOverlay.SetActive(false); //Work out, which monster(s) gets destroyed and the life points to //reduce if (damage < 0) { //Defending monster is destroyed if (!defendingMonster.isDefenceMode) { lifePointsToReduceBy = -damage; } yield return(StartCoroutine( defendingMonster.IDestroyCard(againstPlayer))); } else if (damage == 0 && !defendingMonster.isDefenceMode) { //When the battle is a tie and the monster is in defence, then //no monsters are destroyed, otherwise... yield return(StartCoroutine( defendingMonster.IDestroyCard(againstPlayer))); yield return(StartCoroutine( attackingMonster.IDestroyCard(!againstPlayer))); //Damage would be 0 because Attack was equal //Therefore we do not touch the lifepoints to reduce variable } else { //The attacking monster is weaker than the opponents defending, //so destroy the attacking monster yield return(StartCoroutine( attackingMonster.IDestroyCard(againstPlayer))); lifePointsToReduceBy = damage; //Reverse the damage because the attacker is taking the damage againstPlayer = !againstPlayer; } //Do damage to the appropriate player if (againstPlayer) { player_liveLifePoints -= lifePointsToReduceBy; } else { duel_ai.ai_liveLifePoints -= lifePointsToReduceBy; } canPlayerAttack = checkCanPlayerAttack(); canPlayerDirectAttack = checkCanPlayerDirectAttack(); yield return(new WaitForSeconds(0.5f)); }
/// <summary> /// Called when the Player selects a monster on his/her side of the field /// and selects the attack option. Brings up this overlay /// </summary> /// <param name="aMonster">Selected monster</param> public void StartTargetSelection(DuelMonsterZoneScript aMonster) { attackingMonster = aMonster; //Assign it to the attacking monster pos }
/// <summary> /// Shows the card options overlay when a monster zone has been selected /// </summary> /// <param name="selectedCard">Selected card.</param> public void ShowCardOptionsOverlay(DuelMonsterZoneScript selectedCard) { selectedZone = selectedCard; //Assign the selected card to the var //so when one of the button functions is called it knows which card //to check/use }
/// <summary> /// Executes all the logic done in the Main Phase 1 of the AIs turn /// Typically this is all logic to do with summoning a monster /// </summary> /// <returns>void</returns> protected IEnumerator MainPhase1() { //Use this space for activiating Spell/Trap cards and Summoning monsters Debug.Log("AI: Entering Main Phase 1"); duel_controller.ChangeTurnPhase(DuelSceneScript.TurnPhase.MAINPHASE1); //Setup variables used in checking DuelMonsterZoneScript emptyZone; Monster strongestInHand; Monster aStrongestField; Monster pStrongestField; Monster aDefenseInHand; //Monster aDefenseOnField; if (canSummon && !isMonsterZonesFull()) { Debug.Log("AI: Can summon a monster"); //Then we can summon a monster emptyZone = GetFirstEmptyMonsterZone(); if (duel_controller.turnCounter <= 1) //If AI is playing first turn, //Then let us pick the strongest monster and place it in attack { Monster monster = GetHighestAttackMonsterInHand(); if (monster != null && emptyZone != null) { yield return(StartCoroutine( ISummonMonster(emptyZone, monster))); } } else //Otherwise lets check the Player field and make a decision { strongestInHand = GetHighestAttackMonsterInHand(); aStrongestField = GetHighestAttackMonsterOnField(); DuelMonsterZoneScript tempFind = duel_controller.GetStrongestMonsterOnPlayerField(); pStrongestField = (tempFind != null) ? (Monster)tempFind.ZoneCard : null; // if (pStrongestField == null) { //The players field is empty! We can summon our strongest //monster and go for a direct attack! if (strongestInHand != null && emptyZone != null) { //We have space on our field and got a monster from //our hand. We can now summon it! yield return(StartCoroutine( ISummonMonster(emptyZone, strongestInHand))); } } else //The player has a monster on the field { if (strongestInHand != null && aStrongestField != null) { //The AIs hand is not empty and the AI's field is not //empty if (strongestInHand.Attack >= pStrongestField.Attack || aStrongestField.Attack >= pStrongestField.Attack) { yield return(StartCoroutine( ISummonMonster(emptyZone, strongestInHand))); } else { goDefensive = true; } } else if (strongestInHand != null) { //The AIs hand is not empty but the field may be empty if (strongestInHand.Attack >= pStrongestField.Attack) { yield return(StartCoroutine( ISummonMonster(emptyZone, strongestInHand))); } else { goDefensive = true; } } else if (aStrongestField != null) { //The AI's field is not empty but the hand might be if (aStrongestField.Attack >= pStrongestField.Attack) { if (aStrongestField.Attack == pStrongestField.Attack && ai_monsterzones.Count > 1) { //When the AI has a monster of equal attack //which is can 'throw away' in a monster for //monster battle but still have monsters to //defend or attack with if (strongestInHand != null) { yield return(StartCoroutine( ISummonMonster(emptyZone, strongestInHand))); } } } else { //The AI has nothing strong enough, go defensive goDefensive = true; } } } } } else { //AI cannot summon or monster zones are full Debug.Log("AI: Cannot summon a monster"); //Check field to see if the AI needs to go defensive as we cannot //summon this turn aStrongestField = GetHighestAttackMonsterOnField(); pStrongestField = (Monster)duel_controller. GetStrongestMonsterOnPlayerField().ZoneCard; if (pStrongestField != null) { if (aStrongestField != null) { if (aStrongestField.Attack < pStrongestField.Attack) { goDefensive = true; } } else { goDefensive = true; } } } if (goDefensive && canSummon && !isMonsterZonesFull()) { //Check if we can place a Facedown defense position mosnter //instead Debug.Log("AI: going defensive"); emptyZone = GetFirstEmptyMonsterZone(); aDefenseInHand = GetHighestDefenceMonsterInHand(); if (aDefenseInHand != null && emptyZone != null) { yield return(StartCoroutine(ISetMonster(emptyZone, aDefenseInHand))); } } }
/// <summary> /// Executes all logic for the AIs Battle Phase. Normally has to do with /// selecting which monster battles or if the AI can directly attack the /// player /// </summary> /// <returns>void</returns> protected IEnumerator BattlePhase() { //You cannot conduct a Battle Phase on your first turn, therefore Debug.Log("AI: Entering Battle Phase"); duel_controller.ChangeTurnPhase(DuelSceneScript.TurnPhase.BATTLEPHASE); //Get a list of monsters that are able to attack first! //First check if the opponents field is empty List <DuelMonsterZoneScript> ml = GetMonstersAvailableToAttack(); //If the list is empty, then no point in doing any more check! if (ml != null && ml.Count > 0) { //Avaialble for a direct attack? if (canDirectAttack()) { Debug.Log("AI: Is able to make a direct attack"); foreach (DuelMonsterZoneScript monster in ml) { yield return(StartCoroutine(IDirectAttack(monster))); } } else { //Player has some monsters on the field //Scan field and pair AI monsters to attack/stats of Players Debug.Log("AI: Cannot make a direct attack"); if (!goDefensive) { ml = GetStrongestToWeakestMonsters(ml.ToArray()); for (int i = 0; i < ml.Count; i++) { if (canDirectAttack()) { //Direct attack yield return(StartCoroutine( IDirectAttack(ml[i]))); } else { //Get the strongest monster on the field, or next //strongest monster as the AI counts downwards //from it's strongest monster DuelMonsterZoneScript pMonster = duel_controller. GetStrongestMonsterOnPlayerField(); //Compare and attack //Check first if the defending monster is in defence //mode or attack mode if (pMonster != null) { if (pMonster.isDefenceMode) { //Monster is in defence if (((Monster)ml [i].ZoneCard).Attack > ((Monster)pMonster.ZoneCard).Defence) { //Attack the defensive monster! yield return(StartCoroutine( IMakeAttack(ml [i], pMonster))); } } else { if (((Monster)ml [i].ZoneCard).Attack >= ((Monster)pMonster.ZoneCard).Attack) { //Attack the attacking monster, //this AI is going all out! yield return(StartCoroutine( IMakeAttack(ml [i], pMonster))); } } } } } } else { Debug.Log("AI: Going defensive so not conducting battle"); } } } else { Debug.Log("AI: No monsters available to attack"); } }