//switch (stateMachine.state) //{ // //PlayerState // case State.channeling: // channel.CheckChannel(); // Targetting(selectedAbility); // if (!channel.isChanneling) // { // state = State.animating; // } // break; // //PlayerState // case State.animating: // print(attackInProgress); // if (!attackInProgress) // { // AIController[] enemies = FindObjectsOfType<AIController>(); // foreach(AIController enemy in enemies) // { // if (enemy.attackInProgress == true && enemy.gameObject!= this.gameObject) // { // return; // } // } // attackInProgress = true; // PerformAttack(selectedAbility); // } //foreach (Cell cell in attackIndicator.convertedCells) //{ // cell.enemyHighlight = false; // attackIndicator.areCellsColored = false; // cell.DoDefaultColor(); // enemyTarget.SaveMaterial(); // enemyTarget.DoDefaultMaterial(); //} // break; // } //} /* GOALS WITHIN THIS CODE * 1. Segment out a combat controller utilized public method pool. This pool will handle calculations that are universal such as zodiac and magic interactions * 2. AIController should handle the decisions of the AI. Namely, seeing which abilities are available to it. Checking to see which ones are best. and picking between them. * 3. An Attack Executor (should be shared with FIGHTER class) Class should handle distributing damage and effects. It will use the singleton, Combat Controller, to access universal algorithms in calculating damage. * 4. Animation needs to be accounted for with a separate timer. The timer will tick normally when not moving or pushing else it will wait for moving or pushing to complete then issue the same "END OF ANIMATION" method. * 5. AIController should resemble a player brain. Any limitations of the enemy class not related to decision making should be relegated to another class. * 6. NEW CLASSES: CC.AttackAlgorithms, AnimationTimer, AttackExecutor, AttackReceiver, PlayerState */ //Pre targeting for relative global and support targeting //dont think this needed. private List <AttackReceiver> GetTargets(EnemyAttack ability, EnemyTarget enemy) { allPushables = FindObjectsOfType <Pushable>(); List <AttackReceiver> newTargets = new List <AttackReceiver>(); List <Pushable> translatedTargetList = new List <Pushable>(); switch (ability.targettingClass) { case TargettingClass.global: foreach (Pushable pushable in allPushables) { foreach (Vector2Int position in ability.globalTargetCells) { if (pushable.GetComponent <Mover>().GetGridPos() == position) { translatedTargetList.Add(pushable); } } } //remove targets based on beeline targeting if (ability.attackTarget == AttackTarget.beeline) { switch (enemyTarget.wing) { case Wing.bow: translatedTargetList.Sort(SortByY); translatedTargetList.Reverse(); break; case Wing.port: translatedTargetList.Sort(SortByX); break; case Wing.starboard: translatedTargetList.Sort(SortByX); translatedTargetList.Reverse(); break; default: print("NO WING DEFINED"); break; } } //final list foreach (Pushable pushable in translatedTargetList) { if (pushable.GetComponent <AttackReceiver>() != null) { newTargets.Add(pushable.GetComponent <AttackReceiver>()); } if (ability.attackTarget == AttackTarget.beeline) { break; } } break; case TargettingClass.relative: Vector2Int[] translatedTargetCells = TranslateRelativeTargetCells(ability.relativeTargetCells, enemy); //print("allPushables count: " + allPushables.Length); foreach (Pushable pushable in allPushables) { foreach (Vector2Int position in translatedTargetCells) { if (pushable.GetComponent <Mover>().GetGridPos() == position) { translatedTargetList.Add(pushable); //print("adding pushable"); } } } //print("translatedTargetCells: " + translatedTargetList.Count); //remove targets based on beeline targeting if (ability.attackTarget == AttackTarget.beeline) { switch (enemyTarget.wing) { case Wing.bow: translatedTargetList.Sort(SortByY); translatedTargetList.Reverse(); break; case Wing.port: translatedTargetList.Sort(SortByX); break; case Wing.starboard: translatedTargetList.Sort(SortByX); translatedTargetList.Reverse(); break; default: print("NO WING DEFINED"); break; } } //final list foreach (Pushable pushable in translatedTargetList) { if (pushable.GetComponent <AttackReceiver>() != null) { newTargets.Add(pushable.GetComponent <AttackReceiver>()); } if (pushable.GetComponent <Destroyable>() != null) { pushable.GetComponent <Destroyable>().DestroySelf(); } if (ability.attackTarget == AttackTarget.beeline) { break; } } break; case TargettingClass.support: EnemyTarget randomEnemy = SelectRandomSupportTarget(); newTargets.Add(randomEnemy.GetComponent <AttackReceiver>()); break; case TargettingClass.self: newTargets.Add(attackReceiver); break; //this case inherits "melee Target" from the TestAbility method. This is to reduce redundancy in finding available targets. case TargettingClass.melee: if (meleeTarget == null) { print("no melee targets, ATTACK FILTERING ERROR"); } newTargets.Add(meleeTarget.GetComponent <AttackReceiver>()); break; case TargettingClass.homing: Fighter randomActor = SelectRandomHomingTarget(); if (randomActor != null) { newTargets.Add(randomActor.GetComponent <AttackReceiver>()); } break; case TargettingClass.allAllies: foreach (Fighter fighter in allActors) { if (!fighter.isDead) { if (!fighter.isIntangible) { newTargets.Add(fighter.GetComponent <AttackReceiver>()); } } } break; case TargettingClass.allFoes: foreach (EnemyTarget target in allEnemies) { newTargets.Add(target.GetComponent <AttackReceiver>()); } break; default: print("no valid targeting class error."); break; } return(newTargets); }
//CC.AA public static int SortByY(Fighter actor1, Fighter actor2) { return(actor1.GetComponent <Mover>().GetGridPos().y.CompareTo(actor2.GetComponent <Mover>().GetGridPos().y)); }
//tests to see if ability can be used in given context private bool TestAbility(EnemyAttack selectedAbility) { if (selectedAbility.targettingClass == TargettingClass.melee) { Vector2Int[] directions = { Vector2Int.up, Vector2Int.down, Vector2Int.right, Vector2Int.left }; foreach (Fighter fighter in allActors) { foreach (Vector2Int direction in directions) { if (fighter.GetComponent <Mover>().GetGridPos() + direction == mover.GetGridPos()) { if (!fighter.isDead && !fighter.isIntangible) { meleeTarget = fighter; return(true); } } } } return(false); } if (selectedAbility.targettingClass == TargettingClass.support) { if (allEnemies.Length <= 1) { return(false); } } if (selectedAbility.usesRails) { if (selectedAbility.targettingClass == TargettingClass.global) { if (combatController.ListOfcells[selectedAbility.LandingCell].isOccupied) { return(false); } } if (selectedAbility.targettingClass == TargettingClass.relative) { Vector2Int[] targetCells = { selectedAbility.LandingCell }; if (combatController.ListOfcells[TranslateRelativeTargetCells(targetCells, enemyTarget)[0]].isOccupied) { return(false); } } } if (selectedAbility.RequiredCells.Length > 0) { bool matchFound = false; foreach (Vector2Int coord in selectedAbility.RequiredCells) { if (mover.GetGridPos() == coord) { matchFound = true; } } if (!matchFound) { return(false); } } if (selectedAbility.RequiredWing != Wing.none) { if (enemyTarget.wing != selectedAbility.RequiredWing) { return(false); } } return(true); }