#from __future__ import unicode_literals # -*- coding: utf-8 -*- from __future__ import division import os from PyQt4.QtCore import * from PyQt4.QtGui import * from Creature import Creature from Forme import Forme class Pion(QGraphicsItem): """pion du plateau de combat""" def __init__(self, plateau, numero, parent=None): super(Pion, self).__init__() #plateau self.plateau = plateau #attributs self.numero = numero self.creature = Creature() self.nom = "pion" self.numTxt = "" self.lstCarac = self.creature.listeCarac() #caracteristiques par defaut issues des regles utilisees self.position = (-1, -1) self.forme = Forme(self.plateau.formeCases) self.champDeplacement = {} #dictionnaire des cases jusqu'auquelles le pion peut se deplacer (coordonnees : distance) self.deplacementRestant = 0 self.z = 0 #hauteur z par rapport a l'altitude de la case occupee self.hauteur = 1 #nombre de cases occupees en hauteur self.pixGraphique = None self.largeurOriginale = 0 self.hauteurOriginale = 0 self.polygoneGraphique = None self.nbRotations = 0 self.etat = "" self.attaques = [] #liste des attaques pre-parametrees du pion self.notes = "" def __getstate__(self): self.idCreature = self.creature.id state = {key:value for key, value in self.__dict__.items() if not key in ["plateau", "brillance", "shadow", "creature", \ "polygonesForme", "pixGraphique"]} return (state) def __setstate__(self, state): self.__dict__ = state self.creature = charger("librairie\\creature", self.idCreature) ## if self.creature == None: ############## def creer(self, posX, posY, nom, numTxt = "", creature = None, couleur = None, nbRotations = 0): """place le pion sur le plateau""" #definition de la forme if creature != None: self.creature = creature if len(self.creature.formeDef[self.plateau.formeCases]) > 0: self.forme.definirForme(self.creature.formeDef[self.plateau.formeCases]) self.attaques = creature.listeAttaques() self.lstCarac = self.creature.listeCarac() else: if couleur != None: if couleur.isValid(): self.creature.couleur = couleur self.creerPolygone() self.deplacementRestant = self.creature.deplacement self.nom = nom self.numTxt = numTxt #aspect graphique self.majAspectGraphique() #ajout de l'objet graphique self.plateau.addItem(self) #enregistrement et maj de la position self.majPosition((posX, posY), nbRotations) def recreer(self, plateau): """recree le pion (apres un chargement du plateau par ex)""" self.plateau = plateau super(Pion, self).__init__() self.pixGraphique = None self.polygoneGraphique = None self.creerPolygone() self.majAspectGraphique() self.plateau.addItem(self) self.majPosition(self.position, self.nbRotations) def creerPolygone(self): """cree le polygone representant le pion (doit etre cree avant toute rotation)""" polygone = self.plateau.polygoneAgglo(self.forme.listeCases((0,0))) self.polygoneGraphique = QGraphicsPolygonItem() self.polygoneGraphique.setPolygon(polygone) self.polygoneGraphique.setAcceptHoverEvents(True) self.polygoneGraphique.setFlag(QGraphicsItem.ItemIsFocusable) #l'item peut recevoir des commandes souris/clavier self.polygoneGraphique.setParentItem(self) self.polygoneGraphique.setPos(QPointF(0,0)) if self.plateau.formeCases == "H": self.polygoneGraphique.setTransformOriginPoint(QPointF(2*0.2886*self.plateau.hCase,0.5*self.plateau.hCase)) else: self.polygoneGraphique.setTransformOriginPoint(QPointF(0.5*self.plateau.hCase,0.5*self.plateau.hCase)) def majAspectGraphique(self): """met a jour l'aspect graphique du pion (seulement les parametres independants de la position et de la forme de l'objet)""" self.setZValue(10) #interactions graphiques ## self.setFlag(QGraphicsItem.ItemIsFocusable) #l'item peut recevoir des commandes souris/clavier self.setFlag(QGraphicsItem.ItemHasNoContents) #inutile de peindre l'item ## self.setAcceptHoverEvents(True) #accepte les evenements survol souris self.setHandlesChildEvents(True) #classes graphiques self.brillance = QGraphicsColorizeEffect() self.shadow = QGraphicsDropShadowEffect() #etiquette self.text = QGraphicsSimpleTextItem("{}. {}".format(self.numero, self.txtId())) self.text.setPos(QPointF(self.creature.txt["dx"]-0.112*self.plateau.hCase, self.creature.txt["dy"]-0.275*self.plateau.hCase)) police = QFont("Georgia", self.creature.txt["taille_police"]) police.setBold(self.creature.txt["gras"]) self.text.setFont(police) self.text.setRotation(self.creature.txt["rotation"]) self.text.setParentItem(self) #bordure pinceau = QPen() pinceau.setColor(self.creature.couleur.darker(130)) pinceau.setWidth(10) self.polygoneGraphique.setPen(pinceau) #couleur de fond if self.creature.couleur.isValid(): self.polygoneGraphique.setBrush(self.creature.couleur) else: self.polygoneGraphique.setBrush(QColor(255, 0, 0, 150)) #ombre self.shadow.setColor(QColor(50, 50, 50)) self.shadow.setXOffset(1) self.shadow.setYOffset(2) self.shadow.setBlurRadius(3) self.shadow.setEnabled(True) self.polygoneGraphique.setGraphicsEffect(self.shadow) #brillance (invisible par defaut, est un polygone semi transparent superpose au pion) self.polygoneBrillance = QGraphicsPolygonItem() self.polygoneBrillance.setPolygon(self.polygoneGraphique.polygon()) self.polygoneBrillance.setVisible(False) self.polygoneGraphique.setFlag(QGraphicsItem.ItemIsFocusable) self.setAcceptHoverEvents(True) #accepte les evenements survol souris self.polygoneBrillance.setParentItem(self.polygoneGraphique) def majPosition(self, nouvellePosition, nbRotations = 0): """met a jour la position de l'objet graphique et de sa forme en fonction de sa position enregistree""" valide = True if nouvellePosition in self.champDeplacement and self.plateau.modePrincipal == "combat": distanceParcourue = self.champDeplacement[nouvellePosition] if distanceParcourue <= self.deplacementRestant: self.deplacementRestant -= distanceParcourue else: print ("pas assez de points de deplacement") valide = False if valide: #on met a jour l'occupation des cases if self.position != (-1,-1): for coord in self.forme.listeCases((self.position[0],self.position[1]), self.nbRotations): self.plateau.cases[coord].majOccupation(self) #on met a jour la position du pion self.position = nouvellePosition self.majNbRotation(nbRotations) #on replace if self.plateau.formeCases == "H": angleRotation = 60 positionGraphique = QPointF(self.position[0] * 0.866 * self.plateau.hCase, self.position[1] * self.plateau.hCase) else: angleRotation = 90 positionGraphique = QPointF(self.position[0] * self.plateau.hCase, self.position[1] * self.plateau.hCase) self.prepareGeometryChange() self.setPos(positionGraphique) self.polygoneGraphique.setRotation(self.nbRotations*angleRotation) #maj de l'image self.majImage() #on met a jour l'occupation des cases for coord in self.forme.listeCases((self.position[0],self.position[1]), self.nbRotations): self.plateau.cases[coord].majOccupation(self, self.z) def majImage(self): """met a jour la taille, la position et l'orientation de l'image""" if len(self.creature.img["nom"]) > 0: pix = QPixmap(QString.fromUtf8("img\\"+self.creature.img["nom"])) if self.creature.img["masqueAuto"]: pix.setMask(pix.createHeuristicMask()) if not pix.isNull(): if not self.pixGraphique: self.pixGraphique = QGraphicsPixmapItem() self.pixGraphique.setZValue(10) if pix.height() >= pix.width(): pix = pix.scaledToHeight(self.plateau.hCase*0.9, Qt.SmoothTransformation) else: pix = pix.scaledToWidth(self.plateau.hCase*0.9, Qt.SmoothTransformation) self.largeurOriginale = pix.width() self.hauteurOriginale = pix.height() pix = pix.scaled((self.creature.img["kx"]/10)*pix.width(), \ (self.creature.img["ky"]/10)*pix.height(), \ Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.pixGraphique.setPixmap(pix) deltaX = self.creature.img["dx"] + 0.5*(self.plateau.hCase*1.1544 - self.largeurOriginale) deltaY = self.creature.img["dy"] + 0.5*(self.plateau.hCase - self.hauteurOriginale) if self.creature.img["nom"] != self.creature.logo and self.creature.img["pivote"] == True: self.pixGraphique.setParentItem(self.polygoneGraphique) else: self.pixGraphique.setParentItem(self) self.pixGraphique.setRotation(self.creature.img["rotation"]) self.pixGraphique.setPos(QPointF(deltaX, deltaY)) def majNbRotation(self, nbRotations): self.nbRotations = nbRotations if self.plateau.formeCases == "H": rotationsTour = 6 else: rotationsTour = 4 if self.nbRotations >= 0: self.nbRotations = self.nbRotations % rotationsTour else: self.nbRotations = self.nbRotations % (-rotationsTour) def afficheOmbreSelection(self, actif = False): if actif: self.shadow.setXOffset(3) self.shadow.setYOffset(3) else: self.shadow.setXOffset(1) self.shadow.setYOffset(2) def surbrillance(self, active, opacite = 0.7, couleur = "white"): """active/desactive la surbrillance""" if active: self.polygoneBrillance.setOpacity(opacite) couleur = self.couleurSurbrillance(couleur) pinceau = self.polygoneGraphique.pen() self.polygoneBrillance.setBrush(couleur) self.polygoneBrillance.setPen(pinceau) self.polygoneBrillance.setVisible(active) def estCibleAttaque(self, estCible, possible = True): """le pion s'affiche comme etant cible d'une attaque""" if not possible: couleur = "red" else: couleur = "white" self.surbrillance(estCible, 0.8, couleur) def majZ(self, valeur): """met a jour l'altitude Z du pion""" if valeur != self.z: self.z = valeur def couleurSurbrillance(self, couleur = "white"): """renvoie une QColor visible pour la surbrillance, selon la couleur du pion""" retour = QColor(couleur) if self.polygoneGraphique.brush().color().lightness() > 220: retour = retour.darker(140) elif self.polygoneGraphique.brush().color().lightness() < 80: retour = retour.lighter(140) return retour def supprimer(self): """'deconnecte' les items enfants avant de supprimer du pion""" self.polygoneBrillance.prepareGeometryChange() self.polygoneBrillance.setParentItem(None) if self.pixGraphique != None: self.pixGraphique.prepareGeometryChange() self.pixGraphique.setParentItem(None) self.polygoneGraphique.prepareGeometryChange() self.polygoneGraphique.setParentItem(None) self.text.prepareGeometryChange() self.text.setParentItem(None) self.plateau.removeItem(self) self.plateau = None def boundingRect(self): return QRectF() def hoverEnterEvent(self, event): """evenement lors du survol de la souris (en entree)""" #super(Pion, self).hoverEnterEvent(event) if (self.plateau.pionSelectionne() == None and self.plateau.modeActif == "standard") or self.plateau.modeActif == "pionSupprimer": self.surbrillance(True, 0.4) self.plateau.pionSurvol(self.numero) event.ignore() def hoverLeaveEvent(self, event): """evenement lors du survol de la souris (en entree)""" #super(Pion, self).hoverLeaveEvent(event) self.surbrillance(False) self.plateau.pionSurvol(None) def mousePressEvent(self, event): """evenement lors du clic souris""" super(Pion, self).mousePressEvent(event) if event.button() == 1: #sur clic gauche accepte = self.plateau.pionClique(self.numero) if accepte: event.accept() else: event.ignore() def mouseDoubleClickEvent(self, event): """evenement lors du clic souris""" super(Pion, self).mouseDoubleClickEvent(event) if event.button() == 1: #sur clic gauche accepte = self.plateau.pionDoubleClic(self.numero) if accepte: event.accept() else: event.ignore() ################## ############### evenements clavier et souris ############## #*EP def boundingRect(self): return QRectF() def hoverEnterEvent(self, event): """evenement lors du survol de la souris (en entree)""" #super(Pion, self).hoverEnterEvent(event) if (self.plateau.pionSelectionne() == None and self.plateau.modeActif == "standard") or self.plateau.modeActif == "pionSupprimer": self.surbrillance(True, 0.4) self.plateau.pionSurvol(self.numero) event.ignore() def hoverLeaveEvent(self, event): """evenement lors du survol de la souris (en entree)""" #super(Pion, self).hoverLeaveEvent(event) self.surbrillance(False) self.plateau.pionSurvol(None) def mousePressEvent(self, event): """evenement lors du clic souris""" super(Pion, self).mousePressEvent(event) if event.button() == 1: #sur clic gauche accepte = self.plateau.pionClique(self.numero) if accepte: event.accept() else: event.ignore() def mouseDoubleClickEvent(self, event): """evenement lors du clic souris""" super(Pion, self).mouseDoubleClickEvent(event) if event.button() == 1: #sur clic gauche accepte = self.plateau.pionDoubleClic(self.numero) if accepte: event.accept() else: event.ignore()