#from __future__ import unicode_literals # -*- coding: utf-8 -*- from PyQt4.QtCore import * from PyQt4.QtGui import * import regles import AEtoile import time, threading class Action(object): """action effectuee par un combattant sur le plateau de jeu""" def __init__(self): self._num = None #no du pion actif self._coordCible = None #coord de la case ciblee par le curseur self._cible = None #cible (case ou pion) def activer(self, plateau, numPion): self.plateau = plateau self._num = numPion self.creerItemsGraphiques() def majCoordCible(self, coord): """met a jour les coordonnees de la cible, cad la case actuellement survolee par la souris""" if self.plateau.coordonneesValides(coord): self._coordCible = coord self.maj() def desactiver(self): self.afficherCibles(False) self.detruireItemsGraphiques() def valider(self): #envoyer signal self.envoiSignal() self.desactiver() def estValide(self): return True def maj(self): pass def acteur(self): return self.plateau.combattants[self._num] def coordActeur(self): return self.acteur().position #manipulation des items graphiques def creerItemsGraphiques(self): pass def majItemsGraphiques(self): pass def detruireItemsGraphiques(self): pass def activerCurseur(self): pass #affichage des cibles def afficherCibles(self, actif): pass #envoi du signal en cas de validation def envoiSignal(self): pass def pivoter(self, modRotation): pass class Deplacement(Action): ### a completer avec des icones de deplacement, #la prise en compte de la nage et de l'escalade #et le calcul du cout de deplacement def __init__(self): super(Deplacement, self).__init__() self._chemin = [] #liste des coord des cases a traverser self._chercheurChemin = None self._cout = 0 #cout en points de dep self.cible_aConfirmer = None def activer(self, plateau, numPion): super(Deplacement, self).activer(plateau, numPion) self.plateau.proj.creer(self.acteur()) def desactiver(self): self.plateau.proj.desactiver() if self._chercheurChemin: self._chercheurChemin.arreter() self._chercheurChemin = None super(Deplacement, self).desactiver() def valider(self): if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible: self.cible_aConfirmer = self._coordCible self.creerChemin() else: if self.estValide(): pion.majPosition(self.proj.coord(), self.proj.nbRotations()) super(Deplacement, self).valider() def estValide(self): return len(self._chemin)>0 def majCoordCible(self, coord): if coord != self.coordActeur(): super(Deplacement, self).majCoordCible(coord) def maj(self): self.plateau.proj.majCoord(self._coordCible) def pivoter(self, modRotation): self.plateau.proj.majRotation(modRotation) def creerChemin(self): self.afficherCibles(False) self._chemin = [] self._cout = 0 if self._chercheurChemin: self._chercheurChemin.arreter() self._chercheurChemin = None self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible) self._chemin = self._chercheurChemin.liste() self.afficherCibles(True) def afficherCibles(self, actif): for coord in self._chemin: self.plateau.cases[coord].majEstDansChampDeplacement(actif) def envoiSignal(self): cout = 0 for coord in self._chemin: cout += self.plateau.cases[coord].coutDep() print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout) class Attaque(Action): """attaque pre-parametree affectee a un pion, un personnage ou une creature""" def __init__(self): super(Attaque, self).__init__() self.nom = "Attaque" self.portee = 1 #portee max en cases self.attributs = regles.listeAttributsAttaques() self.notes = "" class Cac(Attaque): """attaque au corps a corps""" def __init__(self): super(Cac, self).__init__() self.nom = "Attaque au corps-à-corps" self._pionCible = None def desactiver(self): self.afficherCibles(False) super(Cac, self).desactiver() def valider(self): if self.estValide() and self._pionCible: super(Cac, self).valider() def maj(self): self.afficherCibles(False) pionCible = self.plateau.cases[self._coordCible].pionOccupant() if pionCible != None and pionCible != self._plateau.pionSelectionne(): self._pionCible = pionCible else: self._pionCible = None self.afficherCibles(True) def estValide(self): return (self._coordCible in self.plateau.zone(self.plateau.pionSelectionne().position, self.portee, 0, False, True)) def afficherCibles(self, actif): if self._pionCible: self._pionCible.estCibleAttaque(actif, self.estValide()) def envoiSignal(self): print "{} a attaqué {} au corps-à-corps".format(self.acteur().txtId(), self._pionCible.txtId()) class Distance(Attaque): """attaque a distance""" def __init__(self): super(Distance, self).__init__() self.nom = "Attaque à distance" self._itemLigne = None self._pionCible = None def majCoordCible(self, coord): if self._pionCible: self._pionCible.estCibleAttaque(False, self.estValide()) if self._coordCible in self.plateau.cases: self.plateau.cases[self._coordCible].majEstCibleCurseur(False) super(Distance, self).majCoordCible(coord) def valider(self): if self.estValide() and self._pionCible: super(Distance, self).valider() def maj(self): """met a jour la ligne de mire representant l'attaque a distance""" self.afficherCibles(False) pionCible = self.plateau.cases[self._coordCible].pionOccupant() self.majItemsGraphiques() if pionCible != None and pionCible != self._plateau.pionSelectionne(): self._pionCible = pionCible else: self._pionCible = None self.afficherCibles(True) def estValide(self): return self.plateau.estCibleAttaqueDistValide(self.plateau.pionSelectionne().position, self._coordCible, 0) def afficherCibles(self, actif): if self._pionCible: self._pionCible.estCibleAttaque(actif, self.estValide()) else: #si pas de pion vise, on affiche la case cible comme visee self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, self.estValide()) def creerItemsGraphiques(self): self._itemLigne = QGraphicsLineItem() self._itemLigne.setZValue(100) pinceau = QPen() pinceau.setWidth(6) self._itemLigne.setPen(pinceau) self._itemLigne.prepareGeometryChange() self.plateau.addItem(self._itemLigne) def majItemsGraphiques(self): self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \ self.plateau.cases[self._coordCible].centreGraphique)) def detruireItemsGraphiques(self): if self._itemLigne != None: self._itemLigne.prepareGeometryChange() self.plateau.removeItem(self._itemLigne) self._itemLigne = None def envoiSignal(self): print "{} a attaqué {} a distance".format(self.acteur().txtId(), self._pionCible.txtId()) class Zone(Attaque): """attaque de zone de base""" def __init__(self): super(Zone, self).__init__() self.nom = "Attaque de zone" self._itemLigne = None self._itemCible = None self._casesCibles = [] def valider(self): if self.estValide() and len(self._casesCibles) > 0: super(Zone, self).valider() def desactiver(self): self.afficherCibles(False) self.detruireItemsGraphiques() def maj(self): """maj la forme de l'attaque de zone et les items cibles""" self.afficherCibles(False) self.majItemsGraphiques() self.majCibles() self.afficherCibles(True) def majCibles(self): """met a jour la liste des cases cibles""" self._casesCibles = [] if self.estValide(): for coord in self.plateau.casesSousForme(self._itemCible, True, True): if coord != self.plateau.pionSelectionne().position: self._casesCibles.append(coord) def afficherCibles(self, actif): for coord in self._casesCibles: self.plateau.cases[coord].majEstCibleAttaque(actif) for numCombattant in self.plateau.pionsSurListeCase(self._casesCibles): self.plateau.combattants[numCombattant].estCibleAttaque(actif) def estValide(self): return self.plateau.estCibleAttaqueDistValide(self.plateau.pionSelectionne().position, self._coordCible) def creerItemsGraphiques(self): self._itemLigne = QGraphicsLineItem() self._itemLigne.setPen(QPen(QColor("black"))) self._itemLigne.prepareGeometryChange() self.plateau.addItem(self._itemLigne) self._itemCible = QGraphicsEllipseItem() self._itemCible.setPen(QPen(QColor("black"))) self._itemCible.prepareGeometryChange() self.plateau.addItem(self._itemCible) def detruireItemsGraphiques(self): if self._itemCible != None: self._itemCible.prepareGeometryChange() self.plateau.removeItem(self._itemCible) self._itemCible = None if self._itemLigne != None: self._itemLigne.prepareGeometryChange() self.plateau.removeItem(self._itemLigne) self._itemLigne = None def envoiSignal(self): touches = "" for pion in self.plateau.pionsSurListeCase(self._casesCibles): touches += "{}, ".format(pion.txtId()) touches = touches[:-2] print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches) class Ligne(Attaque): """attaque de zone de forme lineaire""" def __init__(self): super(Ligne, self).__init__() self.nom = "Attaque de zone: ligne" def majItemsGraphiques(self): self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \ self.plateau.cases[self._coordCible].centreGraphique)) class Disque(Attaque): """attaque de zone de forme circulaire""" def __init__(self): super(Disque, self).__init__() self.nom = "Attaque de zone: disque" self.rayon = 1 def majCibles(self): self._casesCibles = self.plateau.zone(self._coordCible, self.rayon, 0) def afficherCibles(self, actif): super(Disque, self).afficherCibles(actif) #si on affiche une attaque invalide if actif and not self.estValide(): self.plateau.cases[self._coordCible].majEstCibleCurseur(True, False) def majItemsGraphiques(self): self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \ self.plateau.cases[self._coordCible].centreGraphique)) if self.estValide(): rect = self.rectEllipseCirculaire(self.plateau.cases[self._coordCible].centreGraphique, self.rayon) if rect != None: self._itemCible.setRect(rect) self._itemCible.setVisible(self.estvalide() and rect != None) 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 = None 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))) if p1 != p2: rect = QRectF() rect.setTopLeft(p1) rect.setBottomRight(p2) return rect class Cone(Attaque): """attaque de zone de forme conique""" def __init__(self): super(Cone, self).__init__() self.nom = "Attaque de zone: cône" def creerItemsGraphiques(self): self._itemCible = QGraphicsPolygonItem() self._itemCible.setPen(QPen(QColor("black"))) self._itemCible.prepareGeometryChange() self.plateau.addItem(self._itemCible) def majItemsGraphiques(self): self._itemCible.setPolygon(self.polygoneCone(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \ self.plateau.cases[self._coordCible].centreGraphique)) 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