/// <summary> /// Donne le coût en points de mouvements pour une cellule de terrain donnée. Les villes ne sont pas prises en compte. /// </summary> /// <param name="cell">cellule de terrain</param> /// <param param name="groupe">armée accompagnant cette créature pour les bonus de groupe</param> /// <returns>le coût en points de mouvements</returns> public int getMouvementCost(TerrainDescription.TerrainCell cell, Armee groupe) { // Les bateaux ne font QUE nager if ((cell.type != TerrainDescription.TypeTerrain.EAU) && nage && !description.heros) { return(MVTINFINI); } if (cell.route) { return(1); } switch (cell.type) { case TerrainDescription.TypeTerrain.COLLINE: return(description.bonusMouvement == CreatureDescription.BonusEnvironnement.COLLINES ? 3 : 5); case TerrainDescription.TypeTerrain.EAU: return(groupe.vol ? 3 : (groupe.nage ? ((description.bonusMouvement == CreatureDescription.BonusEnvironnement.EAU) ? 1 : 2) : MVTINFINI)); case TerrainDescription.TypeTerrain.FORET: return(description.bonusMouvement == CreatureDescription.BonusEnvironnement.FORÊT ? 3 : 5); case TerrainDescription.TypeTerrain.HERBE: return(description.bonusMouvement == CreatureDescription.BonusEnvironnement.HERBE ? 2 : 3); case TerrainDescription.TypeTerrain.MARECAGE: return(description.bonusMouvement == CreatureDescription.BonusEnvironnement.MARAIS ? 3 : 5); case TerrainDescription.TypeTerrain.MONTAGNE: return(groupe.vol ? 3 : MVTINFINI); } return(MVTINFINI); }
/// <summary> /// Simulation du combat jusqu'au bout, mais sans faire de mal aux armées en place /// </summary> /// <returns>true si l'attaquant gagne, false sinon</returns> public bool simulationCombat() { // Clone les armées Armee sovAtk = _attaque; Armee sovDef = _defense; _attaque = _attaque.Clone(); _defense = _defense.Clone(); bool res; do { do { res = unRound(false); } while (!roundSuivant(res)); if (!res) { break; } } while (armeeSuivante(true)); _attaque = sovAtk; _defense = sovDef; return(res); }
/// <summary> /// Calcule le bonus de défense /// </summary> /// <param name="crea">créature en combat</param> /// <param name="arme">groupe dont elle fait partie</param> /// <returns>bonus de force en défense</returns> private int calculBonusDefense(Creature crea, Armee arme) { int bonus = 0; // +1 par héros dans l'armée for (int i = 0; i < arme.getTaille(); i++) { Creature copain = arme.getCreature(i); if (copain.description.heros) { bonus++; } } if ((crea.description.bonusDefense == CreatureDescription.BonusUrbain.EXTERIEUR) && (!_dansVille)) { bonus += 2; } else if ((crea.description.bonusDefense == CreatureDescription.BonusUrbain.VILLE) && _dansVille) { // Augmente le bonus de défense de 2 bonus += 2; } // Si dans ville, bonus de la ville if (_dansVille) { bonus += _defenseVille; } // la taille compte bonus += (2 * arme.getTaille()) / 5; // Enfin la force de la créature... bonus += crea.description.force; return(bonus); }
// Ajoute une armée nouvellement créée public void addArmee(Armee armee) { // fusion des armées si une armée est déjà à cet emplacement foreach (Armee autre in _armees) { if (autre.positionCarte == armee.positionCarte) { // Fusionne les deux si c'est possible if (autre.getTaille() + armee.getTaille() > Armee.MAX_TAILLE) { Point pt = armee.getPositionLibre(armee.positionCarte, false, false).Value; armee.positionCarte = pt; // récursif addArmee(armee); return; } else { autre.ajouteTroupes(armee); } return; } } // Toute seule _armees.Add(armee); }
// retire une armée perdante public void removeArmee(Armee armee) { if (_armees.Contains(armee)) { _armees.Remove(armee); } }
/// <summary> /// Retourne ce sur quoi le curseur de souris a cliqué /// </summary> /// <param name="mouseX">position X du curseur</param> /// <param name="mouseY">position Y du curseur</param> /// <param name="armeeClick">si non null, l'armée cliquée</param> /// <param name="villeClick">si non null, la ville cliquée</param> /// <returns>la cellule du terrain cliqué</returns> public TerrainDescription.TerrainCell getClicked(int mouseX, int mouseY, ref Armee armeeClick, ref VilleDescription villeClick) { int carteX = (mouseX + _jeu.terrain.offsetCarte.X) / _jeu.blockSize; int carteY = (mouseY + _jeu.terrain.offsetCarte.Y) / _jeu.blockSize; armeeClick = null; villeClick = null; // Une armée se trouve ici ? foreach (Armee armee in _jeu.armees) { if (armee.positionCarte.X == carteX && armee.positionCarte.Y == carteY) { armeeClick = armee; break; } } // Une ville se trouve ici ? foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (carteX >= vd.positionMap.X && carteX <= (vd.positionMap.X + 1) && carteY >= vd.positionMap.Y && carteY <= (vd.positionMap.Y + 1)) { villeClick = vd; break; } } return(_jeu.terrain.terrainDesc.getCellAt(carteX, carteY)); }
/// <summary> /// Focus sur carte sans cliquer. Change le curseur de souris /// </summary> /// <param name="newMouseX">x souris</param> /// <param name="newMouseY">y souris</param> public void focusCarte(int mouseX, int mouseY) { // Seulement si pas modal & si pas click droit en cours Armee focusA = null; VilleDescription focusV = null; TerrainDescription.TerrainCell focusC = _jeu.infoCarte.getClicked(mouseX, mouseY, ref focusA, ref focusV); // Si sélection : peut etre l'épée pour attaquer unité ou ville if (_jeu.selectedArmee != null) { if (((focusA != null) && (focusA.faction != _jeu.tourFaction)) || ((focusV != null) && (focusV.faction != _jeu.tourFaction))) { _jeu.curseur.forme = Cursor.FormeCurseur.EPEE; } else { _jeu.curseur.forme = Cursor.FormeCurseur.FLECHE; } } // Sinon : peut être info ville si ville alliée else { if ((focusV != null) && (focusV.faction == _jeu.tourFaction)) { _jeu.curseur.forme = Cursor.FormeCurseur.INTERROGATION; } else { _jeu.curseur.forme = Cursor.FormeCurseur.FLECHE; } } }
/// <summary> /// L'armée attaque la ville /// </summary> /// <param name="armee">armée</param> /// <param name="v">ville</param> private void attaqueVille(Armee armee, VilleDescription vd) { _jeu.selectedArmee = armee; if (_jeu.interactionJoueur.attaqueVille(vd)) { // Si on a gagné, se déplace dans la ville si on a encore du mouvement armee.moveTarget = vd.positionMap; } }
/// <summary> /// Click gauche - point d'entrée /// </summary> /// <param name="mouseX"></param> /// <param name="mouseY"></param> /// <param name="released">true si cle bouton est relaché avant d'être cliqué</param> public void leftClick(int mouseX, int mouseY, bool released) { // Si une armée bouge, cliquer = arrêter le mouvement if (_jeu.selectedArmeeGO) { _jeu.selectedArmee.stop(); return; } // L'armée ne bouge pas // Détermine sur quoi on clique Armee clickA = null; VilleDescription clickV = null; TerrainDescription.TerrainCell clickC = _jeu.infoCarte.getClicked(mouseX, mouseY, ref clickA, ref clickV); int carteX = (mouseX + _jeu.terrain.offsetCarte.X) / _jeu.blockSize; int carteY = (mouseY + _jeu.terrain.offsetCarte.Y) / _jeu.blockSize; // Déclencheur de mvt : 2nd click if (released && relacheApresChgtCible) { relacheApresChgtCible = false; Point?target = _jeu.selectedArmee == null ? null : _jeu.selectedArmee.moveTarget; if (targetSet == target) { _jeu.selectedArmeeGO = true; } } // Sélection, ville ou mouvement. if (clickA != null) { //Click sur armée leftClickOnArmee(clickA, released); } else if (clickV != null) { // Click sur ville leftClickOnVille(new Point(carteX, carteY), clickV, released); } else { // Click sur terrain leftClickOnCell(new Point(carteX, carteY), released); } // Déclencheur de mvt : 1er click if (released && !relacheApresChgtCible) { Point?target = _jeu.selectedArmee == null ? null : _jeu.selectedArmee.moveTarget; if (target != null && target != targetSet) { relacheApresChgtCible = true; } targetSet = target; } }
/// <summary> /// Clone l'armée (uniquement les troupes, pas la trajectoire, et ne clone pas les créatures) /// </summary> /// <returns></returns> public Armee Clone() { Armee clone = new Armee(_jeu); foreach (Creature crea in _troupe) { clone.addCreature(crea); } return(clone); }
// Fusionne une armée avec this public void ajouteTroupes(Armee autre) { if ((autre.getTaille() + getTaille()) > MAX_TAILLE) { throw new SdGException("Bug : tentative de fusion d'armées volumineuses !"); } foreach (Creature crea in autre._troupe) { this.addCreature(crea); } }
/// <summary> /// Donne le coût en points de mouvements pour une cellule de terrain donnée /// </summary> /// <param name="target">cellule visée</param> /// <param param name="groupe">armée accompagnant cette créature pour les bonus de groupe</param> /// <returns>le coût en points de mouvements</returns> public int getMouvementCost(Point target, Armee groupe) { // Villes foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.contains(target)) { return((vd.faction != this.faction) ? MVTINFINI : 1); } } return(getMouvementCost(_jeu.terrain.terrainDesc.getCellAt(target.X, target.Y), groupe)); }
/// <summary> /// L'armée attaque l'armée ennemie /// </summary> /// <param name="armee">armée</param> /// <param name="cible">armée ennemie</param> private void attaqueArmee(Armee armee, Armee cible) { _jeu.selectedArmee = armee; List <Armee> cibles = new List <Armee>(); cibles.Add(cible); if (_jeu.interactionJoueur.attaqueArmee(cibles)) { // Si on a gagné, se déplace à la place de l'armée si on a encore du mouvement armee.moveTarget = cible.positionCarte; } }
/// <summary> /// Click gauche sur une armée /// </summary> /// <param name="clickA">l'armée</param> /// <param name="released">si on a clické ou relaché</param> private void leftClickOnArmee(Armee clickA, bool released) { // si aucune armée n'est sélectionnée et que c'est notre armée, on la sélectionne if ((_jeu.selectedArmee == null) && (clickA.faction == _jeu.tourFaction)) { _jeu.selectedArmee = clickA; } // si une armée est sélectionné et qu'on clique sur une armée amie, c'est un mouvement + merge // on calcul une nouvelle trajectoire else if ((_jeu.selectedArmee != null) && (clickA.faction == _jeu.tourFaction)) { setTarget(clickA.positionCarte); } // si une armée est sélectionné et qu'on clique sur une armée ennemie, c'est une attaque else if ((_jeu.selectedArmee != null) && (clickA.faction != _jeu.tourFaction)) { // est ce que l'armée fait partie d'une ville ? bool dansVille = false; foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.contains(clickA.positionCarte)) { // Attaque d'une ville si on est à coté Point v = vd.positionMap; Point a = _jeu.selectedArmee.positionCarte; if ((a.X >= (v.X - 1)) && (a.X <= (v.X + 2)) && (a.Y >= (v.Y - 1)) && (a.Y <= (v.Y + 2))) { // Oui ! A l'attaaaaaaaaaaaaaaaaaaaaaaaaque ! attaqueVille(vd); } dansVille = true; break; } } // Armée isolée if (!dansVille) { if ((Math.Abs(clickA.positionCarte.X - _jeu.selectedArmee.positionCarte.X) <= 1) && (Math.Abs(clickA.positionCarte.Y - _jeu.selectedArmee.positionCarte.Y) <= 1)) { //A l'attaaaaaaaaaaaaaaaaaaaaaaaaque ! attaqueArmee(new List <Armee> { clickA }); } } } }
/// <summary> /// Création d'un nouvel héros pour la faction courante /// </summary> /// <param name="nom">nom du héros</param> /// <param name="femme">true si femme</param> /// <param name="allies">true si on ajoute des alliés</param> public void createHeros(string nom, bool femme, bool allies) { // Choix de la ville List <VilleDescription> villesFaction = new List <VilleDescription>(); foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.faction == _jeu.tourFaction) { villesFaction.Add(vd); } } if (villesFaction.Count != 0) { VilleDescription vd = villesFaction[_jeu.rnd.Next(villesFaction.Count)]; int herosType = femme ? TYPE_HEROS : TYPE_HEROINE; Creature heros = new Creature(_jeu, herosType, vd.faction, vd.positionMap); heros.vraiNom = nom; // Possède un étendard heros.addItem(_jeu.items.itemDesc[Items.ETENDARD]); Armee armee = new Armee(_jeu); armee.addCreature(heros); // Alliés éventuels : types 19-27 int nbAllie = 0; if (allies) { int typeAllie = _jeu.rnd.Next(TYPE_ALLIEMAX + 1 - TYPE_ALLIEMIN) + TYPE_ALLIEMIN; nbAllie = _jeu.rnd.Next(3) + 1; for (int i = 0; i < nbAllie; i++) { armee.addCreature(new Creature(_jeu, typeAllie, vd.faction, vd.positionMap)); } } armee.positionCarte = armee.getPositionLibre(armee.positionCarte, false, false).Value; _jeu.addArmee(armee); if (allies) { _jeu.messageInfo = nom + " est accompagné" + (femme ? "e" : "") + " de " + nbAllie + " allié" + (nbAllie > 1 ? "s" : "") + " et se trouve à " + vd.nom; } else { _jeu.messageInfo = nom + " se trouve à " + vd.nom; } } }
/// <summary> /// Change de sélection pour la faction courante /// </summary> public void selectNext() { if ((_jeu.selectedArmee != null) && (_jeu.selectedArmeeGO)) { _jeu.selectedArmee.stop(); } // Construit la liste des armées de la faction List <Armee> armada = _jeu.factions.getArmada(_jeu.tourFaction); Armee nextArmee = _jeu.selectedArmee; if (armada.Count != 0) { int idx; if (nextArmee == null) { idx = 0; } else { idx = armada.IndexOf(nextArmee); } int compteur = 0; do { idx++; compteur++; if (idx >= armada.Count) { idx = 0; } nextArmee = armada[idx]; } while ((nextArmee.blackListed) && (compteur <= armada.Count)); if (compteur > armada.Count) { nextArmee = null; } // Focus _jeu.selectedArmee = nextArmee; if (_jeu.selectedArmee != null) { _jeu.terrain.zoomSur(_jeu.selectedArmee.positionEcran); } } }
/// <summary> /// Transition vers le round suivant : supprime l'armée perdante /// </summary> /// <param name="resultatRound">résultat du round précédent : true si l'attaquant gagne, false sinon</param> /// <returns>true si le combat est fini, false si des rounds supplémentaires sont nécessaires</returns> public bool roundSuivant(bool resultatRound) { Armee perdante = resultatRound ? _defense : _attaque; bool retVal; if (perdante.getTaille() == 1) { // Une armée a été décimée retVal = true; } else { perdante.removeCreature(perdante.getCreature(0)); retVal = false; } _bonusAttaque = calculBonusAttaque(_attaque.getCreature(0), _attaque); _bonusDefense = calculBonusDefense(_defense.getCreature(0), _defense); return(retVal); }
/// <summary> /// Trouve un point accessible pour l'armée près de la ville /// </summary> /// <param name="posVille">position de la ville souhaitée</param> /// <returns>le point cible ou null si pas trouvé</returns> private Point?getPointPresDeVille(Armee armee, Point posVille) { // Prend un point au hasard parmi les 12 points filtrés selon accessiblité List <Point> choix = new List <Point>(); for (int y = -1; y <= 2; y++) { for (int x = -1; x <= 2; x++) { // ne fait que les abords de la ville if (!((x >= 0) && (x <= 1) && (y >= 0) && (y <= 1))) { Point tente = new Point(posVille.X + x, posVille.Y + y); if (armee.getMouvementCost(tente) != Creature.MVTINFINI) { choix.Add(tente); } } } } // Ville inaccessible if (choix.Count == 0) { return(null); } else { // prend le point le plus proche au sens de la distance X/Y (pas forcément le plus proche mais bon...) int minDistance = Int32.MaxValue; int minIndice = 0; for (int i = 0; i < choix.Count; i++) { int d = Math.Max(Math.Abs(armee.positionCarte.X - choix[i].X), Math.Abs(armee.positionCarte.Y - choix[i].Y)); if (minDistance > d) { minDistance = d; minIndice = i; } } return(choix[minIndice]); } }
/// <summary> /// Production des villes /// </summary> public void productions() { foreach (VilleDescription vd in villeDesc) { if (vd.productionCourante != -1) { vd.productionPoints++; int coutPP = vd.geNbToursPourCreatures(_jeu.creatures.description[vd.typeCreatures[vd.productionCourante]].cout); if (vd.productionPoints >= coutPP) { vd.productionPoints -= coutPP; // Ajoute la créature Creature crea = new Creature(_jeu, vd.typeCreatures[vd.productionCourante], vd.faction, vd.positionMap); Armee armee = new Armee(_jeu); armee.addCreature(crea); _jeu.addArmee(armee); } } } }
/// <summary> /// Charge les infos de créatures et d'armées /// </summary> /// <param name="file">flux d'entrée</param> /// <returns>true si ok, false si ko</returns> internal bool load(System.IO.StreamReader file) { int armeesCount = int.Parse(file.ReadLine()); // rince toutes les armées... _jeu.removeAllArmee(); for (int i = 0; i < armeesCount; i++) { Armee arme = new Armee(_jeu); int faction = int.Parse(file.ReadLine()); Point posCarte = new Point(int.Parse(file.ReadLine()), int.Parse(file.ReadLine())); arme.positionEcran = new Point(int.Parse(file.ReadLine()), int.Parse(file.ReadLine())); bool hasTarget = bool.Parse(file.ReadLine()); arme.moveTarget = null; if (hasTarget) { arme.moveTarget = new Point(int.Parse(file.ReadLine()), int.Parse(file.ReadLine())); } int nbCreatures = int.Parse(file.ReadLine()); for (int j = 0; j < nbCreatures; j++) { Creature crea = new Creature(_jeu, int.Parse(file.ReadLine()), faction, posCarte); crea.vraiNom = file.ReadLine(); crea.cout = int.Parse(file.ReadLine()); crea.force = int.Parse(file.ReadLine()); crea.mouvement = int.Parse(file.ReadLine()); crea.mouvementCourant = int.Parse(file.ReadLine()); crea.nage = bool.Parse(file.ReadLine()); crea.vol = bool.Parse(file.ReadLine()); int nbItems = int.Parse(file.ReadLine()); for (int k = 0; k < nbItems; k++) { crea.addItemNoEffect(_jeu.items.itemDesc[int.Parse(file.ReadLine())]); // TODO n'applique pas les bonus } arme.addCreature(crea); } arme.blackListed = false; _jeu.addArmee(arme); } return(true); }
/// <summary> /// Combat jusqu'au bout, en mode non graphique /// l'armée perdante est retirée du jeu /// </summary> /// <returns>true si l'attaquant gagne, false sinon</returns> public bool combatAuto() { bool res = false; do { do { res = unRound(true); } while (!roundSuivant(res)); Armee perdante = res ? _defense : _attaque; _jeu.removeArmee(perdante); // Si l'attaquant a perdu, on arrête if (!res) { break; } } while (armeeSuivante(false)); return(res); }
/// <summary> /// L'armée doit rentrer dans la ville la plus proche /// </summary> /// <param name="armee"></param> private void choisitCibleVilleRefuge(Armee armee) { int minChemin = Int32.MaxValue; VilleDescription vdcible = null; foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.faction == _jeu.tourFaction) { Point cible = vd.positionMap; if (armee.positionCarte == cible) { minChemin = 0; vdcible = vd; break; } else { armee.moveTarget = cible; if ((armee.trajectoire != null) && (armee.trajectoire.chemin != null)) { int lenChem = armee.trajectoire.chemin.Count; if (lenChem != 0 && lenChem < minChemin) { minChemin = lenChem; vdcible = vd; } } } } } if (vdcible != null) { armee.moveTarget = vdcible.positionMap; } else { armee.moveTarget = null; } }
/// <summary> /// Transition vers la sélection de l'armée suivante /// </summary> /// <returns>false s'il n'y a plus d'armée à combattre</returns> public bool armeeSuivante(bool simulation) { _indexDefense++; if (_indexDefense < _garnison.Count) { if (simulation) { _defense = _garnison[_indexDefense].Clone(); } else { _defense = _garnison[_indexDefense]; } _defense.ordonnePourCombat(); _bonusDefense = calculBonusDefense(_defense.getCreature(0), _defense); return(true); } else { return(false); } }
/// <summary> /// Constructeur /// </summary> /// <param name="jeu">jeu</param> /// <param name="attaque">attaquant</param> /// <param name="garnison">défenseurs</param> public Combat(Jeu jeu, Armee attaque, List <Armee> garnison) { _jeu = jeu; _attaque = attaque; _garnison = garnison; _indexDefense = 0; _defense = garnison[0]; // Ordonne les armées dans l'ordre qui va bien (normalement inutile, mais bon) _attaque.ordonnePourCombat(); _defense.ordonnePourCombat(); // Détermine si l'armée de défense est dans une ville foreach (VilleDescription vd in jeu.villes.villeDesc) { if (vd.contains(_defense.positionCarte)) { _dansVille = true; _defenseVille = vd.niveauDefense; break; } } // Calcul du 1er bonus pour l'affichage _bonusAttaque = calculBonusAttaque(_attaque.getCreature(0), _attaque); _bonusDefense = calculBonusDefense(_defense.getCreature(0), _defense); }
// Constructeur public Jeu(GraphicsDeviceManager graphics, int lresX, int lresY) { graphics.PreferredBackBufferWidth = lresX; graphics.PreferredBackBufferHeight = lresY; _scaleX = lresX / 1920.0f; _scaleSpriteBatch = Matrix.CreateScale(_scaleX); _resX = 1920; _resY = (int)((float)lresY / _scaleX); _blockSize = BLOCK_SIZE; _curseur = new Cursor(); _overlays = new List <Overlay>(); _armees = new List <Armee>(); _selectedArmee = null; _selectedArmeeGO = false; _messageDebug = null; _noTour = 1; }
/// <summary> /// Déplacement des armées : met à jour vdcible avec la meilleure cible pour une armée & une ville choisie /// </summary> /// <param name="armee">armee</param> /// <param name="vd">ville</param> private void choisitCibleArmee(Armee armee, VilleDescription vd) { // Choisit la ville la plus proche et l'attaque si on peut gagner if (vd.faction != _jeu.tourFaction) { // Regarde d'abord si elle n'est pas trop loin... Taille max const int DISTANCE_MAX = 25; if (Math.Max(Math.Abs(vd.positionMap.X - armee.positionCarte.X), Math.Abs(vd.positionMap.Y - armee.positionCarte.Y)) < DISTANCE_MAX) { // Regarde d'abord si on gagnerait pour éviter de calculer des trajectoires pour rien // peut-on gagner le combat ? List <Armee> garnison = new List <Armee>(); foreach (Armee arme in _jeu.armees) { if (vd.contains(arme.positionCarte)) { garnison.Add(arme); } } bool gagne; if (garnison.Count != 0) { Combat combat = new Combat(_jeu, armee, garnison); gagne = combat.simulationCombat(); } else { gagne = true; } if (gagne) { // Accessible ? // choisit un point accessible près de la ville Point?cible = getPointPresDeVille(armee, vd.positionMap); if (cible != null) // sinon inaccessible // Déjà là ? { if (armee.positionCarte == cible) { minChemin = 0; vdcible = vd; } else { armee.moveTarget = cible; if ((armee.trajectoire != null) && (armee.trajectoire.chemin != null)) { int lenChem = armee.trajectoire.chemin.Count; if (lenChem != 0 && lenChem < minChemin) { if (minChemin > lenChem) { minChemin = lenChem; vdcible = vd; } } } } } } } } }
/// <summary> /// Déplacement des armées : met à jour vdcible avec la meilleure cible pour une armée & une armée ennemie choisie /// </summary> /// <param name="armee">armee</param> /// <param name="cible">armée ciblée</param> private void choisitCibleArmee(Armee armee, Armee cible) { // Choisit la ville la plus proche et l'attaque si on peut gagner if (cible.faction != _jeu.tourFaction) { // Regarde d'abord si elle n'est pas trop loin... Taille max const int DISTANCE_MAX = 25; if (Math.Max(Math.Abs(cible.positionCarte.X - armee.positionCarte.X), Math.Abs(cible.positionCarte.Y - armee.positionCarte.Y)) < DISTANCE_MAX) { // Regarde ensuite si elle est dans une ville, si oui on l'ignore car c'est pris en compte dans le choix des cibles villes bool dansVille = false; foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.contains(cible.positionCarte)) { dansVille = true; break; } } if (!dansVille) { // Regarde d'abord si on gagnerait pour éviter de calculer des trajectoires pour rien // peut-on gagner le combat ? bool gagne; List <Armee> garnison = new List <Armee>(); garnison.Add(cible); Combat combat = new Combat(_jeu, armee, garnison); gagne = combat.simulationCombat(); if (gagne) { // Accessible ? // choisit un point accessible près de la cible Point?pcible = getPointPresDeArmee(armee, cible.positionCarte); if (pcible != null) // sinon inaccessible // Déjà là ? { if (armee.positionCarte == pcible) { minCheminArmee = 0; armeeCible = cible; } else { armee.moveTarget = pcible; if ((armee.trajectoire != null) && (armee.trajectoire.chemin != null)) { int lenChem = armee.trajectoire.chemin.Count; if (lenChem != 0 && lenChem < minCheminArmee) { if (minCheminArmee > lenChem) { minCheminArmee = lenChem; armeeCible = cible; } } } } } } } } } }
public void cEstMonTour() { switch (this._etat) { case Etat.PHASE_INIT: idxChoixDest = 0; idxChoixDestVD = 0; minChemin = Int32.MaxValue; minCheminArmee = Int32.MaxValue; armeeCible = null; vdcible = null; armada = _jeu.factions.getArmada(_jeu.tourFaction); _etat = Etat.PHASE_CHOIX_DEST; break; case Etat.PHASE_CHOIX_DEST: // Itère plusieurs fois par update() sur cette phase for (int iter = 1; iter < 10; iter++) { // Passe en revue toutes les armées et choisit ce qu'il faut faire if (idxChoixDest < armada.Count) { // Pour toutes les armées de l'armada, regarde la ville la plus proche à attataquer if (idxChoixDestVD < _jeu.villes.villeDesc.Length) { choisitCibleArmee(armada[idxChoixDest], _jeu.villes.villeDesc[this.idxChoixDestVD++]); if (minChemin == 0) { // on ne peut pas faire mieux, on coupe court à la recherche idxChoixDestVD = _jeu.villes.villeDesc.Length; } } else { // Plus ville, Maintenant passe aux armées cibles if (idxChoixDestArmee < _jeu.armees.Count) { choisitCibleArmee(armada[idxChoixDest], _jeu.armees[idxChoixDestArmee++]); if (minCheminArmee == 0) { // On ne peut pas faire mieux, on coupe court à la recherche idxChoixDestArmee = _jeu.armees.Count; } } else { // Plus de ville, plus d'armées, regarde le plus proche si on a trouvé une ville avant de passer à l'armée à bouger suivante idxChoixDestVD = 0; idxChoixDestArmee = 0; // Choisit-on l'armée ou la ville ? if (minCheminArmee < minChemin) { // l'armée cible est plus proche vdcible = null; } else { // la ville cible est plus proche armeeCible = null; } if (armeeCible != null) { // La cible est une armée armada[idxChoixDest].realTarget = armeeCible.positionCarte; // Se déplace jusqu'à la position de la ville Point?target = getPointPresDeArmee(armada[idxChoixDest], armeeCible.positionCarte); // Si l'armée est inaccessible, rentre en ville ! if (target == null) { choisitCibleVilleRefuge(armada[idxChoixDest]); } else if (armada[idxChoixDest].moveTarget != target) { armada[idxChoixDest].moveTarget = target; } } else if (vdcible != null) { // La cible est une ville armada[idxChoixDest].realTarget = vdcible.positionMap; // Se déplace jusqu'à la position de la ville Point?target = getPointPresDeVille(armada[idxChoixDest], vdcible.positionMap); // Si la ville est inaccessible, rentre en ville ! if (target == null) { choisitCibleVilleRefuge(armada[idxChoixDest]); } else if (armada[idxChoixDest].moveTarget != target) { armada[idxChoixDest].moveTarget = target; } } else { // Pas de ville ni d'armée à attaquer, se retire // Trouve la ville amie la plus proche choisitCibleVilleRefuge(armada[idxChoixDest]); } // Passe à l'armée suivante minChemin = Int32.MaxValue; minCheminArmee = Int32.MaxValue; armeeCible = null; vdcible = null; idxChoixDest++; } } } else { _etat = Etat.PHASE_CHOIX_PRODUCTION; break; } } break; case Etat.PHASE_CHOIX_PRODUCTION: // Passe en revue toutes les villes et choisit ce qu'il faut construire foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.faction == _jeu.tourFaction) { choisirProduction(vd); } } _etat = Etat.PHASE_MOUVEMENT; _jeu.selectedArmee = null; _jeu.selectedArmeeGO = false; break; case Etat.PHASE_MOUVEMENT: case Etat.PHASE_MOUVEMENT_2: // Trouve la prochaine armée qui peut bouger if ((_jeu.selectedArmee != null) && !_jeu.selectedArmeeGO) { _jeu.selectedArmee = null; armada = _jeu.factions.getArmada(_jeu.tourFaction); } if ((_jeu.selectedArmee == null)) { foreach (Armee armee in armada) { //armee.reinitTrajectoire(); if (deplaceArmee(armee)) { _jeu.selectedArmee = armee; _jeu.selectedArmeeGO = true; break; } } // Si rien n'est sélectionné, phase d'après if (_jeu.selectedArmee == null) { if (_etat == Etat.PHASE_MOUVEMENT) { _etat = Etat.PHASE_ATTAQUE; } else { // Fini, fin du tour // reinit pour la suite _etat = Etat.PHASE_INIT; _jeu.finTour(); } idxChoixDest = 0; } } break; case Etat.PHASE_ATTAQUE: // Si un combat est en cours ; on continue; if (_jeu.getTopOverlay().modalOverlay != Overlays.Overlay.ModalOverlay.COMBAT) { armada = _jeu.factions.getArmada(_jeu.tourFaction); // Si on peut attaquer une ville, on le fait. if (idxChoixDest < armada.Count) { // Peut-on attaquer ? Point?vqm = armada[idxChoixDest].realTarget; if (vqm != null) { Point v = vqm.Value; Point a = armada[idxChoixDest].positionCarte; // Attaque de ville ou d'armée ? VilleDescription villeAttaquee = null; foreach (VilleDescription vd in _jeu.villes.villeDesc) { if (vd.positionMap == v) { villeAttaquee = vd; break; } } if (villeAttaquee != null) { if ((a.X >= (v.X - 1)) && (a.X <= (v.X + 2)) && (a.Y >= (v.Y - 1)) && (a.Y <= (v.Y + 2))) { // Oui ! A l'attaaaaaaaaaaaaaaaaaaaaaaaaque ! _jeu.terrain.zoomSur(armada[idxChoixDest].positionEcran); attaqueVille(armada[idxChoixDest], villeAttaquee); } } else { // Attaque d'armée ? foreach (Armee cible in _jeu.armees) { if (cible.positionCarte == v && cible.faction != _jeu.tourFaction) { // oui ! attaque l'armée ! _jeu.terrain.zoomSur(armada[idxChoixDest].positionEcran); attaqueArmee(armada[idxChoixDest], cible); break; } } } } idxChoixDest++; } else { // phase de mouvement suivante (jusque dans les villes prises) _etat = Etat.PHASE_MOUVEMENT_2; } } break; } }
/// <summary> /// Fouille une ruine /// </summary> /// <param name="heros">héros visiteur</param> /// <param name="ruine">ruine visitée</param> /// <param name="nomEnnemi">en sortie, le nom de l'ennemi rencontré</param> /// <param name="nomRecompense">en sortie (si vainqueur), le nom de la récompense</param> /// <returns>true si le héros gagne, false s'il meurt</returns> /// public bool fouilleRuine(Creature heros, RuineDescription ruine, ref string nomEnnemi, ref string nomRecompense) { // Détermine l'ennemi à combattre Creature ennemi; switch (_jeu.rnd.Next(3)) { case 0: ennemi = new Creature(_jeu, Creatures.TYPE_GRIFFON, 0, heros.positionCarte); nomEnnemi = "un griffon"; break; case 1: ennemi = new Creature(_jeu, Creatures.TYPE_GEANT, 0, heros.positionCarte); nomEnnemi = "un géant des montagnes"; break; default: ennemi = new Creature(_jeu, Creatures.TYPE_SORCIERE, 0, heros.positionCarte); nomEnnemi = "une sorcière"; break; } Armee aheros = new Armee(_jeu); aheros.addCreature(heros); Armee aennemi = new Armee(_jeu); aennemi.addCreature(ennemi); List <Armee> garnison = new List <Armee>(); garnison.Add(aennemi); Combat combat = new Combat(_jeu, aheros, garnison); bool herosGagne = combat.combatAuto(); // Détermine la récompense : item, troupe ou argent nomRecompense = ""; if (herosGagne) { ruine.visite = true; if (ruine.item != null) { nomRecompense = "l'objet : " + ruine.item.nom; heros.addItem(ruine.item); } else if (_jeu.rnd.Next(4) == 0) { int montant = _jeu.rnd.Next(1500) + 500; nomRecompense = montant + " pièces d'or"; _jeu.factions.getFaction(_jeu.tourFaction).or += montant; } else { // Alliés Armee allies = new Armee(_jeu); int typeAllie = _jeu.rnd.Next(Creatures.TYPE_ALLIEMAX + 1 - Creatures.TYPE_ALLIEMIN) + Creatures.TYPE_ALLIEMIN; int nbAllie = _jeu.rnd.Next(2) + 2; for (int i = 0; i < nbAllie; i++) { allies.addCreature(new Creature(_jeu, typeAllie, _jeu.tourFaction, heros.positionCarte)); } _jeu.addArmee(allies); nomRecompense = nbAllie + " alliés"; } } else { // Suppression du héros du jeu if (_jeu.selectedArmee.getTaille() == 1) { _jeu.removeArmee(_jeu.selectedArmee); _jeu.selectedArmee = null; } else { _jeu.selectedArmee.removeCreature(heros); } } return(herosGagne); }
/// <summary> /// Créer une pop up d'info sur click droit /// </summary> /// <param name="mouseX"></param> /// <param name="mouseY"></param> public void createInfoPopup(int mouseX, int mouseY) { // Détermine où on a cliqué : terrain, ville, armée... float extraHeight = 0; int extraWidth = 0; Armee armeeClick = null; VilleDescription villeClick = null; TerrainDescription.TerrainCell cellClick = getClicked(mouseX, mouseY, ref armeeClick, ref villeClick); string titre = "(bug)"; // Priorité aux armées if (armeeClick != null) { titre = armeeClick.proue.vraiNom + " (" + _jeu.factions.getFaction(armeeClick.faction).nom + ")"; extraHeight = Creatures.CREATURE_SIZE + PopWindow.MARGE_TITRE; extraWidth = Creatures.CREATURE_SIZE * Armee.MAX_TAILLE + PopWindow.MARGE_TITRE * 2; } // puis les villes else if (villeClick != null) { titre = villeClick.nom + " (" + _jeu.factions.getFaction(villeClick.faction).nom + ")"; extraHeight = -2.5f; extraWidth = 300; } // Enfin le terrain else { // Ruines if (cellClick.ruine) { int carteX = (mouseX + _jeu.terrain.offsetCarte.X) / _jeu.blockSize; int carteY = (mouseY + _jeu.terrain.offsetCarte.Y) / _jeu.blockSize; Ruines.RuineDescription desc = _jeu.ruines.ruines[new Point(carteX, carteY)]; titre = "Ruine de " + desc.nom + " (" + (desc.visite ? "déjà visité" : "non exploré") + ")"; } else if (cellClick.route) { titre = "Route - le chemin le plus rapide"; } else { switch (cellClick.type) { case TerrainDescription.TypeTerrain.COLLINE: titre = "Collines - difficile de les traverser"; break; case TerrainDescription.TypeTerrain.EAU: titre = "Eau - il vous faut ou voler, nager ou prendre un bateau"; break; case TerrainDescription.TypeTerrain.FORET: titre = "Forêt - difficile de la traverser"; break; case TerrainDescription.TypeTerrain.HERBE: titre = "Plaine - le terrain le plus rapide après la route"; break; case TerrainDescription.TypeTerrain.MARECAGE: titre = "Marécages - difficile de les traverser"; break; case TerrainDescription.TypeTerrain.MONTAGNE: titre = "Montagnes - A moins de les survoler, on ne peut les traverser"; break; } } } // Taille du texte Vector2 fontSize = _jeu.font.MeasureString(titre); Point taille = PopWindow.getPopWindowSize(_jeu, titre); // Ajoute un bord if (taille.X < extraWidth) { taille.X = extraWidth; } if (extraHeight < 0) { taille.Y = (int)((float)taille.Y * (-extraHeight)); } else { taille.Y = (int)((float)taille.Y + extraHeight); } PopWindow info = new PopWindow(_jeu, Overlay.Position.SOURIS, taille.X, taille.Y, mouseX, mouseY, titre); // Custom Draw pour afficher l'armée s'il le faut if (armeeClick != null) { info.drawCallBack = delegate(SpriteBatch spriteBatch, GraphicsDevice GraphicsDevice, GameTime gameTime) { int x = info.xoverlay + _jeu.terrain.offsetCarte.X + PopWindow.MARGE_TITRE / 2; int y = info.yoverlay + info.height - Creatures.CREATURE_SIZE - PopWindow.MARGE_TITRE / 2 + _jeu.terrain.offsetCarte.Y; for (int i = 0; i < armeeClick.getTaille(); i++) { Creature crea = armeeClick.getCreature(i); _jeu.creatures.draw(spriteBatch, GraphicsDevice, gameTime, x, y, 0f, crea.typeCreature); x += Creatures.CREATURE_SIZE; } }; } // Custom draw pour les villes else if (villeClick != null) { info.drawCallBack = delegate(SpriteBatch spriteBatch, GraphicsDevice GraphicsDevice, GameTime gameTime) { float x = info.xoverlay + PopWindow.MARGE_TITRE / 2; float y = info.yoverlay + PopWindow.MARGE_TITRE + fontSize.Y; spriteBatch.DrawString(_jeu.font, "Défense :" + villeClick.niveauDefense, new Vector2(x, y), Color.BlanchedAlmond); if (villeClick.capitaleFaction != 0) { y += fontSize.Y; spriteBatch.DrawString(_jeu.font, "Capitale de : " + _jeu.factions.getFaction(villeClick.capitaleFaction).nom, new Vector2(x, y), _jeu.factions.getFaction(villeClick.capitaleFaction).couleur); } }; } _jeu.addOverlay(info); _jeu.curseur.forme = Cursor.FormeCurseur.INTERROGATION; }