#from __future__ import unicode_literals # -*- coding: utf-8 -*- from __future__ import division import os from sys import exit, argv, getsizeof, settrace from time import time, sleep, strftime, localtime from threading import Thread from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4 import QtOpenGL from ui.ecran_editionTerrain import Ui_editionTerrain from ui.ecran_editionCreature import Ui_editionCreature from ui.ecran_editionDecor import Ui_editionDecor from ui.ecran_gestionCombat import Ui_gestionCombat from ui.ecran_editionAttaques import Ui_editionAttaques from ui.ecran_affichageTexte import Ui_affichageTexte from Case import Case from Pion import Pion from PionDecor import PionDecor from Cache import Cache from EntreeSortie import EntreeSortie import regles as regles from outilsSvg import * from lancer import jet, estJetValide from operator import itemgetter, attrgetter from math import * class Plateau(QGraphicsScene): """plateau de jeu contenant les cases, decors et pions""" def __init__(self, fenetre, parent=None): super(Plateau, self).__init__() #parametres et variables self.id = "" self.nom = "" self.chapitre = 0 self.fenetre = fenetre self.nbCasesX = 0 self.nbCasesY = 0 self.hCase = 0 self.cases = {} #dict des cases du plateau (coordonnées: case) self.pions = {} #liste de pions positionnes sur le plateau self.decors = {} #liste des decors places sur le plateau self.ordreJeu = {} #numero du pion: ordre de jeu self.numPionEnCours = 0 self.tour = 1 self.cacheEnCours = 1 self.caches = {} self.polygonesCaches = {} for i in range(1,5): self.caches[i] = {"actif":False,"listeCases":[]} self.polygonesCaches[i] = None self.listeCasesZonePlacement = [] self.polygoneZonePlacement = None self.entreesSorties = [] self.modePrincipal = "creation" self.modeActif = "" self.modeCombat = "" self.nbZoomActuel = 0 self.epaisseurpinceau = 0 self.enCours = False self.public = False self.dateCreation = "" self.dateSvg = "" self.notes = "" #note: la hauteur Z (qui gere l'empilement des objets graphiques est distribuee de cette maniere: #cases : 0 a 9 #pions : 10 et + def __getstate__(self): self.dateSvg = time() state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", "listMode", "cacheEnCours", \ "modeParam", "nbZoomActuel", "epaisseurPinceau", \ "editionTerrain", "editionCreature", "editionDecor", \ "polygoneZonePlacement", "gestionCombat", "polygonesCaches", \ "editionAttaques"]} return (state) def __setstate__(self, state): self.__dict__ = state def creer(self, idPlateau, nom, chapitre, formeCases, nbCasesX, nbCasesY, couleur = QColor(0, 255, 0, 80)): """cree le plateau""" self.id = idPlateau self.nom = nom self.chapitre = chapitre self.dateCreation = time() self.hCase = 120 #hauteur d'une case self.nbCasesX = nbCasesX #nb cases en x self.nbCasesY = nbCasesY #nb cases en y self.formeCases = formeCases self.gestionCombat = None self.initialisationGraphique() self.connexions() #cree les cases hexagonales for x in range(nbCasesX): for y in range(nbCasesY): if formeCases == "H": if 1 == (x % 2): y += 0.5 c = Case(self) c.creer(x, y, couleur) self.cases[(x,y)] = c def recreer(self, fenetre): self.fenetre = fenetre self.gestionCombat = None super(Plateau, self).__init__() self.connexions() self.initialisationGraphique() #recreation des cases for coord in self.cases: self.cases[coord].recreer(self) #recreation des pions for numPion in self.pions: self.pions[numPion].recreer(self) self.majOrdreJeu() #recreation des decors for num in self.decors: self.decors[num].recreer(self) #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) #recreation des caches self.polygonesCaches = {} for i in range(1,5): self.polygonesCaches[i] = None def fermer(self): """ferme le plateau 'proprement'""" for item in self.items(): item.prepareGeometryChange() self.removeItem(item) if self.gestionCombat != None: del self.gestionCombat self.fenetre.reinitialiserPanneauxPlateau() def connexions(self): """connecte le plateau aux differents widgets de la fenetre principale""" self.fenetre.connect(self.fenetre.ui.modeCreationPlateau, SIGNAL("clicked()"), self.plateauModeCreation, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.modeCombatPlateau, SIGNAL("clicked()"), self.plateauModeCombat, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.afficherGestionCombat, SIGNAL("clicked()"), self.afficheEcranGestionCombat, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.terrainCouleur, SIGNAL("clicked()"), self.modePeintureCase, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.terrainCopie, SIGNAL("clicked()"), self.modeCopieTerrain, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.pionCouleur, SIGNAL("clicked()"), self.majCouleurPion, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.terrainEdit, SIGNAL("clicked()"), self.terrainEdit, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.terrainNouveau, SIGNAL("clicked()"), self.terrainNouveau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.creatureEdit, SIGNAL("clicked()"), self.creatureEdit, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.creatureNouveau, SIGNAL("clicked()"), self.creatureNouveau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.pionSimpleCreer, SIGNAL("clicked()"), self.modeCreationPion, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.pionSupprimer, SIGNAL("clicked()"), self.majModePionSupprimer, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.decorEdit, SIGNAL("clicked()"), self.decorEdit, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.decorNouveau, SIGNAL("clicked()"), self.decorNouveau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.decorSupprimer, SIGNAL("clicked()"), self.majModePionSupprimer, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.definirEntree, SIGNAL("clicked()"), self.majModeDefinirEntree, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.definirSortie, SIGNAL("clicked()"), self.majModeDefinirSortie, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.definirZonePlacement, SIGNAL("clicked()"), self.majModeZonePlacement, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeSimple, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeLigne, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeLigneOrientee, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeEllipseVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeEllipsePlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeRectVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.effFeu, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.effEau, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.effGlace, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.effPoison, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.effEffacer, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cacheActif, SIGNAL("clicked()"), self.majEtatCacheEnCours, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cacheVoir, SIGNAL("clicked()"), self.voirCacheEnCours, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.cachePlacer, SIGNAL("clicked()"), self.placerCacheEnCours, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.combatDeplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection) self.fenetre.ui.combatDeplacement.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatAttaqueCaC, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection) self.fenetre.ui.combatAttaqueCaC.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatAttaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection) self.fenetre.ui.combatAttaqueDist.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatAttaqueZone, SIGNAL("clicked()"), self.fenetre.barreCombatZone, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.combatAttaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection) self.fenetre.ui.combatAttaqueZone.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatVol, SIGNAL("clicked()"), self.fenetre.barreCombatVol, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.combatVol_altitude, SIGNAL("valueChanged(int)"), self.majZPion, Qt.UniqueConnection) #self.fenetre.connect(self.fenetre.ui.combatVol_altitude, SIGNAL("editingFinished()"), self.majVisibiliteBarreCombat) self.fenetre.connect(self.fenetre.ui.combatZone_ligne, SIGNAL("clicked()"), self.majModeCombatZoneForme, Qt.UniqueConnection) self.fenetre.ui.combatZone_ligne.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatZone_disque, SIGNAL("clicked()"), self.majModeCombatZoneForme, Qt.UniqueConnection) self.fenetre.ui.combatZone_disque.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatZone_cone, SIGNAL("clicked()"), self.majModeCombatZoneForme, Qt.UniqueConnection) self.fenetre.ui.combatZone_cone.setCheckable(True) self.fenetre.connect(self.fenetre.ui.combatRetour, SIGNAL("clicked()"), self.fenetre.barreCombatMenu, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.combatPasserTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection) #self.connect(self.ui.combatInventaire, SIGNAL("clicked()"), self.majModePionSupprimer) self.fenetre.connect(self.fenetre.ui.modeAffichagePlateau, SIGNAL("currentIndexChanged(int)"), self.majModeAffichage, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.listTerrains, SIGNAL("cellClicked(int,int)"), self.modeMajTerrainCase, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.listCreatures, SIGNAL("cellClicked(int,int)"), self.modeCreationCreaturePion, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.listDecors, SIGNAL("cellClicked(int,int)"), self.modeCreationDecor, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.epaisseurPinceau, SIGNAL("valueChanged(int)"), self.majEpaisseurPinceau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.altitudeCase, SIGNAL("valueChanged(double)"), self.modeMajAltitudeCase, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.infoOrdreJeu, SIGNAL("cellClicked(int,int)"), self.clicListOrdreJeu, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.editerAttaques, SIGNAL("clicked()"), self.afficheEcranEditionAttaques, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.notesPion, SIGNAL("textChanged()"), self.majNotesPion, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.notesMjPlateau, SIGNAL("textChanged()"), self.majNotesPlateau, Qt.UniqueConnection) self.fenetre.connect(self.fenetre.ui.agrandirNotesMjPlateau, SIGNAL("clicked()"), self.agrandirNotesMjPlateau, 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.fenetre.ui.vuePlateau.setScene(self) self.fenetre.ui.vuePlateau.scale(0.25, 0.25) self.fenetre.ui.vuePlateau.centerOn(QPointF(0,0)) self.fenetre.ui.vuePlateau.setDragMode(1) self.setItemIndexMethod(QGraphicsScene.BspTreeIndex) #self.setItemIndexMethod(QGraphicsScene.NoIndex) self.nbZoomActuel = 0 self.epaisseurPinceau = 1 self.polygoneZonePlacement = None self.polygonesCaches = {} for i in range(1,5): self.polygonesCaches[i] = None #gestion du mode d'interaction avec le plateau self.modeActif = "standard" self.listMode = ["standard", "caseMajTerrain", "caseCopie", "caseMajEffet", "caseMajAltitude", "pionCreation", \ "pionSelectionne", "pionDecorCreation", "pionDecorSelectionne", "pionSupprimer", "cachePlacer", \ "combatDeplacement", "combatAttaqueCaC", "combatAttaqueDist", \ "placementEntreeSortie", "majZonePlacement"] self.modeParam = {"terrain": None, "numPionSelectionne": 0, "pionNouveau": None, "creature": None, "decor": None, "effet":"", "couleurPion": QColor("grey"), \ "coordProjectionPosition": (0,0), "formeProjectionPosition": None, "nbRotations": 0, \ "typeFormeDessin": "simple", "formeDessin": None, "origineFormeDessin": None, "point2FormeDessin": None, "listeCasesFormeDessin": [], \ "projectionFormeDessin": [], "formeCoordEnCours": (0,0), \ "zoneAttaqueCaC": [], "cibleAttaqueCaC": None, "cibleAttaqueDist": None, "pionCibleAttaqueDist": None, "ligneAttaqueDist": None, \ "typeAttaqueZone": "", "formeAttaqueZone": None, "origineAttaqueZone": None, "point2AttaqueZone": None, "listeCasesAttaqueZone": [], "ligneMireAttaqueZone": None, \ "entreeSortie": None} #mise a jour de l'interface de creation self.fenetre.majVisibilitePanneauxPlateau("creation") self.fenetre.ui.nomPlateau.setText(QString.fromUtf8(self.nom)) self.fenetre.ui.nomPlateau.setText(QString.fromUtf8(self.nom)) self.majBoutonsCouleursPerso() self.majBoutonsCaches() self.majListTerrains() self.majListCreatures() self.majListDecors() self.initListeOrdreJeu() self.initListeAttaques() self.fenetre.ui.notesMjPlateau.setText(QString.fromUtf8(self.notes)) if self.modeParam["couleurPion"].isValid(): self.fenetre.ui.pionCouleur.setStyleSheet("QPushButton {backGround:%s}" %(self.modeParam["couleurPion"].name())) #mise a jour de l'interface d'informations self.majInfosPion(None) self.majInfosDecor(None) def estCree(self): """renvoie vrai si des cases ont ete creees""" if len(self.cases) > 0: retour = True else: retour = False return retour 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,16): rgb = QColorDialog(self.fenetre.ui.vuePlateau).customColor(i) couleur = QColor(rgb) bouton = self.fenetre.ui.outilsEditionPlateau.findChild(QToolButton, "terrainCouleurPerso{}".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.fenetre.ui.vuePlateau).getColor(QColor("white"), self.fenetre.ui.vuePlateau) self.majBoutonsCouleursPerso() return couleur def majBoutonsCaches(self): """met a jour l'affichage et connecte les boutons de caches""" for i in range(1,5): bouton = self.fenetre.ui.outilsEditionPlateau.findChild(QToolButton, "plateauCache{}".format(i)) self.fenetre.connect(bouton, SIGNAL("clicked()"), self.majAffichageMenuCache) def majListesPions(self, numPion = None): """met a jour les listes contenant des donnees liees aux pions""" ## self.majListeOrdreJeu() ## ## if numPion == None or numPion == self.pionSelectionne().numero: ## self.majListeAttributs() ## QApplication.processEvents() pass def majNotesPlateau(self): """les notes du plateau ont ete maj a l'ecran""" self.notes = str(self.fenetre.ui.notesMjPlateau.toPlainText().toUtf8()) def agrandirNotesMjPlateau(self): """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies""" affichageTexte = EcranAffichageTexte(self.notes) affichageTexte.setAttribute(Qt.WA_DeleteOnClose) r = affichageTexte.exec_() self.fenetre.ui.notesMjPlateau.setText(QString.fromUtf8(affichageTexte.recupererTexte())) ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees"""" def afficheEcranEditionTerrains(self, terrain = None): """affiche l'ecran d'edition/creation de terrains""" self.editionTerrain = EcranEditionTerrain(terrain) self.connect(self.fenetre, SIGNAL("majListTerrains()"), self.majListTerrains) self.connect(self.editionTerrain, SIGNAL("majListTerrains()"), self.majListTerrains) self.editionTerrain.setAttribute(Qt.WA_DeleteOnClose) r = self.editionTerrain.exec_() def majListTerrains(self): """mise a jour de la liste des terrains depuis la sauvegarde""" dico = afficheSvg("biblio\\terrain") while self.fenetre.ui.listTerrains.rowCount() > 0: self.fenetre.ui.listTerrains.removeRow(0) index = 0 #self.fenetre.ui.listTerrains.setColumnWidth(0,0) self.fenetre.ui.listTerrains.hideColumn(0) self.fenetre.ui.listTerrains.sizeHintForColumn(1) for elt in dico: terrain = dico[elt] self.fenetre.ui.listTerrains.insertRow(int(index)) self.fenetre.ui.listTerrains.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt))) icon = QIcon("img\\"+terrain.imgTexture) item = QTableWidgetItem(icon,QString.fromUtf8(terrain.nom)) self.fenetre.ui.listTerrains.setItem(int(index),1,item) index += 1 self.fenetre.ui.listTerrains.setIconSize(QSize(30,20)) self.fenetre.ui.listTerrains.sizeHintForColumn(1) self.fenetre.ui.listTerrains.sortItems(0) self.majMode("standard") def terrainEdit(self): """ouvre la fenetre 'terrains' en mode edition""" index = self.fenetre.ui.listTerrains.item(self.fenetre.ui.listTerrains.currentRow(), 0) if index > 0: terrain = charger("biblio\\terrain", str(index.text().toUtf8())) self.afficheEcranEditionTerrains(terrain) def terrainNouveau(self): """ouvre la fenetre 'terrains' en mode edition""" self.afficheEcranEditionTerrains() ############### ##### affichage de la liste des creatures enregistrees, et fonctions d'acces aux donnees"""" def afficheEcranEditionCreatures(self, creature = None): """affiche l'ecran d'edition/creation de creatures""" self.editionCreature = EcranEditionCreature(creature, self.formeCases) self.editionCreature.setAttribute(Qt.WA_DeleteOnClose) self.connect(self.fenetre, SIGNAL("majListCreatures()"), self.majListCreatures) self.connect(self.editionCreature, SIGNAL("majListCreatures()"), self.majListCreatures) r = self.editionCreature.exec_() def majListCreatures(self): """mise a jour de la liste des creatures depuis la sauvegarde""" dico = afficheSvg("biblio\\creature") while self.fenetre.ui.listCreatures.rowCount() > 0: self.fenetre.ui.listCreatures.removeRow(0) index = 0 #self.fenetre.ui.listTerrains.setColumnWidth(0,0) self.fenetre.ui.listCreatures.hideColumn(0) self.fenetre.ui.listCreatures.sizeHintForColumn(1) for elt in dico: creature = dico[elt] self.fenetre.ui.listCreatures.insertRow(int(index)) self.fenetre.ui.listCreatures.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt))) icon = QIcon("img\\"+creature.logo) item = QTableWidgetItem(icon,QString.fromUtf8(creature.nom)) self.fenetre.ui.listCreatures.setItem(int(index),1,item) index += 1 self.fenetre.ui.listCreatures.setIconSize(QSize(30,20)) self.fenetre.ui.listCreatures.sizeHintForColumn(1) ## self.fenetre.ui.listCreatures.sortItems(0) trierTable(self.fenetre.ui.listCreatures, 0, 0) self.majMode("standard") def creatureEdit(self): """ouvre la fenetre 'creatures' en mode edition""" index = self.fenetre.ui.listCreatures.item(self.fenetre.ui.listCreatures.currentRow(), 0) if index > 0: creature = charger("biblio\\creature", str(index.text().toUtf8())) self.afficheEcranEditionCreatures(creature) def creatureNouveau(self): """ouvre la fenetre 'creatures' en mode edition""" self.afficheEcranEditionCreatures() ############### ##### affichage de la liste des decors enregistrees, et fonctions d'acces aux donnees"""" def afficheEcranEditionDecors(self, decor = None): """affiche l'ecran d'edition/creation de decors""" self.editionDecor = EcranEditionDecors(decor, self.formeCases) self.editionDecor.setAttribute(Qt.WA_DeleteOnClose) self.connect(self.fenetre, SIGNAL("majListDecors()"), self.majListDecors) self.connect(self.editionDecor, SIGNAL("majListDecors()"), self.majListDecors) r = self.editionDecor.exec_() def majListDecors(self): """mise a jour de la liste des decors depuis la sauvegarde""" dico = afficheSvg("biblio\\decor") while self.fenetre.ui.listDecors.rowCount() > 0: self.fenetre.ui.listDecors.removeRow(0) index = 0 #self.fenetre.ui.listTerrains.setColumnWidth(0,0) self.fenetre.ui.listDecors.hideColumn(0) self.fenetre.ui.listDecors.sizeHintForColumn(1) for elt in dico: decor = dico[elt] self.fenetre.ui.listDecors.insertRow(int(index)) self.fenetre.ui.listDecors.setItem(int(index),0,QTableWidgetItem(QString.fromUtf8(elt))) icon = QIcon("img\\"+decor.logo) item = QTableWidgetItem(icon,QString.fromUtf8(decor.nom)) self.fenetre.ui.listDecors.setItem(int(index),1,item) index += 1 self.fenetre.ui.listDecors.setIconSize(QSize(30,20)) self.fenetre.ui.listDecors.sizeHintForColumn(1) ## self.fenetre.ui.listDecors.sortItems(0) trierTable(self.fenetre.ui.listDecors, 0, 0) self.majMode("standard") def decorEdit(self): """ouvre la fenetre 'decors' en mode edition""" index = self.fenetre.ui.listDecors.item(self.fenetre.ui.listDecors.currentRow(), 0) if index > 0: decor = charger("biblio\\decor", str(index.text().toUtf8())) self.afficheEcranEditionDecors(decor) def decorNouveau(self): """ouvre la fenetre 'decors' en mode edition""" self.afficheEcranEditionDecors() ############### ########### affichage des curseurs personnalises ######## def curseurSelection(self): self.fenetre.ui.vuePlateau.setDragMode(0) curseurPix = QPixmap("img\\curseurEpee.png")#.scaledToHeight(55, Qt.FastTransformation) curseurPix.setMask(curseurPix.createHeuristicMask()) curseurPointe = QCursor(curseurPix, 0, 0) self.fenetre.ui.vuePlateau.setCursor(curseurPointe) def curseurPinceau(self): self.fenetre.ui.vuePlateau.setDragMode(0) curseurPix = QPixmap("img\\curseurPinceau.png") curseurPinceau = QCursor(curseurPix, 0, curseurPix.height()) self.fenetre.ui.vuePlateau.setCursor(curseurPinceau) def curseurGomme(self): self.fenetre.ui.vuePlateau.setDragMode(0) curseurPix = QPixmap("img\\gomme.png")#.scaledToHeight(55, Qt.FastTransformation) curseurGomme = QCursor(curseurPix, 0, 0) self.fenetre.ui.vuePlateau.setCursor(curseurGomme) def curseurSeringue(self): self.fenetre.ui.vuePlateau.setDragMode(0) curseurPix = QPixmap("img\\curseurSeringue.png") curseurSeringue = QCursor(curseurPix, 0, 0) self.fenetre.ui.vuePlateau.setCursor(curseurSeringue) def curseurEpee(self, valide = True): self.fenetre.ui.vuePlateau.setDragMode(0) if valide: curseurPix = QPixmap("img\\curseurEpee.png") curseurSeringue = QCursor(curseurPix, 0, 0) self.fenetre.ui.vuePlateau.setCursor(curseurSeringue) def curseurArc(self): self.fenetre.ui.vuePlateau.setDragMode(0) curseurPix = QPixmap("img\\arc.png") curseurSeringue = QCursor(curseurPix, curseurPix.width(), 0) self.fenetre.ui.vuePlateau.setCursor(curseurSeringue) def curseurBaguette(self): self.fenetre.ui.vuePlateau.setDragMode(0) curseurPix = QPixmap("img\\baguette.png") curseurBaguette = QCursor(curseurPix, curseurPix.width(), 0) self.fenetre.ui.vuePlateau.setCursor(curseurBaguette) ############ ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres ####### def plateauModeCreation(self): self.fenetre.majVisibilitePanneauxPlateau("creation") self.modePrincipal = "creation" def plateauModeCombat(self): self.fenetre.majVisibilitePanneauxPlateau("combat") self.modePrincipal = "combat" def majModeAffichage(self, index): """met a jour le mode d'affichage""" nouveauMode = "" if index == 0: #passe a l'affichage standard pass elif index == 1: #passe en mode affichage de l'altitude nouveauMode = "altitude" elif index == 2: #affichage des terrains slt nouveauMode = "terrain" elif index == 3: #affichage tactique nouveauMode = "tactique" for coord in self.cases: self.cases[coord].majAffichageSpecial(nouveauMode) def modePeintureCase(self): """enclenche le mode peinture de case a partir de la couleur selectionnee""" self.majMode("standard") couleur = self.chercherCouleur() if couleur.isValid(): self.majMode("caseMajTerrain", couleur) else: self.majMode("standard") def modePeintureCase_perso(self): origine = self.sender().objectName() index = int(origine.replace("terrainCouleurPerso",""))-1 couleur = QColor(QColorDialog(self.fenetre.ui.vuePlateau).customColor(index)) if couleur.isValid(): self.majMode("caseMajTerrain", couleur) else: self.majMode("standard") def modeCopieTerrain(self): """enclenche le mode copie de case""" self.majMode("caseCopie") def modeCaseEffet(self): """enclenche le mode de mise a jour de l'ffet actif des cases""" self.majMode("standard") origine = self.sender().objectName() if origine == "effFeu": effet = "brule" elif origine == "effEau": effet = "eau" elif origine == "effGlace": effet = "glace" elif origine == "effPoison": effet = "poison" elif origine == "effEffacer": effet = "aucun" self.majMode("caseMajEffet", effet) self.fenetre.ui.vuePlateau.setFocus() def modeCreationPion(self): """enclenche le mode de creation de pions simples""" self.majMode("pionCreation") def majModePionSupprimer(self): """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)""" self.majMode("pionSupprimer") def modeCreationDecor(self, ligne, col): """enclenche le mode de creation de decors depuis la liste des decors""" index = self.fenetre.ui.listDecors.item(ligne, 0) decor = charger("biblio\\decor", str(index.text().toUtf8())) self.majMode("pionDecorCreation", decor) self.fenetre.ui.vuePlateau.setFocus() def modeCreationCreaturePion(self, ligne, col): """enclenche le mode de creation de pions depuis la liste des creatures""" index = self.fenetre.ui.listCreatures.item(ligne, 0) creature = charger("biblio\\creature", str(index.text().toUtf8())) self.majMode("pionCreation", creature) self.fenetre.ui.vuePlateau.setFocus() def modeMajTerrainCase(self, ligne, col): """enclenche le mode permettant la mise a jour du terrain des cases""" index = self.fenetre.ui.listTerrains.item(ligne, 0) terrain = charger("biblio\\terrain", str(index.text().toUtf8())) self.majMode("caseMajTerrain", terrain) self.fenetre.ui.vuePlateau.setFocus() def majCouleurPion(self): """selectionne une nouvelle couleur""" self.majMode("standard") couleur = self.chercherCouleur() if couleur.isValid(): self.modeParam["couleurPion"] = couleur self.fenetre.ui.pionCouleur.setStyleSheet("QPushButton {backGround:%s}" %(self.modeParam["couleurPion"].name())) def majEpaisseurPinceau(self, epaisseur): """met a jour l'epaisseur du pinceau (en cases)""" self.fenetre.ui.valeurEpaisseurPinceau.setText(QString.fromUtf8(str(epaisseur))) self.epaisseurPinceau = int(epaisseur) def modeMajAltitudeCase(self): self.majMode("caseMajAltitude") def majModeForme(self): """met a jour la forme utilisee pour la peinture""" bouton = self.sender().objectName() if bouton == "formeSimple": self.modeParam["typeFormeDessin"] = "simple" elif bouton == "formeLigne": self.modeParam["typeFormeDessin"] = "ligne" elif bouton == "formeLigneOrientee": self.modeParam["typeFormeDessin"] = "frontiere" elif bouton == "formeEllipseVide": self.modeParam["typeFormeDessin"] = "ellipseV" elif bouton == "formeEllipsePlein": self.modeParam["typeFormeDessin"] = "ellipseP" elif bouton == "formeRectVide": self.modeParam["typeFormeDessin"] = "rectV" elif bouton == "formeRectPlein": self.modeParam["typeFormeDessin"] = "rectP" if self.modeActif[0:7] != "caseMaj": self.majMode("caseMajTerrain", self.modeParam["terrain"]) def majAffichageMenuCache(self): """un bouton 'cache' a ete clique, on met a jour les infos""" origine = self.sender().objectName() index = int(origine.replace("plateauCache","")) self.cacheEnCours = index for i in range(1,5): bouton = self.fenetre.ui.outilsEditionPlateau.findChild(QToolButton, "plateauCache{}".format(i)) bouton.setCheckable(True) bouton.setChecked((i == index)) self.fenetre.ui.cacheActif.setChecked(self.caches[index]["actif"]) self.voirCacheEnCours() def majModeCombatDeplacement(self): """active le mode de combat 'deplacement' (mode standard)""" self.majModeCombat("combatDeplacement") def majModeCombatAttaqueCaC(self): """active le mode de combat 'corps-a-corps'""" self.majModeCombat("combatAttaqueCaC") def majModeCombatAttaqueDist(self): """active le mode de combat 'attaque a distance'""" self.majModeCombat("combatAttaqueDist") def majModeCombatZone(self): if not len(self.modeParam["typeAttaqueZone"]) > 0: self.modeParam["typeAttaqueZone"] = "ligne" self.majModeCombat("combatAttaqueZone") def majModeCombatZoneForme(self): if self.modeCombat == "combatAttaqueZone": origine = self.sender().objectName() self.modeParam["typeAttaqueZone"] = str(origine).split("_")[1] self.majModeCombat("combatAttaqueZone") def majModeDefinirEntree(self): self.modeParam["entreeSortie"] = EntreeSortie(self, "E") self.modeParam["entreeSortie"].creerForme() self.majMode("placementEntreeSortie") def majModeDefinirSortie(self): self.modeParam["entreeSortie"] = EntreeSortie(self, "S") self.modeParam["entreeSortie"].creerForme() self.majMode("placementEntreeSortie") def majModeZonePlacement(self): self.majMode("majZonePlacement") def majMode(self, mode = "standard", param = None): """modifie ou reinitialise le type d'interaction avec le plateau""" reinit = True #doit-on reinitialiser a la fin de l'operation ##on desactive le mode precedent if self.pionSelectionne() != None: self.pionSelectionne().afficheOmbreSelection(False) if self.modeActif == "pionSelectionne": self.majModeCombat("") self.modeParam["numPionSelectionne"] = 0 elif self.pionDecorSelectionne() != None: self.pionDecorSelectionne().afficheOmbreSelection(False) self.modeParam["numPionSelectionne"] = 0 if self.modeActif == "pionSelectionne" or self.modeActif == "pionCreation" or self.modeActif == "pionDecorSelectionne" or self.modeActif == "pionDecorCreation": self.majProjectionPosition(False) self.modeParam["formeProjectionPosition"] = None self.modeParam["coordProjectionPosition"] = None self.modeParam["nbRotations"] = 0 if self.modeActif[0:7] == "caseMaj" or self.modeActif == "cachePlacer" or self.modeActif == "majZonePlacement": if self.modeParam["formeDessin"] != None: self.modeParam["formeDessin"].prepareGeometryChange() self.removeItem(self.modeParam["formeDessin"]) self.modeParam["formeDessin"] = None self.modeParam["origineFormeDessin"] = None self.modeParam["point2FormeDessin"] = None self.afficherListeCases(self.modeParam["listeCasesFormeDessin"], False) self.modeParam["listeCasesFormeDessin"] = [] if self.modeActif == "placementEntreeSortie": if self.modeParam["entreeSortie"] != None: self.modeParam["entreeSortie"].prepareGeometryChange() self.removeItem(self.modeParam["entreeSortie"]) self.modeParam["entreeSortie"] = None ### definition du nouveau mode if mode in self.listMode and mode != "standard": self.modeActif = mode reinit = False if mode == "caseMajTerrain": #curseur pinceau, on ajoute des terrains au cases if param != None: self.curseurPinceau() self.fenetre.ui.vuePlateau.setDragMode(0) self.modeParam["terrain"] = param elif mode == "caseCopie": #curseur seringue, on 'preleve' le terrain sur la case cliquee, avant de passer en mode majTerrain self.curseurSeringue() self.fenetre.ui.vuePlateau.setDragMode(0) elif mode == "caseMajEffet": #on met a jour l'effet actif sur les cases if param != None: self.curseurPinceau() self.fenetre.ui.vuePlateau.setDragMode(0) self.modeParam["effet"] = param elif mode == "caseMajAltitude": self.curseurPinceau() self.fenetre.ui.vuePlateau.setDragMode(0) elif mode == "cachePlacer": self.curseurPinceau() self.fenetre.ui.vuePlateau.setDragMode(0) self.modeParam["typeFormeDessin"] = "rectP" elif mode == "majZonePlacement": self.curseurPinceau() self.fenetre.ui.vuePlateau.setDragMode(0) self.modeParam["typeFormeDessin"] = "rectP" elif mode == "placementEntreeSortie": self.fenetre.ui.vuePlateau.setDragMode(0) elif mode == "pionDecorCreation": #curseur 'plus', on cree de nouveaux decors self.modeParam["decor"] = None self.fenetre.ui.vuePlateau.setDragMode(0) self.modeParam["formeProjectionPosition"] = Forme(self.formeCases) self.modeParam["nbRotations"] = 0 if param != None: if param.__class__.__name__ == "Decor": self.modeParam["decor"] = param self.modeParam["formeProjectionPosition"].definirForme(self.modeParam["decor"].formeDef[self.formeCases]) elif mode == "pionDecorSelectionne": #un pion decor est selectionne if param != None: self.modeParam["numPionSelectionne"] = param self.pionDecorSelectionne().afficheOmbreSelection(True) self.fenetre.ui.vuePlateau.setCursor(QCursor(Qt.ArrowCursor)) self.modeParam["formeProjectionPosition"] = Forme(self.formeCases) self.modeParam["formeProjectionPosition"].definirForme(self.pionDecorSelectionne().forme.formeDef) self.modeParam["nbRotations"] = self.pionDecorSelectionne().nbRotations elif mode == "pionCreation": #curseur 'plus', on cree de nouveaux pions self.modeParam["creature"] = None self.fenetre.ui.vuePlateau.setDragMode(0) self.modeParam["formeProjectionPosition"] = Forme(self.formeCases) self.modeParam["nbRotations"] = 0 if param != None: if param.__class__.__name__ == "Creature": self.modeParam["creature"] = param self.modeParam["formeProjectionPosition"].definirForme(self.modeParam["creature"].formeDef[self.formeCases]) elif mode == "pionSupprimer": #mode suppression de pions/pions decors self.curseurGomme() self.fenetre.ui.vuePlateau.setDragMode(0) elif mode == "pionSelectionne": #un pion est selectionne, on affiche les deplacements possibles if param != None: self.modeParam["numPionSelectionne"] = param self.pionSelectionne().afficheOmbreSelection(True) self.numPionEnCours = param for i in range(0, self.fenetre.ui.infoOrdreJeu.rowCount()): if str(self.fenetre.ui.infoOrdreJeu.item(i, 0).text().toUtf8()) == str(param): self.fenetre.ui.infoOrdreJeu.setCurrentCell(i,0) self.majAffichagePionSelectionne() self.majListeAttributs() self.afficherNotesPion() self.majListeAttaques() self.majModeCombat("aucun") elif not mode in self.listMode: print("mode non reconnu") ##on reinitialise si necessaire if reinit: #mode standard : pas d'interaction avec les cases, on deplace le plateau en le saisissant ou les pions en cliquant dessus self.modeActif = "standard" self.majAffichagePionSelectionne() self.majInfosPion() self.majInfosDecor() self.majListeAttributs() self.majListeAttaques() self.afficherNotesPion() self.fenetre.majVisibiliteBarreCombat("menu") QApplication.processEvents() self.fenetre.ui.vuePlateau.setCursor(QCursor(Qt.ArrowCursor)) self.fenetre.ui.vuePlateau.setDragMode(1) else: self.fenetre.ui.vuePlateau.setFocus() def majModeCombat(self, mode = ""): """met a jour le mode de combat actif pour le pion selectionne""" ## on desactive le mode precedent si besoin #la projection de position if self.modeCombat == "combatDeplacement": #le champ de deplacement if self.modePrincipal == "combat": self.afficherChampDeplacement(False) self.majProjectionPosition(False) self.modeParam["formeProjectionPosition"] = None self.modeParam["coordProjectionPosition"] = None self.modeParam["nbRotations"] = 0 elif self.modeCombat == "combatAttaqueCaC": #la zone d'attaque au cac self.materialiserPions(True) self.majZoneAttaqueCaC(False) self.modeParam["zoneAttaqueCaC"] = [] if self.modeParam["cibleAttaqueCaC"] != None: self.modeParam["cibleAttaqueCaC"].estCibleAttaque(False) self.modeParam["cibleAttaqueCaC"] = None elif self.modeCombat == "combatAttaqueDist": self.materialiserPions(True) self.majLigneMireAttaqueDist() elif self.modeCombat == "combatAttaqueZone": #l'attaque de zone self.materialiserPions(True) QApplication.processEvents() self.reinitAttaqueZone() if mode != "combatAttaqueZone": self.fenetre.majVisibiliteBarreCombat("menu") self.modeParam["listeCasesAttaqueZone"] = [] ## maj de l'aspect des boutons selon le mode demande for item in self.fenetre.ui.barreBasCombat.children(): if item.__class__.__name__ == "QToolButton": if item.isCheckable(): item.setChecked((item.objectName() == mode and self.pionSelectionne() != None)) if mode == "combatAttaqueZone": item.setChecked((item.objectName() == "combatZone_{}".format(self.modeParam["typeAttaqueZone"])\ and self.pionSelectionne() != None)) ## definition du nouveau mode de combat if self.pionSelectionne() != None: self.modeCombat = mode self.fenetre.ui.vuePlateau.setDragMode(0) self.fenetre.ui.combatVol_altitude.setValue(self.pionSelectionne().z) if mode == "aucun": self.fenetre.ui.vuePlateau.setCursor(QCursor(Qt.ArrowCursor)) if mode == "combatDeplacement": self.fenetre.ui.vuePlateau.setCursor(QCursor(Qt.ArrowCursor)) self.modeParam["formeProjectionPosition"] = Forme(self.formeCases) self.modeParam["formeProjectionPosition"].definirForme(self.pionSelectionne().forme.formeDef) self.modeParam["nbRotations"] = self.pionSelectionne().nbRotations if self.modePrincipal == "combat": #si mode combat, affichage de la zone de deplacement self.afficherChampDeplacement(True) elif mode == "combatAttaqueCaC": self.curseurEpee() self.materialiserPions(False) self.modeParam["zoneAttaqueCaC"] = self.zone(self.pionSelectionne().position, self.pionSelectionne().creature.allonge, True, True) self.majZoneAttaqueCaC(True) elif mode == "combatAttaqueDist": self.curseurArc() self.materialiserPions(False) elif mode == "combatAttaqueZone": self.curseurBaguette() self.materialiserPions(False) self.majFormeAttaqueZone() else: self.fenetre.ui.combatVol_altitude.setValue(0) ############### ########## Gestion du combat ############## def majAffichageTour(self): """met a jour l'affichage du tour en cours""" self.fenetre.ui.combatTour.setText(QString.fromUtf8("Tour: {}".format(self.tour))) def majAffichagePionSelectionne(self): """affiche le nom et le logo du pion actuellement selectionne""" if self.pionSelectionne() != None: self.fenetre.ui.combatPionSelectionne.setText(QString.fromUtf8(self.pionSelectionne().txtId())) if len(self.pionSelectionne().creature.img["nom"]) > 0: pix = QPixmap(QString.fromUtf8("img\\"+self.pionSelectionne().creature.img["nom"])) pix = pix.scaled(44, 44, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.fenetre.ui.combatPionSelectionne_img.setPixmap(pix) else: self.fenetre.ui.combatPionSelectionne_img.setPixmap(QPixmap()) else: self.fenetre.ui.combatPionSelectionne_img.setPixmap(QPixmap()) self.fenetre.ui.combatPionSelectionne.setText(QString.fromUtf8("Pas de pion selectionné")) def initListeOrdreJeu(self): """cree les colonnes et met en forme la table ordre jeu""" ## self.fenetre.ui.infoOrdreJeu.setColumnWidth(0, 20) self.fenetre.ui.infoOrdreJeu.setColumnWidth(2, 30) self.fenetre.ui.infoOrdreJeu.hideColumn(0) ## self.fenetre.ui.infoOrdreJeu.hideColumn(2) self.fenetre.ui.infoOrdreJeu.setIconSize(QSize(30,20)) def majListeOrdreJeu(self): """met a jour la liste des pions infoOrdreJeu""" while self.fenetre.ui.infoOrdreJeu.rowCount() > 0: self.fenetre.ui.infoOrdreJeu.removeRow(0) index = 0 for num in self.ordreJeu: self.fenetre.ui.infoOrdreJeu.insertRow(int(index)) self.fenetre.ui.infoOrdreJeu.setItem(int(index), 0, QTableWidgetItem(QString.fromUtf8(str(num)))) icon = QIcon("img\\"+self.pions[num].creature.logo) item = QTableWidgetItem(icon,QString.fromUtf8(self.pions[num].txtId())) self.fenetre.ui.infoOrdreJeu.setItem(int(index), 1, item) self.fenetre.ui.infoOrdreJeu.setItem(int(index), 2, QTableWidgetItem(QString.fromUtf8(str(self.ordreJeu[num])))) index += 1 self.fenetre.ui.infoOrdreJeu.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""" numPion = int(self.fenetre.ui.infoOrdreJeu.item(ligne, 0).text().toUtf8()) self.fenetre.ui.vuePlateau.centerOn(self.cases[self.pions[numPion].position].centreGraphique) self.pionSaisir(numPion) def pionSuivant(self): """selection du pion suivant dans la liste d'ordre de jeu""" if self.numPionEnCours in self.pions: 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: numPion = num break for ligne in range(0, self.fenetre.ui.infoOrdreJeu.rowCount()): item = self.fenetre.ui.infoOrdreJeu.item(ligne, 0) item.setSelected(int(self.fenetre.ui.infoOrdreJeu.item(ligne, 0).text().toUtf8()) == numPion) if int(item.text().toUtf8()) == numPion: self.fenetre.ui.infoOrdreJeu.scrollToItem(item) self.fenetre.ui.vuePlateau.centerOn(self.cases[self.pions[numPion].position].centreGraphique) self.pionSaisir(numPion) def afficheEcranGestionCombat(self): #*egc """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 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""" attribut = regles.attributOrdreJeu() if attribut != None: dico = {} for numPion in self.pions: dico[numPion] = int(self.pions[numPion].lstCarac[attribut]) ordre = sorted(dico, key = dico.get, reverse=(regles.sensTriOrdreJeu() == 1)) self.ordreJeu = {} for numPion in self.pions: self.ordreJeu[numPion] = ordre.index(numPion) + 1 self.majListeOrdreJeu() def pionDeplacerDansOrdreJeu(self, numPion, 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 numPion in self.ordreJeu: if nouvellePosition == 0: del self.ordreJeu[numPion] if len(self.ordreJeu) > 0: i = 0 tmp = sorted(self.ordreJeu, key=self.ordreJeu.get) if numPion in tmp: tmp.remove(numPion) for num in tmp: i += 1 if i == nouvellePosition: self.ordreJeu[numPion] = i i += 1 self.ordreJeu[num] = i if i < nouvellePosition: self.ordreJeu[numPion] = i + 1 elif nouvellePosition > 0: self.ordreJeu[numPion] = 1 self.majOrdreJeu() def majListeAttributs(self): """met a jour la liste des attributs dans le panneau de combat""" self.fenetre.ui.listeAttributs.setColumnWidth(0, (0.4*self.fenetre.ui.listeAttributs.width())) self.fenetre.ui.listeAttributs.setColumnWidth(1, (0.4*self.fenetre.ui.listeAttributs.width())) self.disconnect(self.fenetre.ui.listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee) #on vide la liste while self.fenetre.ui.listeAttributs.rowCount() > 0: self.fenetre.ui.listeAttributs.removeRow(0) self.fenetre.ui.listeAttributs.setVisible((self.pionSelectionne() != None)) if self.pionSelectionne() != None: #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.listeAttributs.insertRow(i) item = QTableWidgetItem() if i < len(lignesBase): item.setText(QString.fromUtf8(lignesBase[i])) item.setFlags(Qt.NoItemFlags) self.fenetre.ui.listeAttributs.setItem(i, 0, item) self.fenetre.ui.listeAttributs.setRowHidden(i, (i >= len(lignesBase))) #maj des donnees de base self.fenetre.ui.listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom)))) self.fenetre.ui.listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat)))) self.fenetre.ui.listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().z)))) #attributs issus des regles utilisees ordre = regles.ordreAttributs() for elt in ordre: ligne = 10 + ordre.index(elt) self.fenetre.ui.listeAttributs.insertRow(ligne) item = QTableWidgetItem(QString.fromUtf8(elt)) item.setFlags(Qt.NoItemFlags) self.fenetre.ui.listeAttributs.setItem(ligne, 0, item) self.fenetre.ui.listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().lstCarac[elt])))) self.connect(self.fenetre.ui.listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee) def listeAttributCelluleModifiee(self, ligne, colonne): """une cellule de la liste des attributs a ete modifiee""" 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.listeAttributs.item(ligne, 1).text().toUtf8()) valVerifiee = regles.listeControle()[attribut].controler(nouvelleVal) if valVerifiee != None: self.pionSelectionne().lstCarac[attribut] = valVerifiee if attribut == regles.attributOrdreJeu(): print("maj ordre (a implementer)") else: self.fenetre.ui.listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().lstCarac[attribut])))) def initListeAttaques(self): """met en forme et connecte la liste des attaques du pion""" self.fenetre.ui.listeAttaques.setColumnWidth(0, 0) self.fenetre.ui.listeAttaques.setColumnWidth(1, (0.3*self.fenetre.ui.listeAttaques.width())) self.fenetre.ui.listeAttaques.setColumnWidth(2, (0.7*self.fenetre.ui.listeAttaques.width())) self.connect(self.fenetre.ui.listeAttaques, SIGNAL("itemSelectionChanged()"), self.majInfosAttaqueEC) self.connect(self.fenetre.ui.listeAttaques, SIGNAL("cellClicked(int, int)"), self.listeAttaquesCelluleCliquee) self.connect(self.fenetre.ui.notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC) self.fenetre.ui.listeAttributsAttaqueEC.setColumnWidth(0, (0.49*self.fenetre.ui.listeAttributsAttaqueEC.width())) self.fenetre.ui.listeAttributsAttaqueEC.setColumnWidth(1, (0.5*self.fenetre.ui.listeAttributsAttaqueEC.width())) def majListeAttaques(self): #*eea """met a jour la liste des attaques du pion dans le panneau de combat""" #on vide la liste while self.fenetre.ui.listeAttaques.rowCount() > 0: self.fenetre.ui.listeAttaques.removeRow(0) self.fenetre.ui.listeAttaques.setVisible((self.pionSelectionne() != None)) self.fenetre.ui.titreAttaques.setVisible((self.pionSelectionne() != None)) self.fenetre.ui.editerAttaques.setVisible((self.pionSelectionne() != None)) self.fenetre.ui.panneauAttaqueEC.setVisible((self.pionSelectionne() != None)) i = 0 if self.pionSelectionne() != None: for attaque in self.pionSelectionne().attaques: self.fenetre.ui.listeAttaques.insertRow(i) self.fenetre.ui.listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque))))) icone = None if attaque.typ == "cac": icone = QIcon("img\\curseurEpee.png") if attaque.typ == "dist": icone = QIcon("img\\arc.png") if attaque.typ == "zone": icone = QIcon("img\\baguette.png") if icone != None: self.fenetre.ui.listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8(""))) self.fenetre.ui.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.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.fenetre.ui.combatZone_disqueRayon.setValue(attaque.rayon) self.majModeCombat("combatAttaqueZone") def majInfosAttaqueEC(self): #*aec """met a jour les infos de l'attaque en cours (selectionnee)""" selection = self.fenetre.ui.listeAttaques.selectedItems() self.fenetre.ui.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.listeAttaques.item(ligne, 0).text().toUtf8())) self.disconnect(self.fenetre.ui.listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee) #on vide la liste while self.fenetre.ui.listeAttributsAttaqueEC.rowCount() > 0: self.fenetre.ui.listeAttributsAttaqueEC.removeRow(0) self.fenetre.ui.listeAttributsAttaqueEC.insertRow(0) self.fenetre.ui.listeAttributsAttaqueEC.setItem(0, 0, QTableWidgetItem(QString.fromUtf8("numAtt"))) self.fenetre.ui.listeAttributsAttaqueEC.setItem(0, 1, QTableWidgetItem(QString.fromUtf8(str(numAttaque)))) self.fenetre.ui.listeAttributsAttaqueEC.setRowHidden(0, True) #attributs issus des regles utilisees ordre = regles.ordreAttributsAttaques() for elt in ordre: ligne = 1 + ordre.index(elt) self.fenetre.ui.listeAttributsAttaqueEC.insertRow(ligne) item = QTableWidgetItem(QString.fromUtf8(elt)) item.setFlags(Qt.NoItemFlags) self.fenetre.ui.listeAttributsAttaqueEC.setItem(ligne, 0, item) self.fenetre.ui.listeAttributsAttaqueEC.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques[numAttaque].attributs[elt])))) self.connect(self.fenetre.ui.listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee) #maj des notes self.disconnect(self.fenetre.ui.notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC) self.fenetre.ui.notesAttaqueEC.setText(QString.fromUtf8(self.pionSelectionne().attaques[numAttaque].notes)) self.connect(self.fenetre.ui.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.listeAttaques.selectedItems() self.fenetre.ui.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.listeAttaques.item(ligne, 0).text().toUtf8())) self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.notesAttaqueEC.toPlainText().toUtf8()) def afficheEcranEditionAttaques(self): """affiche l'ecran d'edition/creation d'attaques""" if self.pionSelectionne() != None: self.editionAttaques = QDialog() frame = EcranEditionAttaques(self.pionSelectionne()) frame.setParent(self.editionAttaques) self.editionAttaques.setAttribute(Qt.WA_DeleteOnClose) r = self.editionAttaques.exec_() del self.editionAttaques self.majListeAttaques() def majNotesPion(self): """les notes du pion ont ete mises a jour""" if self.pionSelectionne() != None: self.pionSelectionne().notes = str(self.fenetre.ui.notesPion.toPlainText().toUtf8()) else: pass def afficherNotesPion(self): """affiche les notes du pion selectionne dans le QTextEdit dedie""" self.fenetre.ui.notesPion.setVisible((self.pionSelectionne() != None)) if self.pionSelectionne() != None: self.fenetre.ui.notesPion.setText(QString.fromUtf8(self.pionSelectionne().notes)) ############### ############### fonctions de calcul ################ def zone(self, origine, distance, z=0, conditionFranchissable = False, conditionVisible = False): """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 z = 0 -> hauteur z de l'origine par rapport a l'altitude de la case conditionFranchissable = Vrai -> les cases infranchissables ne sont pas prises en compte conditionVisible = Vrai -> les cases bloquant la visibilite ne sont pas prises en compte [cf methode A* (A-star)]""" aVerifier = [] aVerifier2 = [] resultat = {} k = 0 #on part de la premiere case, puis on itere a partir de chaque nouveau depart if origine in self.cases: aVerifier.append(origine) while k <= distance: 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: if conditionFranchissable and not conditionVisible: if self.cases[coord].estFranchissable(z): aVerifier2.append(coord) elif not conditionFranchissable and conditionVisible: if self.cases[coord].terrain.visibilite: aVerifier2.append(coord) elif conditionFranchissable and conditionVisible: if self.cases[coord].estFranchissable(z) and self.cases[coord].terrain.visibilite: aVerifier2.append(coord) else: aVerifier2.append(coord) for elt in aVerifier: resultat[elt] = k aVerifier = aVerifier2 aVerifier2 = [] k += 1 return resultat 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 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)""" pointsPolygone = [] segments = [] case = Case(self) #on verifie que toutes les cases sont adjacentes les unes aux autres valide = True if len(listeCases) > 1: for coord in listeCases: if not len(set(listeCases).intersection(self.lstCoordAdjacentes(coord[0], coord[1]))) > 0: valide = False if not len(listeCases) > 0: valide = False if valide: #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 = case.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 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) else: polygone = None return polygone 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": voisins = [(x, y-1), (x+1, y-0.5), (x+1, y+0.5), (x, y+1), (x-1, y+0.5), (x-1, y-0.5)] else: voisins = [(x, y-1), (x+1, y), (x, y+1), (x-1, y)] return voisins 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""" coord = None if point != None: lstObjets = self.fenetre.ui.vuePlateau.scene().items(point) for objet in lstObjets: if objet: if objet.__class__.__name__ == "Case": coord = (objet.x, objet.y) break return coord def creerOrigineFormeDessin(self, coord): """place le point d'origine de la forme de selection""" self.modeParam["listeCasesFormeDessin"] = [] self.modeParam["origineFormeDessin"] = self.cases[coord].centreGraphique self.modeParam["point2FormeDessin"] = self.cases[coord].centreGraphique self.modeParam["listeCasesFormeDessin"] = [coord] self.afficherListeCases(self.modeParam["listeCasesFormeDessin"], True) def majFormeDessin(self): """cree/maj la forme utilisee pour selectionner les cases et met a jour la liste des cases selectionnes""" self.afficherListeCases(self.modeParam["listeCasesFormeDessin"], False) pinceau = QPen() pinceau.setColor(QColor("black")) point2 = self.modeParam["point2FormeDessin"] if self.modeParam["typeFormeDessin"] == "simple": #pas de forme: on ajoute les cases survolees a la liste des cases coordPoint2 = self.coordonneesAuPoint(point2) zone = self.zone(coordPoint2, self.epaisseurPinceau-1) for coord in zone: if not coord in self.modeParam["listeCasesFormeDessin"]: self.modeParam["listeCasesFormeDessin"].append(coord) elif self.modeParam["typeFormeDessin"] == "frontiere": #droite qui selectionne toutes les cases situees au dessus d'elle if self.modeParam["formeDessin"] == None: self.modeParam["formeDessin"] = QGraphicsLineItem() self.modeParam["formeDessin"].setPen(pinceau) self.addItem(self.modeParam["formeDessin"]) ligne = QLineF(self.modeParam["origineFormeDessin"], point2) orientation = int((1+int(ligne.angle()/22.5))/2) ligne.setAngle(orientation*45) self.modeParam["formeDessin"].setLine(ligne) self.modeParam["listeCasesFormeDessin"] = self.selectionFrontiere() else: if self.modeParam["typeFormeDessin"] == "ligne": #segment simple if self.modeParam["formeDessin"] == None: self.modeParam["formeDessin"] = QGraphicsLineItem() self.modeParam["formeDessin"].setPen(pinceau) self.modeParam["formeDessin"].prepareGeometryChange() self.addItem(self.modeParam["formeDessin"]) ligne = QLineF(self.modeParam["origineFormeDessin"], point2) self.modeParam["formeDessin"].setLine(ligne) elif self.modeParam["typeFormeDessin"] == "rectV" or self.modeParam["typeFormeDessin"] == "rectP": #rectangle if self.modeParam["formeDessin"] == None: self.modeParam["formeDessin"] = QGraphicsRectItem() self.modeParam["formeDessin"].prepareGeometryChange() self.modeParam["formeDessin"].setPen(pinceau) self.addItem(self.modeParam["formeDessin"]) rect = self.rectFormeDessin(self.modeParam["origineFormeDessin"], point2) self.modeParam["formeDessin"].setRect(rect) elif self.modeParam["typeFormeDessin"] == "ellipseV" or self.modeParam["typeFormeDessin"] == "ellipseP": #ellipse if self.modeParam["formeDessin"] == None: self.modeParam["formeDessin"] = QGraphicsEllipseItem() self.modeParam["formeDessin"].prepareGeometryChange() self.modeParam["formeDessin"].setPen(pinceau) self.addItem(self.modeParam["formeDessin"]) rect = self.rectFormeDessin(self.modeParam["origineFormeDessin"], point2) self.modeParam["formeDessin"].setRect(rect) #on liste les cases intersectant la forme plein = (self.modeParam["typeFormeDessin"][len(self.modeParam["typeFormeDessin"])-1:] == "P") self.modeParam["listeCasesFormeDessin"] = self.casesSousForme(self.modeParam["formeDessin"], plein, self.epaisseurPinceau - 1) self.afficherListeCases(self.modeParam["listeCasesFormeDessin"], True) def casesSousForme(self, forme, plein = True, epaisseur = 0): """renvoie la liste des cases en collision avec un QGraphicsItem en parametre plein = False: pas le contenu de la forme epaisseur = renvoie aussi les cases voisines jusqu'a la distance demandee""" tmp = [] listeCases = [] point1 = None point2 = None #point 1 et 2 if forme.__class__.__name__ == "QGraphicsLineItem": point1 = forme.line().p1() point2 = forme.line().p2() elif forme.__class__.__name__ == "QGraphicsRectItem" or forme.__class__.__name__ == "QGraphicsEllipseItem": point1 = forme.rect().topLeft() point2 = forme.rect().bottomRight() else: point1 = forme.boundingRect().topLeft() point2 = forme.boundingRect().bottomRight() #preselection des cases (meilleures perf) if point1 != None and point2 != None and point1 != point2: preSelection = self.preSelectionCollision(point1, point2) else: preSelection = [] for coord in self.cases: preSelection.append(coord) #on liste les cases en collision avec la forme for coord in preSelection: if self.cases[coord].collidesWithItem(forme, Qt.IntersectsItemShape): if plein: tmp.append(coord) else: contenu = True for i in range(0,len(self.cases[coord].polygon())): if not forme.contains(self.cases[coord].polygon().at(i)): contenu = False break if contenu == False: tmp.append(coord) #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire if not plein and epaisseur > 0: for coord in tmp: zone = self.zone(coord, epaisseur) for coord2 in zone: if not coord2 in listeCases: listeCases.append(coord2) else: listeCases = tmp #si la liste est vide, on ajoute l'origine de la forme if len(listeCases) == 0: listeCases = [self.coordonneesAuPoint(point1)] return listeCases def preSelectionCollision(self, point1, point2): """renvoie une liste des cases qui peuvent etre concernees par une collision avec un graphicsItem (pour des raisons de performance)""" preSelection = [] coord1 = self.coordonneesAuPoint(point1) coord2 = self.coordonneesAuPoint(point2) if coord1 != None and coord2 != None: minX = min(coord1[0], coord2[0]) - 1 maxX = max(coord1[0], coord2[0]) + 1 minY = min(coord1[1], coord2[1]) - 1 maxY = max(coord1[1], coord2[1]) + 1 for coord in self.cases: if coord[0] >= minX and coord[0] <= maxX and coord[1] >= minY and coord[1] <= maxY : preSelection.append(coord) else: preSelection = self.cases return preSelection def selectionFrontiere(self): """retourne les cases selectionnees lors de l'utilisation de la forme 'frontiere'""" listeCases = [] ligne = self.modeParam["formeDessin"].line() normale = ligne.normalVector() normale = normale.unitVector() coordOrigine = self.coordonneesAuPoint(self.modeParam["origineFormeDessin"]) dx = normale.p2().x() - normale.p1().x() dy = normale.p2().y() - normale.p1().y() for coord in self.cases: if dx < 0 and dy == 0: #normale pointe vers la gauche if (coord[0] - coordOrigine[0]) <= 0: listeCases.append(coord) if dx > 0 and dy == 0: #normale pointe vers la droite if (coord[0] - coordOrigine[0]) >= 0: listeCases.append(coord) if dx == 0 and dy < 0: #pointe vers le haut (rappel: axe y vers le bas) if (coord[1] - coordOrigine[1]) <= 0: listeCases.append(coord) elif dx == 0 and dy > 0: #pointe vers le bas if (coord[1] - coordOrigine[1]) >= 0: listeCases.append(coord) if dx > 0 and dy < 0: #pointe vers le haut droite if (coord[0] - coordOrigine[0]) + -1*(coord[1] - coordOrigine[1]) >= 0: listeCases.append(coord) elif dx > 0 and dy > 0: #pointe vers le bas droite if -1*(coord[0] - coordOrigine[0]) + -1*(coord[1] - coordOrigine[1]) <= 0: listeCases.append(coord) if dx < 0 and dy < 0: #pointe vers le haut gauche if (coord[0] - coordOrigine[0]) + (coord[1] - coordOrigine[1]) <= 0: listeCases.append(coord) elif dx < 0 and dy > 0: #pointe vers le bas gauche if -1*(coord[0] - coordOrigine[0]) + (coord[1] - coordOrigine[1]) >= 0: listeCases.append(coord) return listeCases def validerFormeDessin(self): """la projection des cases a peindre a ete acceptee, on peint ces cases""" if self.modeActif[0:7] == "caseMaj" or self.modeActif == "caseCopie" or self.modeActif == "cachePlacer" or self.modeActif == "majZonePlacement": self.majListeCases(self.modeParam["listeCasesFormeDessin"]) self.majMode(self.modeActif) ## self.majMode("standard") def rectFormeDessin(self, point1, point2): """retourne le rectangle repesentant la forme de selection determine pour ce faire les points A et B, cad le point haut-droit et le point bas-gauche""" pointA = QPointF(min(point1.x(), point2.x()), min(point1.y(), point2.y())) pointB = QPointF(max(point1.x(), point2.x()), max(point1.y(), point2.y())) rect = QRectF(pointA, pointB) return rect def majLigneMireAttaqueDist(self, coordCible = None): """met a jour la ligne de mire representant l'attaque a distance""" if self.modeParam["cibleAttaqueDist"] != None and self.modeParam["cibleAttaqueDist"] != coordCible: self.cases[self.modeParam["cibleAttaqueDist"]].majEstCibleCurseur(False) ## if self.modeParam["pionCibleAttaqueDist"] != None and self.modeParam["pionCibleAttaqueDist"] != self.cases[coordCible].pionOccupant(): if self.modeParam["pionCibleAttaqueDist"] != None: self.modeParam["pionCibleAttaqueDist"].estCibleAttaque(False) if coordCible != None and self.pionSelectionne() != None and self.modeCombat == "combatAttaqueDist": if coordCible == None: coordCible = pion.position if coordCible != self.modeParam["cibleAttaqueDist"]: if self.modeParam["ligneAttaqueDist"] == None: self.modeParam["ligneAttaqueDist"] = QGraphicsLineItem() self.modeParam["ligneAttaqueDist"].setZValue(100) pinceau = QPen() pinceau.setWidth(6) self.modeParam["ligneAttaqueDist"].setPen(pinceau) self.modeParam["ligneAttaqueDist"].prepareGeometryChange() self.addItem(self.modeParam["ligneAttaqueDist"]) z = 0 pionSurCase = self.cases[coordCible].pionOccupant() if pionSurCase != None: z = pionSurCase.z cibleValide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, coordCible, z) if pionSurCase != None: pionSurCase.estCibleAttaque(True, cibleValide) self.modeParam["pionCibleAttaqueDist"] = pionSurCase else: self.cases[coordCible].majEstCibleCurseur(True, cibleValide) self.modeParam["cibleAttaqueDist"] = coordCible point1 = self.cases[self.pionSelectionne().position].centreGraphique point2 = self.cases[coordCible].centreGraphique ligne = QLineF(point1, point2) self.modeParam["ligneAttaqueDist"].setLine(ligne) else: if self.modeParam["ligneAttaqueDist"] != None: self.modeParam["ligneAttaqueDist"].prepareGeometryChange() self.removeItem(self.modeParam["ligneAttaqueDist"]) self.modeParam["ligneAttaqueDist"] = None self.modeParam["cibleAttaqueDist"] = None ## if pion == None: ## self.modeParam["pionCibleAttaqueDist"] = None def estCibleAttaqueDistValide(self, coordOrigine, coordCible, zPion = 0): """la case cible est elle valide pour une attaque a distance depuis la position et hauteur du pion selectionne? on compare pour ce faire les altitudes des cases sur la ligne de mire""" casesLigneMire = [] #on preselectionne les cases concernees preSelection = self.preSelectionCollision(self.cases[coordOrigine].centreGraphique, self.cases[coordCible].centreGraphique) if coordOrigine in preSelection: preSelection.remove(coordOrigine) if coordCible in preSelection: preSelection.remove(coordCible) for coord in preSelection: ligne = QLineF(self.cases[coordOrigine].centreGraphique, self.cases[coordCible].centreGraphique) ligneGraphique = QGraphicsLineItem(ligne) ligneGraphique.prepareGeometryChange() self.addItem(ligneGraphique) if self.cases[coord].collidesWithItem(ligneGraphique, Qt.IntersectsItemShape): casesLigneMire.append(coord) self.removeItem(ligneGraphique) del ligneGraphique #on trie les cases par distance au point d'origine (de la plus proche a la plus eloignee) casesLigneMireDistance = {} #distance: coord for coord in casesLigneMire: distance = sqrt((coordOrigine[0] - coord[0])**2 + (coordOrigine[1] - coord[1])**2) casesLigneMireDistance[coord] = distance #on compare enfin les altitudes de chaque case en fonction de la distance zOrigine = self.cases[coordOrigine].altitude + self.pionSelectionne().z + self.pionSelectionne().creature.hauteur zCible = self.cases[coordCible].altitude + zPion distanceTot = sqrt((coordCible[0] - coordOrigine[0])**2 + (coordCible[1] - coordOrigine[1])**2) valide = True for coord in casesLigneMireDistance: if self.cases[coord].terrain.visibilite == False: valide = False break else: if zOrigine >= zCible: z = (zOrigine - zCible) * (casesLigneMireDistance[coord] / distanceTot) else: z = (zCible - zOrigine) * ((distanceTot - casesLigneMireDistance[coord]) / distanceTot) if self.cases[coord].estOccupee(int(z)): if self.modeParam["pionCibleAttaqueDist"] != None: if self.cases[coord].estOccupeePar(int(z)) != self.modeParam["pionCibleAttaqueDist"]: valide = False else: valide = False break return valide def validerAttaqueDist(self): """on essaie de valider une attaque a distance vers un pion ou une case""" if self.modeParam["pionCibleAttaqueDist"] != None: msg = "{} attaque a distance le pion {}".format(self.pionSelectionne().txtId(), self.modeParam["pionCibleAttaqueDist"].txtId()) valide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, self.modeParam["cibleAttaqueDist"], self.modeParam["pionCibleAttaqueDist"].z) else: msg = "{} attaque a distance la case {}".format(self.pionSelectionne().txtId(), self.modeParam["cibleAttaqueDist"]) valide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, self.modeParam["cibleAttaqueDist"]) if not valide: msg += " [INVALIDE]" print(msg) self.majModeCombat("aucun") def rectEllipseCirculaire(self, centre, rayon): """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et verticalement le nombre de cases demandees""" rect = QRectF() if rayon > 0: p1 = QPointF((centre.x() - (rayon*self.hCase)), (centre.y() - (rayon*self.hCase))) p2 = QPointF((centre.x() + (rayon*self.hCase)), (centre.y() + (rayon*self.hCase))) rect.setTopLeft(p1) rect.setBottomRight(p2) else: rect = None return rect def polygoneCone(self, point1, point2): """renvoie le polygone du cone defini par les deux points (origine, distance)""" ligne1 = QLineF(point1, point2) longueur = ligne1.length() ligne1.setAngle(ligne1.angle() + 22.5) ligne1.setLength(1.1547*longueur) ligne2 = QLineF(point1, point2) ligne2.setAngle(ligne2.angle() - 22.5) ligne2.setLength(1.1547*longueur) polygone = QPolygonF() polygone.append(point1) polygone.append(ligne1.p2()) polygone.append(ligne2.p2()) return polygone def majFormeAttaqueZone(self): """cree la forme de l'attaque de zone""" for coord in self.modeParam["listeCasesAttaqueZone"]: self.cases[coord].majEstCibleAttaque(False) for numPion in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]): self.pions[numPion].estCibleAttaque(False) if self.modeCombat == "combatAttaqueZone" and self.pionSelectionne() != None: if self.modeParam["typeAttaqueZone"] == "ligne": if self.modeParam["formeAttaqueZone"] == None: self.modeParam["origineAttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique self.modeParam["point2AttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique self.modeParam["formeAttaqueZone"] = QGraphicsLineItem() self.modeParam["formeAttaqueZone"].setPen(QPen(QColor("black"))) self.modeParam["formeAttaqueZone"].prepareGeometryChange() self.addItem(self.modeParam["formeAttaqueZone"]) if self.modeParam["origineAttaqueZone"] != self.modeParam["point2AttaqueZone"]: ligne = QLineF(self.modeParam["origineAttaqueZone"], self.modeParam["point2AttaqueZone"]) self.modeParam["formeAttaqueZone"].setLine(ligne) self.modeParam["listeCasesAttaqueZone"] = [] lst = self.casesSousForme(self.modeParam["formeAttaqueZone"],False) for coord in lst: self.modeParam["listeCasesAttaqueZone"].append(coord) #on retire la case du pion selectionne si besoin: if self.pionSelectionne().position in self.modeParam["listeCasesAttaqueZone"]: self.modeParam["listeCasesAttaqueZone"].remove(self.pionSelectionne().position) elif self.modeParam["typeAttaqueZone"] == "disque": if self.modeParam["ligneMireAttaqueZone"] == None: self.modeParam["origineAttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique self.modeParam["point2AttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique self.modeParam["ligneMireAttaqueZone"] = QGraphicsLineItem() self.modeParam["ligneMireAttaqueZone"].setPen(QPen(QColor("black"))) self.modeParam["ligneMireAttaqueZone"].prepareGeometryChange() self.addItem(self.modeParam["ligneMireAttaqueZone"]) if self.modeParam["origineAttaqueZone"] != self.modeParam["point2AttaqueZone"]: ligne = QLineF(self.modeParam["origineAttaqueZone"], self.modeParam["point2AttaqueZone"]) self.modeParam["ligneMireAttaqueZone"].setLine(ligne) coordCible = self.coordonneesAuPoint(self.modeParam["point2AttaqueZone"]) cibleValide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, coordCible) if cibleValide: rayon = self.fenetre.ui.combatZone_disqueRayon.value() if self.modeParam["formeAttaqueZone"] == None: self.modeParam["formeAttaqueZone"] = QGraphicsEllipseItem() self.modeParam["formeAttaqueZone"].setPen(QPen(QColor("black"))) self.modeParam["formeAttaqueZone"].prepareGeometryChange() self.addItem(self.modeParam["formeAttaqueZone"]) rect = self.rectEllipseCirculaire(self.modeParam["point2AttaqueZone"], rayon) self.modeParam["listeCasesAttaqueZone"] = [] if rect != None and rect.bottomRight() != rect.topLeft(): self.modeParam["formeAttaqueZone"].setRect(rect) lst = self.zone(coordCible, rayon, 0) #zone bcp plus rapide que casesSousforme self.modeParam["listeCasesAttaqueZone"] = lst else: self.cases[coordCible].majEstCibleCurseur(True, False) self.modeParam["listeCasesAttaqueZone"] = [] if self.modeParam["formeAttaqueZone"] != None: self.modeParam["formeAttaqueZone"].setVisible(cibleValide == True and rect != None) elif self.modeParam["typeAttaqueZone"] == "cone": if self.modeParam["formeAttaqueZone"] == None: self.modeParam["origineAttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique self.modeParam["point2AttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique self.modeParam["formeAttaqueZone"] = QGraphicsPolygonItem() self.modeParam["formeAttaqueZone"].setPen(QPen(QColor("black"))) self.modeParam["formeAttaqueZone"].prepareGeometryChange() self.addItem(self.modeParam["formeAttaqueZone"]) if self.modeParam["origineAttaqueZone"] != self.modeParam["point2AttaqueZone"]: cone = self.polygoneCone(self.modeParam["origineAttaqueZone"], self.modeParam["point2AttaqueZone"]) self.modeParam["formeAttaqueZone"].setPolygon(cone) lst = self.casesSousForme(self.modeParam["formeAttaqueZone"], True, True) self.modeParam["listeCasesAttaqueZone"] = [] for coord in lst: if coord != self.pionSelectionne().position: self.modeParam["listeCasesAttaqueZone"].append(coord) for coord in self.modeParam["listeCasesAttaqueZone"]: self.cases[coord].majEstCibleAttaque(True) for numPion in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]): self.pions[numPion].estCibleAttaque(True) def validerAttaqueZone(self): """l'attaque de zone est validee""" if self.modeActif == "pionSelectionne" and self.modeCombat == "combatAttaqueZone": for numPion in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]): print("{} a lance une attaque de zone sur {}".format(self.pionSelectionne().nom, self.pionSelectionne().numero , \ self.pions[numPion].nom, self.pions[numPion].numero)) self.majModeCombat("aucun") def reinitAttaqueZone(self): if self.modeParam["formeAttaqueZone"] != None: self.modeParam["formeAttaqueZone"].prepareGeometryChange() self.removeItem(self.modeParam["formeAttaqueZone"]) self.modeParam["formeAttaqueZone"] = None if self.modeParam["ligneMireAttaqueZone"] != None: self.modeParam["ligneMireAttaqueZone"].prepareGeometryChange() self.removeItem(self.modeParam["ligneMireAttaqueZone"]) self.modeParam["ligneMireAttaqueZone"] = None if self.modeParam["point2AttaqueZone"] != None: self.cases[self.coordonneesAuPoint(self.modeParam["point2AttaqueZone"])].majEstCibleCurseur(False) for coord in self.modeParam["listeCasesAttaqueZone"]: self.cases[coord].majEstCibleAttaque(False) for numPion in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]): self.pions[numPion].estCibleAttaque(False) def pionSurCase(self, coord): """renvoie le pion present sur la case, none sinon""" retour = None for num in self.pions: if self.pions[num].position == coord: retour = num return retour def pionsSurListeCase(self, listeCases): """renvoie la liste des pions presents sur la liste de cases""" retour = [] for coord in listeCases: pion = self.cases[coord].pionOccupant() if pion != None and not pion.numero in retour: retour.append(pion.numero) 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].estFranchissable(): listeCases2.append(coord) self.polygoneZonePlacement.setPolygon(self.polygoneAgglo(listeCases2)) self.listeCasesZonePlacement = listeCases def materialiserPions(self,actif): """avtive/desactive la reception par les pions (autres que le pion selectionne) des hover events""" for numPion in self.pions: if numPion != self.modeParam["numPionSelectionne"]: self.pions[numPion].setAcceptsHoverEvents(actif) self.pions[numPion].polygoneGraphique.setAcceptsHoverEvents(actif) for numPion in self.decors: self.decors[numPion].setAcceptsHoverEvents(actif) self.decors[numPion].polygoneGraphique.setAcceptsHoverEvents(actif) ####################### ######## interaction avec les cases, decors et pions ############# def pionSelectionne(self): """renvoie le pion actuellement selectionne""" if self.modeParam["numPionSelectionne"] in self.pions: retour = self.pions[self.modeParam["numPionSelectionne"]] else: retour = None return retour def pionDecorSelectionne(self): """renvoie le pion actuellement selectionne""" if self.modeParam["numPionSelectionne"] in self.decors: retour = self.decors[self.modeParam["numPionSelectionne"]] else: retour = None return retour def caseCliquee(self, coord): """on a clique sur la case (clic gauche)""" accepte = False if coord in self.cases: case = self.cases[coord] if self.modeActif == "caseCopie": if len(case.terrain.nom) > 0: self.majMode("caseMajTerrain", case.terrain) accepte = True else: self.majMode("caseMajTerrain", case.couleur) accepte = True elif self.modeActif[0:7] == "caseMaj" or self.modeActif == "cachePlacer" or self.modeActif == "majZonePlacement": self.creerOrigineFormeDessin(coord) accepte = True elif self.modeActif == "pionDecorSelectionne": if coord != self.pionDecorSelectionne().position: self.pionDeposer(coord) accepte = True elif self.modeActif == "pionSelectionne": if self.modeCombat == "combatDeplacement": if self.pionSelectionne() != None: if coord != self.pionSelectionne().position: self.pionDeposer(coord) accepte = True elif self.modeCombat == "combatAttaqueCaC": if self.modeParam["cibleAttaqueCaC"] in self.modeParam["zoneAttaqueCaC"]: print("{} attaque {} au corps a corps".format(self.pionSelectionne().nom, self.modeParam["cibleAttaqueCaC"])) self.majMode("pionSelectionne", None) accepte = True else: print("cette case est invalide pour une corps a corps") accepte = True elif self.modeCombat == "combatAttaqueDist": self.validerAttaqueDist() accepte = True elif self.modeCombat == "combatAttaqueZone": self.validerAttaqueZone() accepte = True elif self.modeActif == "pionCreation": self.pionCreer(coord) accepte = True elif self.modeActif == "pionDecorCreation": self.pionDecorCreer(coord) accepte = True return accepte def caseSurvolClicEnfonce(self, coordCase): """une case est survolee par le curseur (le clic gauche est enfonce)""" if self.modeActif[0:7] == "caseMaj" or self.modeActif == "cachePlacer" or self.modeActif == "majZonePlacement": if self.cases[coordCase].centreGraphique != self.modeParam["point2FormeDessin"]: if self.modeParam["origineFormeDessin"] == None: self.modeParam["origineFormeDessin"] = self.cases[coordCase].centreGraphique self.modeParam["point2FormeDessin"] = self.cases[coordCase].centreGraphique self.majFormeDessin() def clicGaucheRelache(self): """si une forme de selection etait affichee, elle est validee""" if len(self.modeParam["listeCasesFormeDessin"]) > 0: self.validerFormeDessin() def caseSurvol(self, case): """une case est survole par le curseur, on affiche ses informations dans la zone prevue""" self.majInfosCase(case) if (self.modeActif == "pionSelectionne" and self.modeCombat == "combatDeplacement") or self.modeActif == "pionCreation"\ or self.modeActif == "pionDecorSelectionne" or self.modeActif == "pionDecorCreation": self.majProjectionPosition(False) self.modeParam["coordProjectionPosition"] = (case.x, case.y) self.majProjectionPosition(True) elif self.modeActif == "pionSelectionne" and self.modeCombat == "combatAttaqueDist" and self.modeParam["cibleAttaqueDist"] != (case.x, case.y): self.majLigneMireAttaqueDist((case.x,case.y)) elif self.modeActif == "pionSelectionne" and self.pionSelectionne() != None and self.modeCombat == "combatAttaqueZone": if case.centreGraphique != self.modeParam["point2AttaqueZone"]: self.cases[self.coordonneesAuPoint(self.modeParam["point2AttaqueZone"])].majEstCibleCurseur(False) self.modeParam["point2AttaqueZone"] = case.centreGraphique self.majFormeAttaqueZone() def afficherListeCases(self, listeCases, actif): """met ou non en evidence les cases selectionnees""" for coord in listeCases: self.cases[coord].majEstCibleCurseur(actif) def majListeCases(self, listeCases): """met a jour les cases dont les coordonnees sont dans la liste""" self.afficherListeCases(listeCases, False) if self.modeActif[0:7] == "caseMaj": for coord in listeCases: self.caseMaj(coord) elif self.modeActif == "cachePlacer": self.majAffichageCache(self.cacheEnCours, False) self.caches[self.cacheEnCours]["listeCases"] = listeCases self.majAffichageCache(self.cacheEnCours, True) elif self.modeActif == "majZonePlacement": self.majZonePlacement(listeCases) def caseMaj(self, coordCase): """met a jour la case selon le mode actif (et les cases adjacentes selon l'epaisseur du pinceau)""" if self.modeActif == "caseMajTerrain": if self.modeParam["terrain"] != None: if self.modeParam["terrain"].__class__.__name__ == "Terrain": self.cases[coordCase].majTerrain(self.modeParam["terrain"]) elif self.modeParam["terrain"].__class__.__name__ == "QColor": if self.modeParam["terrain"].isValid(): self.cases[coordCase].majTerrain(None) self.cases[coordCase].majCouleur(self.modeParam["terrain"]) self.cases[coordCase].majAltitude(int(self.fenetre.ui.altitudeCase.value())) elif self.modeActif == "caseMajEffet": self.cases[coordCase].majEffet(self.modeParam["effet"]) elif self.modeActif == "caseMajAltitude": self.cases[coordCase].majAltitude(int(self.fenetre.ui.altitudeCase.value())) def majInfosCase(self, case=None): """met a jour les informations d'un pion dans la zone prevue""" if case != None: if len(case.terrain.nom) > 0: self.fenetre.ui.infoCaseEnCours_terrain.setText(QString.fromUtf8(case.terrain.nom)) else: self.fenetre.ui.infoCaseEnCours_terrain.setText(QString.fromUtf8("Case")) self.fenetre.ui.infoCaseEnCours_coord.setText(QString.fromUtf8("X: {} Y: {}".format(case.x, case.y))) self.fenetre.ui.infoCaseEnCours_altitude.setText(QString.fromUtf8("Alt.: {}".format(case.altitude))) if case.effetActif != "": pix = QPixmap(QString.fromUtf8("img\\"+case.imgEffet[case.effetActif])) pix = pix.scaled(21, 21, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.fenetre.ui.infoCaseEnCours_effetImg.setPixmap(pix) self.fenetre.ui.infoCaseEnCours_effetNom.setText(QString.fromUtf8(case.effetActif)) else: self.fenetre.ui.infoCaseEnCours_effetImg.clear() self.fenetre.ui.infoCaseEnCours_effetNom.clear() self.fenetre.ui.infoCase.setVisible(True) else: self.fenetre.ui.infoCase.setVisible(False) def pionClique(self, numPion): """on a clique sur ce pion""" accepte = False if self.pionSelectionne() != None and self.modeCombat == "combatAttaqueDist": self.validerAttaqueDist() accepte = True elif self.modeActif == "standard" and self.pionSelectionne() == None: self.pionSaisir(numPion) accepte = True return accepte def pionSurvol(self, numPion): """le pion est survole par le curseur, on affiche ses informations dans la zone prevue""" if numPion in self.pions: pion = self.pions[numPion] else: pion = None self.majInfosPion(pion) if self.pionSelectionne() != None and self.modeCombat == "combatAttaqueCaC": self.majProjectionAttaqueCaC(pion) pass if numPion in self.pions: case = self.cases[self.pions[numPion].position] self.caseSurvol(case) def pionDoubleClic(self, numPion): """on a double-clique sur le pion""" accepte = False if self.pionSelectionne() == self.pions[numPion] and self.modeCombat == "aucun": ## self.pionSaisir(numPion) self.majModeCombat("combatDeplacement") accepte = True return accepte def pionCreer(self, coordCase): """creer un jeton aux coordonnees indiquees""" valide = True for coord in self.modeParam["formeProjectionPosition"].listeCases(coordCase): if not coord in self.cases: valide = False else: if not self.cases[coord].estFranchissable(): valide = False if valide: numero = 1 if len(self.pions) > 0: numero = max(self.pions) + 1 pion = Pion(self, numero) if self.modeParam["creature"] != None: nom = self.modeParam["creature"].nom elif len(self.fenetre.ui.pionSimple_nom.text().toUtf8()) > 0: nom = self.fenetre.ui.pionSimple_nom.text().toUtf8() numTxt = self.numeroterNom(nom) self.pions[numero] = pion pion.creer(coordCase[0], coordCase[1], nom, numTxt, self.modeParam["creature"], self.modeParam["couleurPion"], self.modeParam["nbRotations"]) self.pionDeplacerDansOrdreJeu(numero, len(self.ordreJeu) + 2) def numeroterNom(self, nom): """renvoie le nom du pion avec un numero complementaire si necessaire """ i = 1 for numPion in self.pions: if self.pions[numPion].nom == nom: i += 1 if i == 1: retour = "" else: retour = str(i) return retour def pionSaisir(self, numPion): """on saisit un pion""" if numPion != self.modeParam["numPionSelectionne"]: self.majMode("pionSelectionne", numPion) def pionDeposer(self, coordCase): """on depose le pion sur la case voulue""" if self.pionSelectionne() != None: pion = self.pionSelectionne() else: pion = self.pionDecorSelectionne() if pion != None: valide = True for coord in self.modeParam["formeProjectionPosition"].listeCases(coordCase, self.modeParam["nbRotations"]): if coord in self.cases: if not self.cases[coord].estFranchissable(pion.z): if not self.cases[coord].estOccupeePar(pion.z) == pion: #si la case est occupee par le pion qu'on depose, elle est donc valide pour un deplacement valide = False else: valide = False if valide: positionPrecedente = pion.position #mise a jour de la position du pion selon le mode if self.modePrincipal == "combat": ## if coordCase in pion.champDeplacement: ## print("le pion a ete deplace de {} vers {} \n -> soit une distance de {} cases"\ ## "".format(positionPrecedente, coordCase, self.pionSelectionne().champDeplacement[coordCase])) self.majInfosPion() pion.majPosition(coordCase, self.modeParam["nbRotations"]) self.majModeCombat("aucun") else: print("Deplacement impossible!") def afficherChampDeplacement(self, actif): """cree et affiche ou efface et detruit le champ de deplacement du pion selectionne""" if self.pionSelectionne() != None: if actif: self.pionSelectionne().champDeplacement = self.zone(self.pionSelectionne().position, \ self.pionSelectionne().deplacementRestant, \ True) for coord in self.pionSelectionne().champDeplacement: self.cases[coord].majEstDansChampDeplacement(actif) if not actif: self.pionSelectionne().champDeplacement = {} def majInfosPion(self, pionSurvole=None): """met a jour les informations d'un pion dans la zone prevue""" if pionSurvole != None: pion = pionSurvole else: if self.pionSelectionne() != None: pion = self.pionSelectionne() else: pion = None if pion != None: self.fenetre.ui.infoPionEnCours_nom.setText(QString.fromUtf8(pion.nom)) self.fenetre.ui.infoPionEnCours_depRestant.setText(QString.fromUtf8("Dep.: {}".format(pion.deplacementRestant))) if len(pion.creature.img["nom"]) > 0: pix = QPixmap(QString.fromUtf8("img\\"+pion.creature.img["nom"])) pix = pix.scaled(61, 51, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.fenetre.ui.infoPionEnCours_image.setPixmap(pix) self.fenetre.ui.infoPion.setVisible(True) self.fenetre.ui.infoPionEnCours_etourdi.setVisible(False) self.fenetre.ui.infoPionEnCours_brule.setVisible(False) self.fenetre.ui.infoPionEnCours_mouille.setVisible(False) self.fenetre.ui.infoPionEnCours_vol.setVisible((pion.z != 0)) self.fenetre.ui.infoPionEnCours_endormi.setVisible(False) self.fenetre.ui.infoPionEnCours_paralyse.setVisible(False) self.fenetre.ui.infoPionEnCours_entrave.setVisible(False) self.fenetre.ui.infoPionEnCours_mort.setVisible(False) else: self.fenetre.ui.infoPion.setVisible(False) def majZPion(self, valeur): """met a jour l'altitude du pion selectionne""" if self.pionSelectionne() != None: self.pionSelectionne().majZ(valeur) def pionDecorSurvol(self, numPionDecor): """le pion-decor est survole par le curseur, on affiche ses informations dans la zone prevue""" if numPionDecor in self.decors: self.majInfosDecor(self.decors[numPionDecor]) else: self.majInfosDecor(None) def pionDecorSaisir(self, numPionDecor): """on saisit un pion decor (mode creation seulement)""" if numPionDecor != self.modeParam["numPionSelectionne"]: self.majMode("pionDecorSelectionne", numPionDecor) def majInfosDecor(self, pionDecor=None): """met a jour les informations d'un pion dans la zone prevue""" if pionDecor != None: self.fenetre.ui.infoDecorEnCours_nom.setText(QString.fromUtf8(pionDecor.decor.nom)) self.fenetre.ui.infoDecorEnCours_hauteur.setText(QString.fromUtf8("Haut.: {}".format(pionDecor.decor.hauteur))) if len(pionDecor.decor.img["nom"]) > 0: pix = QPixmap(QString.fromUtf8("img\\"+pionDecor.decor.img["nom"])) pix = pix.scaled(61, 51, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.fenetre.ui.infoDecorEnCours_image.setPixmap(pix) self.fenetre.ui.infoDecor.setVisible(True) else: self.fenetre.ui.infoDecor.setVisible(False) def majProjectionPosition(self, activer, z=0): """maj l'affichage de la projection de la position d'un objet avant creation ou deplacement (pion, decor...)""" valide = True possible = True if self.modeParam["formeProjectionPosition"] != None and self.modeParam["coordProjectionPosition"] != None: proj = self.modeParam["formeProjectionPosition"].listeCases(self.modeParam["coordProjectionPosition"], self.modeParam["nbRotations"]) for coord in proj: if not coord in self.cases: valide = False #deplacement valide? (pas d'occupation d'une case hors plateau) if valide == True: for coord in proj: if self.cases[coord].estFranchissable(z) or self.cases[coord].estOccupeePar(z) == self.pionSelectionne(): #la case est franchissable, ou elle ne l'est pas mais est occupée par le pion meme qu'on deplace self.cases[coord].majEstCibleCurseur(activer, True) #on affiche la distance correspondante en bulle-info if activer and self.modeActif == "pionSelectionne" and self.modePrincipal == "combat": if coord in self.pionSelectionne().champDeplacement: msg = "Distance {}".format(self.pionSelectionne().champDeplacement[coord]) QToolTip.showText(QCursor.pos(), msg, self.fenetre.ui.vuePlateau) else: self.cases[coord].majEstCibleCurseur(activer, False) def majProjectionAttaqueCaC(self, pionCible): """affiche ou non la cible de l'attaque au corps a corps, selon sa validite ou non""" if self.modeActif == "pionSelectionne" and self.modeCombat == "combatAttaqueCaC": if pionCible != self.pionSelectionne(): if pionCible != None: conditionPossible = (pionCible.position in self.modeParam["zoneAttaqueCaC"]) pionCible.estCibleAttaque(True, conditionPossible) else: if self.modeParam["cibleAttaqueCaC"] != None: self.modeParam["cibleAttaqueCaC"].estCibleAttaque(False) self.modeParam["cibleAttaqueCaC"] = pionCible def majZoneAttaqueCaC(self, actif = True): """affiche ou non les cases a portee du pion selectionne pour une attaque au corps-a-corps""" for coord in self.modeParam["zoneAttaqueCaC"]: self.cases[coord].majEstDansChampDeplacement(actif) def pionDecorCreer(self, coordCase): """creer un jeton aux coordonnees indiquees""" valide = True for coord in self.modeParam["formeProjectionPosition"].listeCases(coordCase, self.modeParam["nbRotations"]): if not self.cases[coord].estFranchissable(): valide = False if valide: numero = 10001 if len(self.decors) > 0: numero = max(self.decors) + 10001 pionDecor = PionDecor(self, numero) pionDecor.creer(coordCase[0], coordCase[1], self.modeParam["decor"], self.modeParam["nbRotations"]) self.decors[numero] = pionDecor def pionSupprimer(self, num): """supprime le pion entre en parametre""" #settrace(trace_calls) if num in self.pions: for coord in self.pions[num].forme.listeCases(self.pions[num].position, self.pions[num].nbRotations): self.cases[coord].majOccupation(self.pions[num]) self.pionSurvol(None) self.pionDeplacerDansOrdreJeu(num, 0) pionSuppr = self.pions.pop(num) pionSuppr.supprimer() else: print("erreur: ce pion n'est pas dans la liste des pions") def pionDecorSupprimer(self, num): """supprime le pion entre en parametre""" if num in self.decors: for coord in self.decors[num].forme.listeCases(self.decors[num].position, self.decors[num].nbRotations): self.cases[coord].majOccupation(self.decors[num]) self.pionDecorSurvol(None) pionDecorASuppr = self.decors.pop(num) pionDecorASuppr.supprimer() else: print("ce pion n'est pas dans la liste des decors") ############### ######### caches ############### def voirCacheEnCours(self): """centre la vue sur et met en evidence le cache actif""" if len(self.caches[self.cacheEnCours]["listeCases"]) > 0: #centre la vue sur le premier point du polygone d'une case du milieu de la liste indiceMilieu = int((len(self.caches[self.cacheEnCours]["listeCases"])/2)) self.fenetre.ui.vuePlateau.centerOn(self.cases[self.caches[self.cacheEnCours]["listeCases"][indiceMilieu]].polygon()[0]) #mettre en surbrillance #for coord in self.caches[self.cacheEnCours]["listeCases"]: # self. def placerCacheEnCours(self): """active le mode de mise a jour de la liste des cases cachees par ce cache""" self.majMode("cachePlacer") self.fenetre.ui.cacheActif.setChecked(True) self.majEtatCacheEnCours() def majEtatCacheEnCours(self): """met a jour l'etat (actif ou non) du cache selon l'etat de la case correspondante""" self.caches[self.cacheEnCours]["actif"] = self.fenetre.ui.cacheActif.isChecked() self.majAffichageCache(self.cacheEnCours, self.caches[self.cacheEnCours]["actif"]) def majAffichageCache(self, numCache, afficher = True): """met a jour l'affichage des cases selon les parametres enregistres pour le cache""" if self.polygonesCaches[numCache] == None: self.polygonesCaches[numCache] = Cache(self, numCache) self.polygonesCaches[numCache].afficher(afficher, self.caches[numCache]["listeCases"]) ###############" ######### gestion des evenements souris et clavier ############### #*ES def wheelEvent(self, event): """zoom/dezoom avec la molette de la souris""" #on zoom/dezoom et on recentre sur la position du curseur #super (Plateau, self).wheelEvent(event) zoom = 1.00 if event.delta() > 0: if self.nbZoomActuel <= 10: self.nbZoomActuel += 1 zoom = 1.25 elif event.delta() < 0: if self.nbZoomActuel >= -10: zoom = 0.8 self.nbZoomActuel -= 1 if zoom != 0.00: self.fenetre.ui.vuePlateau.scale(zoom, zoom) self.fenetre.ui.vuePlateau.centerOn(event.scenePos()) event.accept() #pour considerer l'evenement comme resolu, sans ca les barres de defilement reagissent aussi def mouseMoveEvent(self, event): super(Plateau, self).mouseMoveEvent(event) if event.buttons() == Qt.LeftButton and self.fenetre.ui.vuePlateau.dragMode() != QGraphicsView.ScrollHandDrag: coord = self.coordonneesAuPoint(event.scenePos()) if coord != None: self.caseSurvolClicEnfonce(coord) else: if self.modeActif == "placementEntreeSortie": self.modeParam["entreeSortie"].majProjection(event.scenePos()) event.ignore() def mousePressEvent(self, event): super(Plateau, self).mousePressEvent(event) if event.button() == 1 and self.fenetre.ui.vuePlateau.dragMode() != QGraphicsView.ScrollHandDrag: if self.modeActif == "placementEntreeSortie" and not event.isAccepted(): self.modeParam["entreeSortie"].positionner() self.entreesSorties.append(self.modeParam["entreeSortie"]) self.modeParam["entreeSortie"] = None self.majMode("standard") elif self.modeActif == "pionSupprimer": for item in self.items(event.scenePos()): if item.__class__.__name__ == "PionDecor": self.pionDecorSupprimer(item.numero) break elif item.parentItem().__class__.__name__ == "Pion": self.pionSupprimer(item.parentItem().numero) break else: ## if not event.isAccepted(): ## self.caseCliquee(self.coordonneesAuPoint(event.scenePos())) event.ignore() elif event.button() == 2: if self.pionSelectionne() != None and self.modeCombat != "" and self.modeCombat != "aucun": self.majModeCombat("aucun") else: self.majMode("standard") event.accept() #event.ignore() def mouseReleaseEvent(self, event): super(Plateau, self).mouseReleaseEvent(event) self.clicGaucheRelache() def keyPressEvent(self, event): """gestion des evenements clavier""" toucheClavier = event.key() if self.modeActif == "pionCreation" or self.modeActif == "pionSelectionne" or self.modeActif == "pionDecorSelectionne" or self.modeActif == "pionDecorCreation": #pivots de la projection du deplacement if toucheClavier == Qt.Key_Right: self.majProjectionPosition(False) self.modeParam["nbRotations"] += 1 self.majProjectionPosition(True) event.accept() elif toucheClavier == Qt.Key_Left: self.majProjectionPosition(False) self.modeParam["nbRotations"] -= 1 self.majProjectionPosition(True) event.accept() elif self.modeActif == "creerEntreeSortie": if toucheClavier == Qt.Key_Right: self.modeParam["entreeSortie"].nbRotations += 1 if toucheClavier == Qt.Key_Left: self.modeParam["entreeSortie"].nbRotations -= 1 self.modeParam["entreeSortie"].majProjection() if self.modeActif[0:7] == "caseMaj": if toucheClavier == Qt.Key_Up: self.fenetre.ui.epaisseurPinceau.setValue(self.fenetre.ui.epaisseurPinceau.value()+1) elif toucheClavier == Qt.Key_Down: self.fenetre.ui.epaisseurPinceau.setValue(self.fenetre.ui.epaisseurPinceau.value()-1) if toucheClavier == Qt.Key_Delete: if self.pionSelectionne() != None: num = self.pionSelectionne().numero if self.modeActif == "pionSelectionne": self.pionSupprimer(num) elif self.modeActif == "pionDecorSelectionne": self.pionDecorSupprimer(num) self.majMode("standard") elif self.modeActif == "placementEntreeSortie": self.modeParam["entreeSortie"].plateau = None self.removeItem(self.modeParam["entreeSortie"]) self.entreesSorties.remove(self.modeParam["entreeSortie"]) self.modeParam["entreeSortie"] = None self.majMode("standard") ################