#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) self._sourceCurseur = "" self._nomBouton = "" self._enCours = False def typeAtt(self): return "" def activer(self, plateau, numPion): self.plateau = plateau self._num = numPion self.enfoncerBouton(True) self.activerCurseur() self.creerItemsGraphiques() self._enCours = True 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() self.desactiverCurseur() self.enfoncerBouton(False) self._enCours = False def enCours(self): return self._enCours 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 def activerCurseur(self): if len(self._sourceCurseur) > 0: curseurPix = QPixmap(self._sourceCurseur) if not curseurPix.isNull(): curseur = QCursor(curseurPix, 0, curseurPix.height()) self.plateau.fenetre.ui.cbt_vue.setCursor(curseur) def desactiverCurseur(self): self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor)) def enfoncerBouton(self, actif): for bouton in self.plateau.fenetre.ui.pi_actions.findChildren(QToolButton): if bouton.objectName() == self._nomBouton: bouton.setChecked(actif) #manipulation des items graphiques def creerItemsGraphiques(self): pass def majItemsGraphiques(self): pass def detruireItemsGraphiques(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 self._sourceCurseur = "" self._nomBouton = "pi_deplacement" def typeAtt(self): return "dep" 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() and self.plateau.proj.projectionValide(): self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.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, cout in self._chemin: valide = True if actif: if cout > self.acteur().depMarche: valide = False else: cout = 0 self.plateau.cases[coord].majAffichageDeplacement(cout, valide) def envoiSignal(self): cout = self._chemin[-1][1] #cout de deplacement retenu pour la derniere case 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._icone = "" self._portee = 1 #portee max en cases self._rayon = 0 self._attributs = regles.listeAttributsAttaques() self._notes = "" def typeAtt(self): return "att" def nom(self): return self._nom def majNom(self, nom): if len(str(nom)) > 0: self._nom = nom def portee(self): return self._portee def majPortee(self, portee): try: ent = int(portee) if ent > 0: if ent >= 1000: ent = 999 self._portee = ent except: pass def rayon(self): return self._rayon def majRayon(self, rayon): try: ent = int(rayon) if ent > 0: if ent >= 100: ent = 99 self._rayon = ent except: pass def majAttribut(self, nom, nouvelleVal): if nom in self._attributs: if regles.attributAttaque(nom).controler(nouvelleVal): self._attributs[nom] = nouvelleVal def majAttributs(self, dicoAttributs): self._attributs = dicoAttributs def attributs(self): return self._attributs def notes(self): return self._notes def majNotes(self, notes): #on limite a 400 le nombre de caracteres notes = str(notes) self._notes = notes[0:400] def icone(self): return QIcon(self._icone) class Cac(Attaque): """attaque au corps a corps""" def __init__(self): super(Cac, self).__init__() self._nom = "Attaque au corps-à-corps" self._pionCible = None self._sourceCurseur = "" self._nomBouton = "pi_attaqueCac" self._icone = "img\\curseurEpee.png" def typeAtt(self): return "cac" 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 self._sourceCurseur = "" self._nomBouton = "pi_attaqueDist" self._icone = ":/interface/16/ressource/arc_16.png" def typeAtt(self): return "dist" 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 != None: 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 = [] self._sourceCurseur = "" self._nomBouton = "pi_attaqueZone" self._icone = ":/interface/16/ressource/baguette_16.png" def typeAtt(self): return "zone" 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!= None and coord != self.plateau.pionSelectionne().position: self._casesCibles.append(coord) def afficherCibles(self, actif): for coord in self._casesCibles: self.plateau.cases[coord].majEstCibleCurseur(actif) for numCombattant in self.plateau.pionsSurListeCase(self._casesCibles): self.plateau.combattants[numCombattant].estCibleAttaque(actif) 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 num in self.plateau.pionsSurListeCase(self._casesCibles): touches += "{}, ".format(self.plateau.combattants[num].txtId()) touches = touches[:-2] print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches) class Ligne(Zone): """attaque de zone de forme lineaire""" def __init__(self): super(Ligne, self).__init__() self._nom = "Attaque de zone: ligne" def typeAttZone(self): return "ligne" def majItemsGraphiques(self): self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \ self.plateau.cases[self._coordCible].centreGraphique)) def majCibles(self): """met a jour la liste des cases cibles""" self._casesCibles = [] if self.estValide(): for coord in self.plateau.casesSousForme(self._itemLigne, True, True): if coord!= None and coord != self.plateau.pionSelectionne().position: self._casesCibles.append(coord) def estValide(self): retour = True for coord in self._casesCibles: if self.plateau.cases[coord].estObstacleVision(): retour = False break return retour class Disque(Zone): """attaque de zone de forme circulaire""" def __init__(self): super(Disque, self).__init__() self._nom = "Attaque de zone: disque" def typeAttZone(self): return "disque" def majCoordCible(self, coord): if self._coordCible in self.plateau.cases: self.plateau.cases[self._coordCible].majEstCibleCurseur(False) super(Disque, self).majCoordCible(coord) 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 not self.estValide(): self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, 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 estValide(self): return self.plateau.estCibleAttaqueDistValide(self.plateau.pionSelectionne().position, self._coordCible) 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.plateau.hCase)), (centre.y() - (rayon*self.plateau.hCase))) p2 = QPointF((centre.x() + (rayon*self.plateau.hCase)), (centre.y() + (rayon*self.plateau.hCase))) if p1 != p2: rect = QRectF() rect.setTopLeft(p1) rect.setBottomRight(p2) return rect class Cone(Zone): """attaque de zone de forme conique""" def __init__(self): super(Cone, self).__init__() self._nom = "Attaque de zone: cône" def typeAttZone(self): return "cone" 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