|
|
@@ -6,103 +6,86 @@ import os
|
|
|
from PyQt4.QtCore import *
|
|
|
from PyQt4.QtGui import *
|
|
|
|
|
|
-from Creature import Creature
|
|
|
from Forme import Forme
|
|
|
from outilsSvg import *
|
|
|
|
|
|
class Pion(QGraphicsItem):
|
|
|
"""pion du plateau de combat"""
|
|
|
- def __init__(self, plateau, numero, parent=None):
|
|
|
+ def __init__(self, parent=None):
|
|
|
super(Pion, self).__init__()
|
|
|
- #plateau
|
|
|
- self.plateau = plateau
|
|
|
+ #caracteristiques du pion
|
|
|
+ self.nom = nom
|
|
|
+ self.couleur = couleur
|
|
|
+ self.logo = logo
|
|
|
+ self.img = ImgPion()
|
|
|
+ self.etiquette = EtiquettePion()
|
|
|
|
|
|
- #attributs
|
|
|
- self.numero = numero
|
|
|
- self.creature = Creature()
|
|
|
- self.nom = "pion"
|
|
|
- self.numTxt = ""
|
|
|
- self.lstCarac = self.creature.listeCarac() #caracteristiques par defaut issues des regles utilisees
|
|
|
+ #infos liees au plateau (forme et position)
|
|
|
+ self.plateau = None
|
|
|
+ self.numComplementaire = "" #numero complementaire si necessaire
|
|
|
+ #(si plusieurs pions portent le meme nom)
|
|
|
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.z = 0
|
|
|
+ self.hauteur = 1
|
|
|
+ self.forme = None
|
|
|
+ self.formeDef = {"H":[], "C":[]}
|
|
|
+
|
|
|
+ #objets et parametres graphiques
|
|
|
self.pixGraphique = None
|
|
|
+ self.etiquetteGraphique = 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 = ""
|
|
|
-
|
|
|
+ self.nbRotations = 0
|
|
|
+
|
|
|
|
|
|
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"]}
|
|
|
+ nePasSvg = ["plateau", "brillance", "shadow", "creature", "polygonesForme", "pixGraphique"]
|
|
|
+ state = {key:value for key, value in self.__dict__.items() if not key in nePasSvg}
|
|
|
return (state)
|
|
|
-
|
|
|
+
|
|
|
def __setstate__(self, state):
|
|
|
self.__dict__ = state
|
|
|
- self.creature = charger("lib\\biblio\\creature", self.idCreature)
|
|
|
- if self.creature == None:
|
|
|
- self.creature = Creature()
|
|
|
-
|
|
|
+ super(Pion, self).__init__()
|
|
|
|
|
|
def paint(self, painter, option, widget = None):
|
|
|
- """reimplemente de QGraphicsItem"""
|
|
|
+ """reimplemente de QGraphicsItem: on ne peint pas cet item, seulement ses items enfants"""
|
|
|
pass
|
|
|
|
|
|
def txtId(self):
|
|
|
"""renvoie le nom et le numero complementaire du pion"""
|
|
|
- return "{} {}".format(self.nom, self.numTxt)
|
|
|
-
|
|
|
- ########### fonctions graphiques et geometriques ##############
|
|
|
- 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()
|
|
|
+ return "{} {}".format(self.nom, self.numComplementaire)
|
|
|
+
|
|
|
+ ###attributs du pion
|
|
|
+ def position(self):
|
|
|
+ """retourne la position actuelle du pion"""
|
|
|
+ return self.position
|
|
|
+
|
|
|
+ def casesOccupees(self):
|
|
|
+ """retourne la liste des cases occupees sur le plateau par le pion (x,y,z)"""
|
|
|
+ retour = []
|
|
|
+ if self.plateau:
|
|
|
+ for x, y in self.forme.listeCases(self.position, self.nbRotations):
|
|
|
+ for z in range(1, self.hauteur):
|
|
|
+ retour.append((x, y, (self.plateau.cases[(x, y)].altitude + self.z + z)))
|
|
|
+ return retour
|
|
|
|
|
|
- #ajout de l'objet graphique
|
|
|
- self.plateau.addItem(self)
|
|
|
+ def majZ(self, valeur):
|
|
|
+ """met a jour l'altitude Z du pion"""
|
|
|
+ if valeur != self.z:
|
|
|
+ self.z = valeur
|
|
|
|
|
|
- #enregistrement et maj de la position
|
|
|
- self.majPosition((posX, posY), nbRotations)
|
|
|
+ ########### fonctions graphiques et geometriques ##############
|
|
|
+ def ajouterAuPlateau(self, plateau):
|
|
|
+ """cerre l'objet graphique representant le pion et le place sur le plateau"""
|
|
|
+ self.plateau = plateau
|
|
|
|
|
|
- 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)
|
|
|
+ #definition de la forme (interpretation de formeDef)
|
|
|
+ if len(self.formeDef[self.plateau.formeCases]) > 0:
|
|
|
+ self.forme = Forme(self.plateau.formeCases)
|
|
|
+ self.forme.definirForme(self.creature.formeDef[self.plateau.formeCases])
|
|
|
|
|
|
- def creerPolygone(self):
|
|
|
- """cree le polygone representant le pion (doit etre cree avant toute rotation)"""
|
|
|
+ #creation du polygone
|
|
|
polygone = self.plateau.polygoneAgglo(self.forme.listeCases((0,0)))
|
|
|
self.polygoneGraphique = QGraphicsPolygonItem()
|
|
|
self.polygoneGraphique.setPolygon(polygone)
|
|
|
@@ -115,51 +98,29 @@ class Pion(QGraphicsItem):
|
|
|
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)"""
|
|
|
+ #parametres de l'objet graphique
|
|
|
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.setFlag(QGraphicsItem.ItemHasNoContents)
|
|
|
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 = QGraphicsDropShadowEffect()
|
|
|
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)
|
|
|
@@ -167,18 +128,13 @@ class Pion(QGraphicsItem):
|
|
|
self.setAcceptHoverEvents(True) #accepte les evenements survol souris
|
|
|
self.polygoneBrillance.setParentItem(self.polygoneGraphique)
|
|
|
|
|
|
+ #on ajoute l'objet au plateau
|
|
|
+ self.plateau.addItem(self)
|
|
|
+ self.majPosition(self.position, self.nbRotations)
|
|
|
+
|
|
|
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:
|
|
|
+ if self.plateau:
|
|
|
#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):
|
|
|
@@ -205,12 +161,12 @@ class Pion(QGraphicsItem):
|
|
|
#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"]:
|
|
|
+ if len(self.img.nom) > 0:
|
|
|
+ pix = QPixmap(QString.fromUtf8("img\\"+self.img.nom))
|
|
|
+ if self.img.masqueAuto:
|
|
|
pix.setMask(pix.createHeuristicMask())
|
|
|
if not pix.isNull():
|
|
|
if not self.pixGraphique:
|
|
|
@@ -222,21 +178,33 @@ class Pion(QGraphicsItem):
|
|
|
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(), \
|
|
|
+ pix = pix.scaled((self.img.kx/10)*pix.width(), \
|
|
|
+ (self.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:
|
|
|
+ deltaX = self.img.dx + 0.5*(self.plateau.hCase*1.1544 - self.largeurOriginale)
|
|
|
+ deltaY = self.img.dy + 0.5*(self.plateau.hCase - self.hauteurOriginale)
|
|
|
+ if self.img.nom != self.logo and self.pivote == True:
|
|
|
self.pixGraphique.setParentItem(self.polygoneGraphique)
|
|
|
else:
|
|
|
self.pixGraphique.setParentItem(self)
|
|
|
- self.pixGraphique.setRotation(self.creature.img["rotation"])
|
|
|
+ self.pixGraphique.setRotation(self.img.rotation)
|
|
|
self.pixGraphique.setPos(QPointF(deltaX, deltaY))
|
|
|
|
|
|
+ def majEtiquette(self):
|
|
|
+ """met a jour la taille, le format et l'orientation de l'etiquette"""
|
|
|
+ self.etiquetteGraphique = QGraphicsSimpleTextItem("{}".format(self.txtId()))
|
|
|
+ self.etiquetteGraphique.setPos(QPointF(self.etiquette.dx - 0.112*self.plateau.hCase, \
|
|
|
+ self.etiquette.dy - 0.275*self.plateau.hCase))
|
|
|
+ police = QFont("Georgia", self.etiquette.taille_police)
|
|
|
+ police.setBold(self.etiquette.gras)
|
|
|
+ self.etiquetteGraphique.setFont(police)
|
|
|
+ self.etiquetteGraphique.setRotation(self.etiquette.rotation)
|
|
|
+ self.etiquetteGraphique.setParentItem(self)
|
|
|
+
|
|
|
def majNbRotation(self, nbRotations):
|
|
|
+ """ajoute/retranche le nombre au nombre total de rotations du pion"""
|
|
|
self.nbRotations = nbRotations
|
|
|
if self.plateau.formeCases == "H":
|
|
|
rotationsTour = 6
|
|
|
@@ -248,14 +216,31 @@ class Pion(QGraphicsItem):
|
|
|
else:
|
|
|
self.nbRotations = self.nbRotations % (-rotationsTour)
|
|
|
|
|
|
+ def retirerDuPlateau(self):
|
|
|
+ """'deconnecte' les items enfants avant de supprimer du pion du plateau"""
|
|
|
+ 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)
|
|
|
+ if self.etiquetteGraphique:
|
|
|
+ self.etiquetteGraphique.prepareGeometryChange()
|
|
|
+ self.etiquetteGraphique.setParentItem(None)
|
|
|
+ self.plateau.removeItem(self)
|
|
|
+ self.plateau = None
|
|
|
+
|
|
|
+ ###effets graphiques
|
|
|
def afficheOmbreSelection(self, actif = False):
|
|
|
+ """modifie l'ombre du pion en fonction de si celui-ci est selectionne ou non"""
|
|
|
if actif:
|
|
|
self.shadow.setXOffset(3)
|
|
|
self.shadow.setYOffset(3)
|
|
|
else:
|
|
|
self.shadow.setXOffset(1)
|
|
|
- self.shadow.setYOffset(2)
|
|
|
-
|
|
|
+ self.shadow.setYOffset(2)
|
|
|
+
|
|
|
def surbrillance(self, active, opacite = 0.7, couleur = "white"):
|
|
|
"""active/desactive la surbrillance"""
|
|
|
if active:
|
|
|
@@ -264,8 +249,8 @@ class Pion(QGraphicsItem):
|
|
|
pinceau = self.polygoneGraphique.pen()
|
|
|
self.polygoneBrillance.setBrush(couleur)
|
|
|
self.polygoneBrillance.setPen(pinceau)
|
|
|
- self.polygoneBrillance.setVisible(active)
|
|
|
-
|
|
|
+ self.polygoneBrillance.setVisible(active)
|
|
|
+
|
|
|
def estCibleAttaque(self, estCible, possible = True):
|
|
|
"""le pion s'affiche comme etant cible d'une attaque"""
|
|
|
if not possible:
|
|
|
@@ -274,11 +259,6 @@ class Pion(QGraphicsItem):
|
|
|
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)
|
|
|
@@ -288,57 +268,31 @@ class Pion(QGraphicsItem):
|
|
|
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
|
|
|
-
|
|
|
##################
|
|
|
|
|
|
############### 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()
|
|
|
+class ImgPion():
|
|
|
+ def __init__(self):
|
|
|
+ self.nomFichier = "" #nom du fichier image source
|
|
|
+ self.kx = 1 #coeff d'agrandissement horizontal
|
|
|
+ self.ky = 1 #coeff d'agrandissement vertical
|
|
|
+ self.dx = 0 #decalage horizontal
|
|
|
+ self.dy = 0 #decalage vertical
|
|
|
+ self.rotation = 0 #rotation(en degres)
|
|
|
+ self.pivote = False #l'image pivote avec le pion?
|
|
|
+ self.masqueAuto = False #creer un masque automatiquement
|
|
|
+
|
|
|
+class EtiquettePion():
|
|
|
+ def __init__(self):
|
|
|
+ self.taille_police = "" #taille de la police
|
|
|
+ self.gras = False #en gras
|
|
|
+ self.dx = 0 #decalage horizontal
|
|
|
+ self.dy = 0 #decalage vertical
|
|
|
+ self.rotation = 0 #rotation(en degres)
|
|
|
|
|
|
- #######################
|