#from __future__ import unicode_literals # -*- coding: utf-8 -*- from __future__ import division from time import time from PyQt4.QtCore import Qt, SIGNAL, QPointF, QString from PyQt4.QtGui import QGraphicsScene, QColor, QPixmap, QPainter, QIcon, \ QTableWidgetItem, QToolButton, QColorDialog, QMessageBox, \ QApplication, QGraphicsPolygonItem, QPen, QGraphicsView, QTableWidget, \ QLineEdit, QTextEdit, QSlider, QDoubleSpinBox import Actions from Cache import Cache from Case import Case from EcranAffichageTexte import EcranAffichageTexte from EcranCreerPlateau import EcranCreerPlateau from EcranGestionCombat import EcranGestionCombat import Modes from Pinceau import Pinceau from ProjectionDep import ProjectionDep from Terrain import Terrain from lib.Actions import choisirAttaqueZone from lib.EcranEditionMateriel import EcranEditionMateriel from lib.ListePions import ListePions from lib.commun import lstLibEtats from lib.dmF import contractTxt from lib.gC import GestionCombat from lib.gM import GestionMateriel from lib.geometrie import Geometrie from lib.mat import Materiel, chargerMat import regles as regles class Plateau(QGraphicsScene, Materiel): """plateau de jeu contenant les cases, decors et pions""" def __init__(self, fenetre, parent=None): super(Plateau, self).__init__() #parametres et variables self._type = "pl" self.fenetre = fenetre ##partie et infos plateau self.chapitre = 0 self.creePar = "" self.enCours = False self.public = False self.dateCreation = "" self.dateSvg = "" self.notes = "" self.presentation = "" #carac self.nbCasesX = 0 self.nbCasesY = 0 self.hCase = 0 self.couleurInit = QColor(0, 255, 0, 80) self.zP = None #plafond self._compteurPile = 0 #compteur d'empilement, pour gerer l'ordre de recreation des pions #objets self.pinceau = Pinceau(self) self.gM = GestionMateriel() self.gC = GestionCombat() self.geo = Geometrie() self.cases = {} #dict des cases du plateau (coordonnées: case) self.pions = ListePions() self.caches = {} self.listeCasesZonePlacement = [] self.polygoneZonePlacement = None self.entreesSorties = [] #infos combat self.numCombattantEnCours = 0 self.ordreJeu = {} #numero du pion: ordre de jeu def estCreateur(self): """retourne vrai si l'utilisateur en cours est le createur du plateau""" return (self.fenetre.util == self.creePar) def __getstate__(self): self.dateSvg = time() state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", \ "editionTerrain", "editionCreature", "editionDecor", \ "polygoneZonePlacement", "gestionCombat", \ "editionAttaques", "pinceau"]} return (state) def __setstate__(self, state): self.__dict__ = state def vue(self): return self.fenetre.ui.cbt_vue def combattants(self): return self.pions.combattants() def combattantsVisibles(self): return self.pions.combattantsVisibles() def decors(self): return self.pions.combattants() def creer(self): """cree le plateau""" self.dateCreation = time() self.creePar = self.fenetre.profil.pseudo() self.hCase = 120 #hauteur d'une case self.modeActif = Modes.ModeBase(self) self.gestionCombat = None self.initialisationGraphique() self.connexions() #cree les cases hexagonales for x, y in self.geo.listeCases(): c = Case(self) c.creer(x, y, self.couleurInit) self.cases[(x, y)] = c self.plateauModeCreation() def incrementerPile(self): self._compteurPile += 1 return self._compteurPile def recreer(self, fenetre): self.fenetre = fenetre self.gestionCombat = None super(Plateau, self).__init__() self.modeActif = Modes.ModeBase(self) self.connexions() self.initialisationGraphique() #recreation des cases for coord in self.cases: self.cases[coord].recreer(self) #recreation des caches for idCache in self.caches: self.caches[idCache].ajouter(self) self.majCaches() #recreation des pions #on recree les pions par ordre d'empilement (du bas vers le haut) ordre = [pion for pion in self.pions.pions().values()] ordre.sort(key=lambda x: x.posPile) for pion in ordre: pion.ajouterAuPlateau(self) self.gC.reinitialiser() #recreation des marqueurs entree/sortie for entreeSortie in self.entreesSorties: entreeSortie.recreer(self) #recreation de la zone de placement: if len(self.listeCasesZonePlacement) > 0: self.polygoneZonePlacement = None self.majZonePlacement(self.listeCasesZonePlacement) if self.public: self.plateauModeCombat() else: self.plateauModeCreation() def fermer(self): """ferme le plateau 'proprement'""" self.miniature() self.pinceau = None for item in self.items(): item.prepareGeometryChange() self.removeItem(item) if self.gestionCombat != None: del self.gestionCombat self.reinitialiserPanneaux() def reinitialiserPanneaux(self): """remet a neuf les commandes liees au plateau""" for panneau in [self.fenetre.ui.cbt_panneauHaut, \ self.fenetre.ui.cbt_panneauBas, \ self.fenetre.ui.cbt_panneauGauche, \ self.fenetre.ui.cbt_panneauDroite]: #listes for liste in panneau.findChildren(QTableWidget): while liste.rowCount() > 0: liste.removeRow(0) #textes for texte in panneau.findChildren(QLineEdit): texte.clear() for texte in panneau.findChildren(QTextEdit): texte.clear() #a cocher for bouton in panneau.findChildren(QToolButton): if bouton.isCheckable(): bouton.setChecked(False) #autre for item in panneau.findChildren(QSlider): item.setValue(1) for item in panneau.findChildren(QDoubleSpinBox): item.setValue(0) def miniature(self): """renvoie une miniature du plateau (QPixMap compresse) qui sera enregistree avec les infos de la sauvegarde""" ## img = QImage(128, 128, QImage.Format_ARGB32_Premultiplied) img = QPixmap(1024, 768) img.fill(QColor("white")) peintre = QPainter(img) self.render(peintre) peintre.end() img.scaledToHeight(128, Qt.FastTransformation) def connexions(self): """connecte le plateau aux differents widgets de la fenetre principale""" #modes d'interaction self.fenetre.connect(self.fenetre.ui.cbt_modeCreation, SIGNAL("clicked()"), self.plateauModeCreation, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cbt_modeCombat, SIGNAL("clicked()"), self.plateauModeCombat, Qt.UniqueConnection) #etapes du combat self.fenetre.connect(self.fenetre.ui.cbt_etapeSuivante, SIGNAL("clicked()"), self.etapeSuivante, Qt.UniqueConnection) self.connect(self.fenetre.ui.pc_listePJ, SIGNAL("cellClicked(int, int)"), self.ajouterPj) #affichage de fenetres self.fenetre.connect(self.fenetre.ui.cbt_nom, SIGNAL("clicked()"), self.afficherEcranPlateau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cbt_afficherGestion, SIGNAL("clicked()"), self.afficheEcranGestionCombat, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_dialogueCouleurs, SIGNAL("clicked()"), self.modePeintureCase, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_afficherNotes, SIGNAL("clicked()"), self.agrandirNotesMjPlateau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.pi_fiche, SIGNAL("clicked()"), self.afficherFichePion, Qt.UniqueConnection) #listes self.fenetre.connect(self.fenetre.ui.cp_listeTerrains, SIGNAL("cellClicked(int,int)"), self.modeMajTerrainCase, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_listeCreatures, SIGNAL("cellClicked(int,int)"), self.modeCreationCombattant, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_listeDecors, SIGNAL("cellClicked(int,int)"), self.modeCreationDecor, Qt.UniqueConnection) #creation self.fenetre.connect(self.fenetre.ui.cp_epaisseurPinceau, SIGNAL("valueChanged(int)"), self.majEpaisseurPinceau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_pipetteCouleur, SIGNAL("clicked()"), self.modeCopieTerrain, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_effets, SIGNAL("activated(int)"), self.modeCaseEffet, Qt.UniqueConnection) #autres: self.fenetre.connect(self.fenetre.ui.cp_gomme, SIGNAL("clicked()"), self.majModeSupprimerPions, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_placerEntree, SIGNAL("clicked()"), self.majModeDefinirEntree, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_placerCache, SIGNAL("clicked()"), self.majModePlacerCache, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_placerSortie, SIGNAL("clicked()"), self.majModeDefinirSortie, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_defPlacement, SIGNAL("clicked()"), self.majModeZonePlacement, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.pi_notes, SIGNAL("textChanged()"), self.majNotesCombattant, Qt.UniqueConnection) #formes (dessin) self.fenetre.connect(self.fenetre.ui.cp_formeSimple, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_formeLigne, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_formeLigneOrientee, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_formePot, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_formeRectVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.act_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.act_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.act_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.act_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection) # self.fenetre.connect(self.fenetre.ui.pi_formeAttaqueZone, SIGNAL("activated (int)"), self.majModeCombatZone, Qt.UniqueConnection) # self.fenetre.connect(self.fenetre.ui.pi_rayonAttaqueZone, SIGNAL("valueChanged(int)"), self.majRayonZone, Qt.UniqueConnection) def initialisationGraphique(self): """cree la scene graphique et les parametres necessaires a son fonctionnement, et met a jour l'interface""" #on cree la scene graphique kx = 1 if self.formeCases == "H": kx = 0.866 marge = 240 self.setSceneRect(0 - marge, 0 - marge, (kx*self.hCase*(self.nbCasesX+2)) + marge, (self.hCase*(self.nbCasesY+2)) + marge) self.vue().setScene(self) self.vue().scale(0.25, 0.25) self.vue().centerOn(QPointF(0,0)) self.vue().setDragMode(1) self.setItemIndexMethod(QGraphicsScene.BspTreeIndex) self.polygoneZonePlacement = None #gestion du mode d'interaction avec le plateau self.pions.initialiser(self) self.pinceau = Pinceau(self) self.proj = ProjectionDep(self) #mise a jour de l'interface de creation self.majNomPlateau() self.majBoutonsCouleursPerso() self.gM.initialiser(self.fenetre) self.gC.initialiser(self) self.geo.initialiser(self) self.initListeAttaques() self.majBoutonEtape() self.fenetre.ui.act_deplacement.setCheckable(True) self.fenetre.ui.act_attaqueCac.setCheckable(True) self.fenetre.ui.act_attaqueDist.setCheckable(True) # self.fenetre.ui.act_attaqueZone.setCheckable(True) #mise a jour de l'interface d'informations self.majInfoCb(None) self.majInfoDc(None) def estCree(self): """renvoie vrai si des cases ont ete creees""" return (len(self.cases) > 0) def afficherEcranPlateau(self): """affiche la fenetre de description du plateau""" ecran = EcranCreerPlateau() ecran.afficher(self) r = ecran.exec_() if r == 1: res = ecran.resultat() self.majNom(res.nom()) self.chapitre = res.chapitre self.description = res.description self.presentation = res.presentation self.majNomPlateau() def majNomPlateau(self): """met a jour l'affichage du nom du plateau""" txt = self.nom() if not self.public: txt += " [Non Publié]" self.fenetre.ui.cbt_nom.setText(QString().fromUtf8(" {} ".format(txt))) def majBoutonEtape(self): """met a jour le label et l'effet du bouton d'etape (en bas a droite)""" if not self.public: self.fenetre.ui.cbt_etapeSuivante.setText(QString().fromUtf8("Publier le plateau")) return if not self.gC.tour() > 0: self.fenetre.ui.cbt_etapeSuivante.setText(QString().fromUtf8("Démarrer le combat")) return self.fenetre.ui.cbt_etapeSuivante.setText(QString().fromUtf8("Tour {}\nFinir son tour".format(self.gC.tour()))) def etapeSuivante(self): """apres clic sur le bouton d'etape, on passe a l'etape suivante (publication, demarrage du combat...)""" if not self.public: self.publier() return self.gC.pionSuivant() def publier(self): self.public = True self.majListePJ() self.majBoutonEtape() def majListePJ(self): """met a jour la liste des pj qui peuvent etre ajoutes au plateau""" self.fenetre.ui.pc_listePJ.setColumnWidth(0,0) self.fenetre.ui.pc_listePJ.vider() dejaCrees = [] for numPj in self.pions.pjs(): dejaCrees.append(self.pions[numPj].idM()) for idM in self.fenetre.pjs: if not idM in dejaCrees: pj = chargerMat(idM, "grp") ligne = self.fenetre.ui.pc_listePJ.nouvelleLigneFin() self.fenetre.ui.pc_listePJ.majTexte(ligne, 0, idM) self.fenetre.ui.pc_listePJ.setItem(ligne, 1, QTableWidgetItem(QIcon(pj.icone().pix()), \ QString(pj.nom()))) self.fenetre.ui.pc_listePJ.setVisible((self.fenetre.ui.pc_listePJ.rowCount() > 0)) def ajouterPj(self, ligne, col): idM = self.fenetre.ui.pc_listePJ.texte(ligne, 0) pj = chargerMat(idM, "grp") if pj: self.activerMode(Modes.CreationPion, pj) def couleursRapides(self): return [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \ (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \ (255,255,127), (240,80,0), (85,170,255), (85,85,255), (85,0,255), (0,255,255)] def majBoutonsCouleursPerso(self): """met a jour l'affichage des couleurs customisees dans la boite de dialogue de selection de couleur""" for i in range(0,18): couleur = QColor() r, g, b = self.couleursRapides()[i] couleur.setRgb(r, g, b) bouton = self.fenetre.ui.cp_boiteCouleurs.findChild(QToolButton, "cp_couleur{}".format(i+1)) if couleur.isValid(): bouton.setStyleSheet("QToolButton {backGround:%s}"%(couleur.name())) self.fenetre.connect(bouton, SIGNAL("clicked()"), self.modePeintureCase_perso) def chercherCouleur(self): """ouvre la boite de dialogue de selection de couleur""" couleur = QColorDialog(self.vue()).getColor(QColor("white"), self.vue()) return couleur def majListesPions(self, numCombattant = None): """met a jour les listes contenant des donnees liees aux pions""" ## self.majListeOrdreJeu() ## ## if numCombattant == None or numCombattant == self.pionSelectionne().numero: ## self.majListeAttributs() ## QApplication.processEvents() pass # def ajouterPj(self): # """affiche la fenetre de selection des pj, et recupere l'eventuel pj selectionne""" # self.ecranSelPj = EcranSelectionPj(self.fenetre) # self.ecranSelPj.setAttribute(Qt.WA_DeleteOnClose) # listePj = chargerUnique("parties\\{}\\groupe".format(self.fenetre.partie)) # self.ecranSelPj.charger(listePj) # r = self.ecranSelPj.exec_() # if r == 1: # idPj = int(self.ecranSelPj.selection()) # if idPj != None: # pj = listePj[idPj] # self.activerMode(Modes.CreationPion, pj) # self.ecranSelPj = None def agrandirNotesMjPlateau(self): """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies""" affichageTexte = EcranAffichageTexte(self.notes) affichageTexte.exec_() self.notes = affichageTexte.recupererTexte() del affichageTexte ############### affichage des caches enregistres def majCaches(self): """charge la liste des caches avec les donnees en memoire""" traite = [] for idCache in self.caches: for coord in self.caches[idCache].listeCases(): if not coord in traite: self.cases[coord].majCache() traite.append(coord) #### affichage de la fiche du perso ou du decor def afficherFichePion(self): if self.pionSelectionne(): fen = EcranEditionMateriel(self.pionSelectionne()) fen.afficher() fen.exec_() ############### maj des infos du panneau Pi a la selection/deselection d'un pion #voir a balancer tout ca dans une classe a part def majPanneauPi(self): return if self.pionSelectionne(): estCombattant = (self.pionSelectionne().numero > 0) #affichage # self.fenetre.ui.pi_actions.setEnabled(estCombattant) self.fenetre.ui.pi_ongletsListes.setTabEnabled(0, estCombattant) self.fenetre.ui.pi_ongletsListes.setTabEnabled(1, estCombattant) ### maj la selection dans la liste d'ordre de jeu if estCombattant: for i in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()): if str(self.fenetre.ui.inf_listeOrdreJeu.item(i, 0).text().toUtf8()) == str(self.pionSelectionne().numero): self.fenetre.ui.inf_listeOrdreJeu.setCurrentCell(i,0) ### maj de la liste des attributs if estCombattant: self.fenetre.ui.pi_listeAttributs.setColumnWidth(0, 50) self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee) #on vide la liste while self.fenetre.ui.pi_listeAttributs.rowCount() > 0: self.fenetre.ui.pi_listeAttributs.removeRow(0) #creation des lignes de base lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans listeAttributCelluleModifiee for i in range(0, 10): #10 premieres colonnes reservees pour les infos de base self.fenetre.ui.pi_listeAttributs.insertRow(i) item = QTableWidgetItem() if i < len(lignesBase): item.setText(QString.fromUtf8(lignesBase[i])) item.setFlags(Qt.NoItemFlags) self.fenetre.ui.pi_listeAttributs.setItem(i, 0, item) self.fenetre.ui.pi_listeAttributs.setRowHidden(i, (i >= len(lignesBase))) #maj des donnees de base self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom())))) self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat)))) self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().zR)))) #attributs issus des regles utilisees ordre = regles.ordreAttributs() for elt in ordre: ligne = 10 + ordre.index(elt) self.fenetre.ui.pi_listeAttributs.insertRow(ligne) item = QTableWidgetItem(QString.fromUtf8(elt)) item.setFlags(Qt.NoItemFlags) self.fenetre.ui.pi_listeAttributs.setItem(ligne, 0, item) self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[elt])))) self.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee) ###affiche les notes du combattant self.fenetre.ui.pi_notes.majTexte(self.pionSelectionne().notes) ###maj la liste des attaques du pion if estCombattant: #on vide la liste while self.fenetre.ui.pi_listeAttaques.rowCount() > 0: self.fenetre.ui.pi_listeAttaques.removeRow(0) i = 0 for attaque in self.pionSelectionne().attaques: self.fenetre.ui.pi_listeAttaques.insertRow(i) self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque))))) icone = None if attaque.typ == "cac": icone = QIcon(":/interface/16/ressource/epee_16.png") if attaque.typ == "dist": icone = QIcon(":/interface/16/ressource/arc_16.png") if attaque.typ == "zone": icone = QIcon(":/interface/16/ressource/baguette_16.png") if icone != None: self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8(""))) self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom))) else: #maj des infos dans le panneau pi #vide la liste des attributs self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee) while self.fenetre.ui.pi_listeAttributs.rowCount() > 0: self.fenetre.ui.pi_listeAttributs.removeRow(0) #vide la liste des attaques du pion while self.fenetre.ui.pi_listeAttaques.rowCount() > 0: self.fenetre.ui.pi_listeAttaques.removeRow(0) self.majInfosAttaqueEC() ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres ####### def majArborescenceModes(self): self.fenetre.ui.cbt_arbo.majTexte(self.modeActif.arborescence()) def plateauModeCreation(self): self.activerMode(Modes.StandardCp) def plateauModeCombat(self): self.activerMode(Modes.StandardPi) def activerMode(self, mode, param = None): """desactive le mode actif et active le nouveau a la place""" self.modeActif.desactiver() self.modeActif = mode(self) self.modeActif.activer(param) self.majArborescenceModes() def modePeintureCase(self): """enclenche le mode peinture de case a partir de la couleur selectionnee""" couleur = self.chercherCouleur() if couleur.isValid(): terrain = Terrain() terrain.couleur = couleur self.activerMode(Modes.MajCases, terrain) else: self.activerMode(Modes.StandardCp) def modePeintureCase_perso(self): origine = self.sender().objectName() index = int(origine.replace("cp_couleur",""))-1 couleur = QColor() r, g, b = self.couleursRapides()[index] couleur.setRgb(r, g, b) if couleur.isValid(): terrain = Terrain() terrain.couleur = couleur self.activerMode(Modes.MajCases, terrain) else: self.activerMode(Modes.StandardCp) def modeCopieTerrain(self): """enclenche le mode copie de case""" self.activerMode(Modes.Pipette) def modeCaseEffet(self, index): """enclenche le mode de mise a jour de l'effet actif des cases""" effets = ["brule", "eau", "glace", "poison", "aucun"] self.activerMode(Modes.MajCasesEffet, effets[index]) def modeCreationPion(self): """enclenche le mode de creation de pions simples""" self.majMode("pionCreation") def majModeSupprimerPions(self): """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)""" self.activerMode(Modes.SuppressionPion) def modeCreationDecor(self, ligne, col): """enclenche le mode de creation de decors depuis la liste des decors""" decor = chargerMat(self.fenetre.ui.cp_listeDecors.selection()) self.activerMode(Modes.CreationPion, decor) def modeCreationCombattant(self, ligne, col): """enclenche le mode de creation de pions depuis la liste des creatures""" creature = chargerMat(self.fenetre.ui.cp_listeCreatures.selection()) self.activerMode(Modes.CreationPion, creature) def modeMajTerrainCase(self, ligne, col): """enclenche le mode permettant la mise a jour du terrain des cases""" terrain = chargerMat(self.fenetre.ui.cp_listeTerrains.selection()) if terrain: self.activerMode(Modes.MajCases, terrain) else: print "terrain invalide" def majEpaisseurPinceau(self, epaisseur): """met a jour l'epaisseur du pinceau (en cases)""" self.fenetre.ui.cp_valeurEpaisseurPinceau.majTexte(str(epaisseur)) self.pinceau.majEpaisseur(int(epaisseur)) def majModeForme(self): """met a jour la forme utilisee pour la peinture""" formes = {"cp_formeSimple": "simple", \ "cp_formeLigne": "ligne", \ "cp_formeLigneOrientee": "frontiere", \ "cp_formePot": "pot", \ "cp_formeEllipseVide": "ellipseV", \ "cp_formeEllipsePlein": "ellipseP", \ "cp_formeRectVide": "rectV", \ "cp_formeRectPlein": "rectP"} self.pinceau.majForme(formes[str(self.sender().objectName())]) def majModePlacerCache(self): """active le mode de creation des caches""" if self.public: dial = QMessageBox() dial.setText(QString().fromUtf8("Vous ne pouvez pas placer de caches une fois le plateau publié")) dial.exec_() return self.activerMode(Modes.PlacerCaches) def majModeCombatDeplacement(self): """active le mode de combat 'deplacement' (mode standard)""" self.modeActif.nouvelleAction(Actions.Deplacement) def majModeCombatAttaqueCaC(self): """active le mode de combat 'corps-a-corps'""" self.modeActif.nouvelleAction(Actions.Cac) def majModeCombatAttaqueDist(self): """active le mode de combat 'attaque a distance'""" self.modeActif.nouvelleAction(Actions.Distance) def majModeCombatZone(self): action = choisirAttaqueZone() self.modeActif.nouvelleAction(action) # def majModeCombatLigne(self): # self.modeActif.nouvelleAction(Actions.Ligne) # # def majModeCombatDisque(self): # self.modeActif.nouvelleAction(Actions.Disque) # # def majModeCombatCone(self): # self.modeActif.nouvelleAction(Actions.Cone) def majModeDefinirEntree(self): self.activerMode(Modes.CreationEntreeSortie, "E") def majModeDefinirSortie(self): self.activerMode(Modes.CreationEntreeSortie, "S") def majModeZonePlacement(self): self.activerMode(Modes.ZonePlacement) ############### ########## Gestion du combat ############## def afficheEcranGestionCombat(self): """affiche l'ecran de gestion du combat""" self.gestionCombat = EcranGestionCombat(self) self.gestionCombat.show() self.connect(self.fenetre, SIGNAL("majListesPions"), self.majListesPions) self.connect(self.gestionCombat, SIGNAL("majListesPions"), self.majListesPions) QApplication.processEvents() ## r = self.gestionCombat.exec_() # def majAffichageTour(self): # """met a jour l'affichage du tour en cours""" # self.fenetre.ui.cbt_tour.majTexte("Tour: {}".format(self.tour)) # # def initListeOrdreJeu(self): # """cree les colonnes et met en forme la table ordre jeu""" # self.fenetre.ui.inf_listeOrdreJeu.setColumnWidth(2, 30) # self.fenetre.ui.inf_listeOrdreJeu.hideColumn(0) # self.fenetre.ui.inf_listeOrdreJeu.hideColumn(2) # self.fenetre.ui.inf_listeOrdreJeu.setIconSize(QSize(30,20)) # # def majListeOrdreJeu(self): # """met a jour la liste des pions infoOrdreJeu""" # while self.fenetre.ui.inf_listeOrdreJeu.rowCount() > 0: # self.fenetre.ui.inf_listeOrdreJeu.removeRow(0) # index = 0 # for num in self.ordreJeu: # self.fenetre.ui.inf_listeOrdreJeu.insertRow(int(index)) # self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 0, QTableWidgetItem(QString.fromUtf8(str(num)))) # icon = QIcon(self.combattants[num].icone().fichier()) # item = QTableWidgetItem(icon, QString.fromUtf8(self.combattants[num].txtId())) # self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 1, item) # self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 2, QTableWidgetItem(QString.fromUtf8(str(self.ordreJeu[num])))) # index += 1 # # self.fenetre.ui.inf_listeOrdreJeu.sizeHintForColumn(1) # ## trierTable(self.fenetre.ui.infoOrdreJeu, 2, 0) # # def clicListOrdreJeu(self, ligne, col): # """on a clique dans la liste d'ordre de jeu, le pion correspondant est selectionne et centre sur la carte""" # numCombattant = int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8()) # self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique) # self.modeActif.clic_combattant(numCombattant) # # def pionSuivant(self): # """selection du pion suivant dans la liste d'ordre de jeu""" # if not len(self.combattants) > 0: return # # if self.numPionEnCours in self.combattants: # suivant = self.ordreJeu[self.numPionEnCours] + 1 # else: # suivant = 1 # if suivant > len(self.ordreJeu): # self.tour += 1 # self.majAffichageTour() # suivant = 1 # for num in self.ordreJeu: # if self.ordreJeu[num] == suivant: # numCombattant = num # break # # for ligne in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()): # item = self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0) # item.setSelected(int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8()) == numCombattant) # if int(item.text().toUtf8()) == numCombattant: # self.fenetre.ui.inf_listeOrdreJeu.scrollToItem(item) # # self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique) # self.pionSaisir(numCombattant) # # # def majOrdreJeu(self): # """met a jour l'ordre de jeu des pions en fonction de l'attribut prevu par les regles s'il existe, # ou en fonction de l'ordre de jeu parametre sinon""" # if len(self.ordreJeu) > 0: # attribut = regles.attributOrdreJeu() # if attribut != None: # dico = {} # for numCombattant in self.combattants: # dico[numCombattant] = int(self.combattants[numCombattant].listeAttributs[attribut]) # ordre = sorted(dico, key = dico.get, reverse=(regles.sensTriOrdreJeu() == 1)) # self.ordreJeu = {} # for numCombattant in self.combattants: # self.ordreJeu[numCombattant] = ordre.index(numCombattant) + 1 # self.majListeOrdreJeu() # # def pionDeplacerDansOrdreJeu(self, numCombattant, nouvellePosition): # """deplace un pion dans le dictionnaire gerant l'ordre de jeu de maniere a assurer sa coherence # nouvellePosition = 0 supprime le pion de la liste""" # if numCombattant in self.ordreJeu: # if nouvellePosition == 0: # del self.ordreJeu[numCombattant] # if len(self.ordreJeu) > 0: # i = 0 # tmp = sorted(self.ordreJeu, key=self.ordreJeu.get) # if numCombattant in tmp: # tmp.remove(numCombattant) # for num in tmp: # i += 1 # if i == nouvellePosition: # self.ordreJeu[numCombattant] = i # i += 1 # self.ordreJeu[num] = i # if i < nouvellePosition: # self.ordreJeu[numCombattant] = i + 1 # elif nouvellePosition > 0: # self.ordreJeu[numCombattant] = 1 # self.majOrdreJeu() def listeAttributCelluleModifiee(self, ligne, colonne): """une cellule de la liste des attributs a ete modifiee""" return if colonne != 1: print("valeur non modifiable") else: #on verifie la validite de la donnee entree lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans majListeAttribut if ligne < len(lignesBase): pass elif ligne >= 10: attribut = regles.ordreAttributs()[(ligne - 10)] nouvelleVal = str(self.fenetre.ui.pi_listeAttributs.item(ligne, 1).text().toUtf8()) valVerifiee = regles.listeControle()[attribut].controler(nouvelleVal) if valVerifiee != None: self.pionSelectionne().listeAttributs[attribut] = valVerifiee if attribut == regles.attributOrdreJeu(): print("maj ordre (a implementer)") else: self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[attribut])))) def initListeAttaques(self): """met en forme et connecte la liste des attaques du pion""" self.fenetre.ui.pi_listeAttaques.setColumnWidth(0, 0) self.fenetre.ui.pi_listeAttaques.setColumnWidth(1, (0.3*self.fenetre.ui.pi_listeAttaques.width())) self.fenetre.ui.pi_listeAttaques.setColumnWidth(2, (0.7*self.fenetre.ui.pi_listeAttaques.width())) self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("itemSelectionChanged()"), self.majInfosAttaqueEC) self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("cellClicked(int, int)"), self.listeAttaquesCelluleCliquee) self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC) self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(0, (0.49*self.fenetre.ui.pi_listeAttributsAttaqueEC.width())) self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(1, (0.5*self.fenetre.ui.pi_listeAttributsAttaqueEC.width())) def majListeAttaques(self): """met a jour la liste des attaques du pion dans le panneau de combat""" #on vide la liste while self.fenetre.ui.pi_listeAttaques.rowCount() > 0: self.fenetre.ui.pi_listeAttaques.removeRow(0) self.fenetre.ui.pi_listeAttaques.setVisible((self.pionSelectionne() != None)) ## self.fenetre.ui.editerAttaques.setVisible((self.pionSelectionne() != None)) self.fenetre.ui.pi_panneauAttaqueEC.setVisible((self.pionSelectionne() != None)) i = 0 if self.pionSelectionne() != None: for attaque in self.pionSelectionne().attaques: self.fenetre.ui.pi_listeAttaques.insertRow(i) self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque))))) icone = None if attaque.typ == "cac": icone = QIcon(":/interface/16/ressource/epee_16.png") if attaque.typ == "dist": icone = QIcon(":/interface/16/ressource/arc_16.png") if attaque.typ == "zone": icone = QIcon(":/interface/16/ressource/baguette_16.png") if icone != None: self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8(""))) self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom))) self.majInfosAttaqueEC() def listeAttaquesCelluleCliquee(self, ligne, colonne): """on a clique sur une cellule de la liste des attaques""" numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8())) if numAttaque >= 0: self.utiliserAttaque(numAttaque) def utiliserAttaque(self, numAttaque): """le pion selectionne utilise son attaque n""" if self.pionSelectionne() != None: if numAttaque < len(self.pionSelectionne().attaques): attaque = self.pionSelectionne().attaques[numAttaque] if attaque.typ == "cac": self.majModeCombat("combatAttaqueCaC") if attaque.typ == "dist": self.majModeCombat("combatAttaqueDist") if attaque.typ == "zone": self.modeParam["typeAttaqueZone"] = attaque.formeZone self.majModeCombat("combatAttaqueZone") def majInfosAttaqueEC(self): """met a jour les infos de l'attaque en cours (selectionnee)""" selection = self.fenetre.ui.pi_listeAttaques.selectedItems() self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0) if self.pionSelectionne() != None and len(selection) > 0: ligne = selection[0].row() numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8())) self.disconnect(self.fenetre.ui.pi_panneauAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee) #on vide la liste while self.fenetre.ui.pi_listeAttributsAttaqueEC.rowCount() > 0: self.fenetre.ui.pi_listeAttributsAttaqueEC.removeRow(0) self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(0) self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 0, QTableWidgetItem(QString.fromUtf8("numAtt"))) self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 1, QTableWidgetItem(QString.fromUtf8(str(numAttaque)))) self.fenetre.ui.pi_listeAttributsAttaqueEC.setRowHidden(0, True) #attributs issus des regles utilisees ordre = regles.ordreAttributsAttaques() for elt in ordre: ligne = 1 + ordre.index(elt) self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(ligne) item = QTableWidgetItem(QString.fromUtf8(elt)) item.setFlags(Qt.NoItemFlags) self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 0, item) self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques[numAttaque].attributs[elt])))) self.connect(self.fenetre.ui.pi_listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee) #maj des notes self.disconnect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC) self.fenetre.ui.pi_notesAttaqueEC.majTexte(self.pionSelectionne().attaques[numAttaque].notes) self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC) def attaqueECCelluleModifiee(self, ligne, colonne): """une cellule de la liste d'attributs de l'attaque en cours a ete modifiee""" pass def majNotesAttaqueEC(self): """met a jour les notes de l'attaque en cours (selectionnee)""" selection = self.fenetre.ui.pi_listeAttaques.selectedItems() self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0) if self.pionSelectionne() != None and len(selection) > 0: ligne = selection[0].row() numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8())) self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_notesAttaqueEC.toPlainText().toUtf8()) def majNotesCombattant(self): """les notes du pion ont ete mises a jour""" if self.pionSelectionne() != None: self.pionSelectionne().notes = str(self.fenetre.ui.pi_notes.toPlainText().toUtf8()) else: pass ############### ######### gestion des evenements souris et clavier ############### def clic_pion(self, num): if num > 0: return self.clic_combattant(num) else: return self.clic_decor(num) def clic_combattant(self, num): return self.modeActif.clic_combattant(num) def clic_decor(self, num): return self.modeActif.clic_decor(num) def clic_case(self, coord): return self.modeActif.clic_case(coord) def survol_pion(self, num): if num > 0: return self.survol_combattant(num) else: return self.survol_decor(num) def survol_combattant(self, num): """le pion est survole par le curseur, on affiche ses informations dans la zone prevue""" return self.modeActif.survol_decor(num) def survol_decor(self, num): """le pion est survole par le curseur, on affiche ses informations dans la zone prevue""" return self.modeActif.survol_decor(num) def survol_case(self, coord): self.majInfoTr(self.cases[coord]) self.majInfoPion(self.pions[self.cases[coord].occupant()]) return self.modeActif.survol_case(coord) def finSurvol_pion(self, num): self.majInfoPion(None) if num > 0: return self.finSurvol_combattant(num) else: return self.finSurvol_decor(num) def finSurvol_combattant(self, num): """le pion est survole par le curseur, on affiche ses informations dans la zone prevue""" return self.modeActif.finSurvol_combattant(num) def finSurvol_decor(self, num): """le pion est survole par le curseur, on affiche ses informations dans la zone prevue""" return self.modeActif.finSurvol_decor(num) def finSurvol_case(self, coord): return self.modeActif.finSurvol_case(coord) def survolClic_case(self, coord): return self.modeActif.survolClic_case(coord) def doubleClic_pion(self, num): if num > 0: return self.doubleClic_combattant(num) def doubleClic_combattant(self, num): return self.modeActif.doubleClic_combattant(num) def mouseMoveEvent(self, event): super(Plateau, self).mouseMoveEvent(event) if event.buttons() == Qt.LeftButton and self.vue().dragMode() != QGraphicsView.ScrollHandDrag: coord = self.coordonneesAuPoint(event.scenePos()) if coord != None: self.survolClic_case(coord) else: self.modeActif.mouvementSouris(event) event.ignore() def mousePressEvent(self, event): super(Plateau, self).mousePressEvent(event) if event.button() == 1: self.modeActif.clicGauche(event) elif event.button() == 2: self.modeActif.clicDroit(event) event.accept() def mouseReleaseEvent(self, event): super(Plateau, self).mouseReleaseEvent(event) self.modeActif.finClicGauche(event) def keyPressEvent(self, event): """gestion des evenements clavier""" self.modeActif.toucheClavier(event) ################ ############### Fonctions diverses def pionSelectionne(self): """renvoie le pion actuellement selectionne""" if self.modeActif.__class__.__name__ == "PionSelectionne": return self.modeActif.pion() return None def afficherListeCases(self, listeCases, actif): """met ou non en evidence les cases selectionnees""" for coord in listeCases: self.cases[coord].majEstCibleCurseur(actif) def pionDeposer(self, coordCase): """on depose le pion sur la case voulue""" if self.pionSelectionne() != None: pion = self.pionSelectionne() if pion != None: if self.proj.valide(): pion.majPosition(self.proj.coord(), self.proj.nbRotations()) def nouveauCache(self, listeCases): nouvelId = 0 if len(self.caches) > 0: nouvelId = max(self.caches) + 1 cache = Cache(nouvelId) cache.activer(True) cache.nom = "Cache {}".format(nouvelId + 1) self.caches[nouvelId] = cache self.ajouterCacheATable(cache) for coord in listeCases: self.cases[coord].ajouterCache(nouvelId) def supprimerCache(self): ligne = self.fenetre.ui.cp_listeCaches.currentRow() idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0)) for coord in self.cases: self.cases[coord].supprimerCache(idCache) self.fenetre.ui.cp_listeCaches.removeRow(idCache) del self.caches[idCache] def centrerSur(self, num): """centre la vue sur le pion""" self.vue().centerOn(self.cases[self.pions[num].position].centreGraphique) # def coordonneesValides(self, coord): # """les coordonnees entrees en parametre sont elles celles d'une case du plateau""" # return (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.nbCasesX and coord[1] < self.nbCasesY) # # def lstCoordAdjacentes(self, x, y): # """renvoie la liste des coordonnees adjacentes, !!!! sans condition d'existence sur le plateau !!!! # attention: l'ordre est important""" # if self.formeCases == "H": # if 1 == (x % 2): # voisins = [(x, y-1), (x+1, y), (x+1, y+1), (x, y+1), (x-1, y+1), (x-1, y)] # else: # voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x, y+1), (x-1, y), (x-1, y-1)] # else: # voisins = [(x, y-1), (x+1, y), (x, y+1), (x-1, y)] # return voisins # def zone(self, origine, rayon, zR = 0): # """renvoie un dictionnaire representant la liste des coordonnees des cases comprises dans la zone # la zone en question est la liste des cases situees a une distance d des coordonnees d'origine""" # if not self.coordonneesValides(origine) or not rayon >= 0: return {} # if rayon == 0: return {origine: 0} # resultat = {} # aVerifier = [] ; aVerifier2 = [] ; k = 0 # #on part de la premiere case, puis on itere a partir de chaque nouveau depart sur les voisins # aVerifier.append(origine) # while k <= rayon: # for depart in aVerifier: # for coord in self.cases[depart].voisins: # if not coord in aVerifier and not coord in aVerifier2 and not coord in resultat: # aVerifier2.append(coord) # for elt in aVerifier: # resultat[elt] = k # aVerifier = aVerifier2 ; aVerifier2 = [] ; k += 1 # return resultat # def zone3d(self, origine, rayon, zCible=0): # """renvoie les cases de la zone au format (x, y, z)""" # retour = [] # zone = self.zone(origine, rayon) # for coord in zone: # x, y = coord # dz = rayon - zone[coord] # for z in range(-dz, dz + 1): # retour.append( (x, y, (zCible+z) ) ) # return retour # def cone(self, coord1, coord2): # """renvoie les coord des cases composant le cone (en 2d)""" # retour = [] # x1, y1 = coord1 ; x2, y2 = coord2 # if x1 % 2 == 1: y1 += 0.5 # if x2 % 2 == 1: y2 += 0.5 # # if abs(y2 - y1) - abs(x2 - x1) <= 0 : # #secteur horizontal # angleRef = (y2 - y1) / (x2 - x1) # dist2Ref = ( (x2 - x1)**2 + (y2 - y1)**2 ) # for coord in self.cases: # x, y = coord # if x % 2 == 1: y += 0.5 # if x != x1: # angle = (y - y1) / (x - x1) # if abs( angleRef - angle ) <= 0.5 and ( (x - x1)**2 + (y - y1)**2 ) <= dist2Ref \ # and ( (x - x1) * (x2 - x1) ) > 0: # retour.append(coord) # else: # #secteur vertical # angleRef = (x2 - x1) / (y2 - y1) # dist2Ref = ( (x2 - x1)**2 + (y2 - y1)**2 ) # for coord in self.cases: # x, y = coord # if x % 2 == 1: y += 0.5 # if y != y1: # angle = (x - x1) / (y - y1) # if abs( angleRef - angle ) <= 0.5 and ( (x - x1)**2 + (y - y1)**2 ) <= dist2Ref \ # and ( (y - y1) * (y2 - y1) ) > 0: # retour.append(coord) # return retour # # def cone3d(self, coord1, coord2, z1 = 0, z2 = 0): # return self.cone(coord1, coord2) # def blocAdjacent(self, listeCases): # """renvoie un bloc de cases adjacentes a partir de la liste en parametre""" # retour = [] # tmp1 = [listeCases[0]]; tmp2 = [listeCases[0]] # while len(tmp2) > 0: # tmp2 = [] # #on liste les cases voisines qui sont dans la liste et pas encore verifiees # for coord in tmp1: # for voisine in self.cases[coord].voisins: # if voisine in listeCases and not voisine in tmp1 and not voisine in tmp2: # tmp2.append(voisine) # #chacune de ces cases prend le statut de verifiee # for coord in tmp1: # listeCases.remove(coord) # retour.append(coord) # tmp1 = tmp2 # return retour # def polygone(self, x, y): # """renvoie l'objet graphique hexagone de la case de coordonnees (x, y)""" # polygone = QPolygonF() # if self.formeCases == "H": # #si x est impair sur un plateau a cases hexagonales, le y est augmente de 0.5 # if 1 == (x % 2): # y += 0.5 # polygone << QPointF(((x*0.866)+0.2886)*120, y*120) \ # << QPointF(((x*0.866)+0.866)*120, y*120) \ # << QPointF(((x*0.866)+1.1547)*120, (y+0.5)*120) \ # << QPointF(((x*0.866)+0.866)*120, (y+1)*120) \ # << QPointF(((x*0.866)+0.2886)*120, (y+1)*120) \ # << QPointF( (x*0.866)*120, (y+0.5)*120) # else: # polygone << QPointF(x*120, y*120) \ # << QPointF((x+1)*120, y*120) \ # << QPointF((x+1)*120, (y+1)*120) \ # << QPointF(x*120, (y+1)*120) # return polygone # def polygoneAgglo(self, listeCases): # """renvoie un polygone contruit par agglomeration des polygones des cases de la liste # les cases doivent etre adjacentes (cases hexagonales ou carrees)""" # segments = [] # #on parcourt les faces des polygones des cases, et on ne garde que ceux qui n'ont pas de case 'en face' # for coord in listeCases: # polygone = self.polygone(coord[0], coord[1]) # voisins = self.lstCoordAdjacentes(coord[0], coord[1]) # # for i in range(0, len(voisins)): # if not voisins[i] in listeCases: # j = i+1 # if j > len(voisins) - 1: # j = 0 # segments.append(QLineF(polygone[i], polygone[j])) # # #on 'accroche' les segments les uns aux autres, dans l'ordre # if not len(segments) > 0: return None # segments2 = [segments[0]] # for segment2 in segments2: # for segment in segments: # if not QLineF(segment.p1(), segment.p2()) in segments2 and not QLineF(segment.p2(), segment.p1()) in segments2: # if sqrt((segment.p1().x()-segment2.p2().x())**2+(segment.p1().y()-segment2.p2().y())**2) < 1: # segments2.append(QLineF(segment.p1(), segment.p2())) # elif sqrt((segment.p2().x()-segment2.p2().x())**2+(segment.p2().y()-segment2.p2().y())**2) < 1: # segments2.append(QLineF(segment.p2(), segment.p1())) # # pointsPolygone = [] # premierPoint = segments2[0].p1() # pointsPolygone.append(premierPoint) # for segment in segments2: # pointSuivant = segment.p2() # if pointSuivant != premierPoint: # pointsPolygone.append(pointSuivant) # # #creation du polygone # polygone = QPolygonF() # for point in pointsPolygone: # polygone.append(point) # # return polygone # def coordCentreListeCases(self, listeCases): # """renvoie les coordonnees centrales d'une liste de cases""" # retour = None # if len(listeCases) > 0: # listeTriee = sorted(listeCases) # posMilieu = int(len(listeCases)/2) # retour = listeTriee[posMilieu] # return retour def coordonneesAuPoint(self, point): """renvoie les coordonnees de la case situee au QPointF entre en parametre""" item = self.itemAt(point) try: coord = item.coord() except: coord = None return coord def pionAuPoint(self, point): """retourne le premier pion de la pile s'il y en a plusieurs""" coord = self.coordonneesAuPoint(point) if not coord: return None pions = self.cases[coord].occupants() if len(pions) == 0: return None return pions[0] def ldmValide(self, origine, cible): """la ligne de mire entre les deux points est elle valide origine et cible sont toutes deux de la forme (x,y,z)""" if not cible != origine: return False ldm = self.geo.ligne(origine, cible) if len(ldm) == 0: return False ldm.remove(origine) ; ldm.remove(cible) x0, y0, z0 = origine ; x1, y1, z1 = cible for coord in ldm: x, y, z = coord occupant = self.cases[(x, y)].occupant(z) if occupant: #si une case de la ligne est occupee par autre chose que le tireur et sa cible if occupant != self.cases[(x0, y0)].occupant(z0) and \ occupant != self.cases[(x1, y1)].occupant(z1): return False return True def coutDep(self, coord1, coord2, z2 = None): """renvoie le cout de deplacement de la case 1 a la case 2 pour le pion actuellement selectionne / un cout egal a -1 implique un deplacement impossible""" retour = 0 dist = 1 if not self.cases[coord2].terrain.franchissable: return -1 if self.cases[coord2].z1(): return -1 if z2 == None: z2 = self.cases[coord2].z1() if self.cases[coord2].occupant(z2): return -1 if self.pionSelectionne().zR == 0: dz = self.cases[coord2].z1() - self.cases[coord1].z1() if dz < (-1 * self.pionSelectionne().saut): return -1 if dz > self.pionSelectionne().h: #si la diff de hauteur est superieure a la hauteur du combattant, il escalade if not self.pionSelectionne().depEscalade > 0: return -1 retour += self.pionSelectionne().coutDep("depEscalade", dz) elif 0 < dz <= self.pionSelectionne().h: dist += dz if self.cases[coord2].terrain.nage: if not self.pionSelectionne().depNage > 0: return -1 retour += self.pionSelectionne().coutDep("depNage", dist) else: if not self.pionSelectionne().depMarche > 0: return -1 retour += self.pionSelectionne().coutDep("depMarche", dist) else: if not self.pionSelectionne().depVol > 0: return -1 retour += self.pionSelectionne().coutDep("depVol", dist) return retour def majZonePlacement(self, listeCases): """met a jour la forme et l'affichage de la zone de placement initale des joueurs""" if len(listeCases) > 0: if self.polygoneZonePlacement == None: self.polygoneZonePlacement = QGraphicsPolygonItem(scene=self) self.polygoneZonePlacement.setZValue(0) qCouleurFond = QColor("white") qCouleurFond.setAlpha(50) self.polygoneZonePlacement.setBrush(qCouleurFond) pinceau = QPen(QColor("orange")) pinceau.setWidth(20) self.polygoneZonePlacement.setPen(pinceau) self.polygoneZonePlacement.setAcceptedMouseButtons(Qt.NoButton) self.polygoneZonePlacement.setAcceptHoverEvents(False) self.addItem(self.polygoneZonePlacement) listeCases2 = [] for coord in listeCases: if self.cases[coord].terrain.franchissable: listeCases2.append(coord) listeCases3 = self.geo.blocAdjacent(listeCases2) polygone = self.geo.polygoneAgglo(listeCases3) if not polygone: return self.polygoneZonePlacement.setPolygon(polygone) self.listeCasesZonePlacement = listeCases ####### maj des panneaux d'info def majInfoPion(self, pion = None): self.majInfoCb((pion if pion.numero > 0 else None) if pion else None) self.majInfoDc((pion if pion.numero < 0 else None) if pion else None) def majInfoCb(self, cb = None): self.fenetre.ui.icb_panneau.setVisible((cb != None)) if cb: self.fenetre.ui.icb_image.chargerImage(cb.icone()) self.fenetre.ui.icb_nom.majTexte(contractTxt(cb.nom(), 25)) self.fenetre.ui.icb_mort.setVisible((cb.etat == 4)) self.fenetre.ui.icb_image.setEnabled((cb.etat != 4)) self.fenetre.ui.icb_etourdi.setVisible(0 in cb.statuts) self.fenetre.ui.icb_brule.setVisible(4 in cb.statuts) self.fenetre.ui.icb_paralyse.setVisible(2 in cb.statuts) self.fenetre.ui.icb_empoisonne.setVisible(3 in cb.statuts) self.fenetre.ui.icb_gele.setVisible(1 in cb.statuts) self.fenetre.ui.icb_etat.majTexte(lstLibEtats("cb")[cb.etat]) self.fenetre.ui.icb_hauteur.majTexte("Hauteur: {}".format(cb.h)) self.fenetre.ui.icb_vol.majTexte("En vol: {}".format(cb.zR) if cb.enVol else "") def majInfoDc(self, dc = None): self.fenetre.ui.idc_panneau.setVisible((dc != None)) if dc: self.fenetre.ui.idc_image.chargerImage(dc.icone()) self.fenetre.ui.idc_nom.majTexte(contractTxt(dc.nom(), 25)) self.fenetre.ui.idc_detruit.setVisible((dc.etat == 4)) self.fenetre.ui.idc_image.setEnabled((dc.etat != 4)) self.fenetre.ui.idc_brule.setVisible(4 in dc.statuts) self.fenetre.ui.idc_verrouille.setVisible(5 in dc.statuts) self.fenetre.ui.idc_etat.majTexte(lstLibEtats("dc")[dc.etat]) self.fenetre.ui.idc_hauteur.majTexte("Hauteur: {}".format(dc.h) if not (self.zP and dc.hMax) else "") def majInfoTr(self, case = None): if case: self.fenetre.ui.ic_coord.majTexte("X{} Y{}".format(case.x, case.y)) self.fenetre.ui.ic_terrain.majTexte(case.terrain.nom() if (len(case.terrain.nom()) > 0) else "Case") self.fenetre.ui.ic_altitude.majTexte("{}".format(case.z0)) if case.effetActif not in ["", "aucun"]: imgEffet = {"brule": "feu_16.png", "eau": "eau_16.png","glace": "glace_16.png","poison": "poison_16.png"} pix = QPixmap(":/interface/16/ressource/{}".format(imgEffet[case.effetActif])) self.fenetre.ui.ic_effet.setPixmap(pix) else: self.fenetre.ui.ic_effet.clear()