// The first fighter will always be the action character, and the second, the target character. public List <CharacterBehavior> SearchFighters(CharacterBehavior attacker, CharacterBehavior opponent) { List <CharacterBehavior> fighters = new List <CharacterBehavior>(); Queue <CharacterBehavior> queue = new Queue <CharacterBehavior>(); System.Action <CharacterBehavior> SelectFighter = (fighter) => { if (!fighters.Contains(fighter)) { fighters.Add(fighter); queue.Enqueue(fighter); } }; SelectFighter(attacker); SelectFighter(opponent); while (queue.Count > 0) { CharacterBehavior currentFighter = queue.Dequeue(); CaseBehavior currentCell = currentFighter.caseActuelle.GetComponent <CaseBehavior>(); // Propagate in all directions for (int dir = 0; dir < 4; ++dir) { if (!currentCell.debordement(dir) && currentCell.cheminDegage(currentCell.versDirection(dir))) { CaseBehavior nextCell = currentCell.getCaseVers(dir); if (nextCell.isCaseRevealed() && nextCell.cheminDegage(nextCell.versDirection(CaseBehavior.opposee(dir))) && nextCell.enemyFighterPresent(currentFighter.gameObject)) { if (nextCell.isNonWoundedEnemyPresent(currentFighter.gameObject)) { foreach (CharacterBehavior character in nextCell.characters) { SelectFighter(character); } } } } } } return(fighters); }
// Recherche A* iterative de ligne de vue List <CaseBehavior> getLineOfSight(CaseBehavior fromCell) { List <CaseBehavior> charactersOnSight = new List <CaseBehavior>(); // Propagate in all directions for (int dir = 0; dir < 4; ++dir) { CaseBehavior currentCell = fromCell; bool gotToSightLimit = false; while (!gotToSightLimit) { if (!currentCell.debordement(dir) && currentCell.cheminDegage(currentCell.versDirection(dir))) { CaseBehavior nextCell = currentCell.getCaseVers(dir); if (nextCell.isCaseRevealed() && nextCell.cheminDegage(nextCell.versDirection(CaseBehavior.opposee(dir)))) { if (nextCell.characters.Count > 0) { charactersOnSight.Add(nextCell); gotToSightLimit = true; } else { currentCell = nextCell; } } else { gotToSightLimit = true; } } else { gotToSightLimit = true; } } } return(charactersOnSight); }
// Recherche A* iterative de deplacement et saut void SearchPath(CaseBehavior startCell, int depth, bool jump) { Queue <CaseBehavior> queue = new Queue <CaseBehavior>(); RegisterAction(ActionType.WALK, startCell, 0); if (jump) { RegisterAction(ActionType.JUMP, startCell, 0); } if (depth > 0) { queue.Enqueue(startCell); } // Proof that this iterative BFS (Broad-First-Search) has no redundancy: // If we can only jump through a cell, there will be only one register of this cell. // If we can jump and move through the same cell (therefore as first move), then the code will discard the jump. // Since the priority increase with depth, no cell will be registered twice for move (due to register priority check) // As a conclusion: we guarantee no redundant check. while (queue.Count > 0) { CaseBehavior currentCell = queue.Dequeue(); int priority = GetActionPriority(ActionType.WALK, currentCell); // 0: init, depth: stop, MAX: JumpStart Debug.Assert(!currentCharacter.surLaRegletteAdverse(currentCell)); // Propagate in all directions for (int dir = 0; dir < 4; ++dir) { if (!currentCell.debordement(dir) && currentCell.cheminDegage(currentCell.versDirection(dir))) { CaseBehavior nextCell = currentCell.getCaseVers(dir); if (nextCell.isCaseRevealed() && nextCell.cheminDegage(nextCell.versDirection(CaseBehavior.opposee(dir))) && (currentCharacter is CB_Magicien || !nextCell.isNonWoundedEnemyPresent(currentCharacter.gameObject))) { // Si la case suivante est traversable et le mouvement precedent n'est pas un saut, enregistrer un mouvement. if (currentCharacter.canCrossCell(nextCell) && priority != MAX_PRIORITY) { if (priority + 1 == depth) { // Si ce n'est pas la case finale, on doit pouvoir terminer le mouvement sur cette case. // WARNING: le cas d'un couloir de plusieurs cases contenant plusieur cases non finales n'est pas pris en compte. // (possibilite d'effectuer un mouvement qui devra etre annule par la suite) if (currentCharacter.canStayOnCell(nextCell)) { RegisterAction(ActionType.WALK, nextCell, priority + 1, currentCell); } } else { // propage le mouvement si besoin. if (RegisterAction(ActionType.WALK, nextCell, priority + 1, currentCell) && !currentCharacter.surLaRegletteAdverse(nextCell)) { queue.Enqueue(nextCell); } } } // si le saut est permis et que c'est le premier mouvement, initier un saut else if (priority == 0 && jump) { if (RegisterAction(ActionType.JUMP, nextCell, 1, currentCell)) { queue.Enqueue(nextCell); } } // sinon si le mouvement precedent etait un saut, enregistrer la fin du saut si possible. else if (priority == MAX_PRIORITY && currentCharacter.canStayOnCell(nextCell)) { RegisterAction(ActionType.JUMP, nextCell, 2, currentCell); } } } } } }
// Vérifie l'ensemble des actions spéciales qui peuvent etre exécutées depuis la case actuelle vers la direction ciblée public void checkAdjacentCell(CaseBehavior currentCell, int dir) { if (!currentCell.debordement(dir)) { CaseBehavior nextCell = currentCell.getCaseVers(dir); if (!nextCell.isCaseRevealed()) { // Si une salle non ouverte est adjacente et accessible, en permettre l'ouverture if (currentCell.cheminDegage(currentCell.versDirection(dir))) { RegisterAction(ActionType.REVEAL, nextCell, 0); } } else { // Accès à la case pour vérifier que l'on peut s'y déplacer if (currentCell.cheminDegage(currentCell.versDirection(dir)) && nextCell.cheminDegage(nextCell.versDirection(CaseBehavior.opposee(dir)))) { // Regarder si un combat est possible if (nextCell.enemyFighterPresent(currentCharacter.gameObject)) { RegisterAction(ActionType.ATTACK, nextCell, 0); } if (currentCharacter is CB_Clerc) { // Regarder si un allie peut etre soigne if (nextCell.woundedCharacterReadyForHealing()) { RegisterAction(ActionType.HEAL, nextCell, 0); } } } // Si une herse non brisee relie cette case if (nextCell.herse != null && currentCell.herse == nextCell.herse && !nextCell.herse.GetComponent <HerseBehavior>().herseBrisee) { if (currentCharacter is CB_Guerrier) { RegisterAction(ActionType.DESTROYDOOR, nextCell, 0); } else if (currentCharacter is CB_Voleuse) { if (currentCell.herse.GetComponent <HerseBehavior>().herseOuverte) { RegisterAction(ActionType.CLOSEDOOR, nextCell, 0); } else { RegisterAction(ActionType.OPENDOOR, nextCell, 0); } } } } } if (currentCharacter is CB_PasseMuraille) { if (!currentCell.debordement(dir)) { // Peut franchir les murs adjacents CaseBehavior nextCell = currentCell.getCaseVers(dir); if (nextCell.isCaseRevealed()) { if (currentCell.versDirection(dir) == CaseBehavior.cheminCaseAdjacente.mur || nextCell.versDirection(CaseBehavior.opposee(dir)) == CaseBehavior.cheminCaseAdjacente.mur ) { if (currentCharacter.canStayOnCell(nextCell)) { RegisterAction(ActionType.WALLWALK, currentCell, 0); RegisterAction(ActionType.WALLWALK, nextCell, 1, currentCell); } } } } } }