浏览代码

Attaques a distance et de zone reprises pour fonctionner
en '3d' (sauf cone)

unknown 10 年之前
父节点
当前提交
cbd1864cad
共有 23 个文件被更改,包括 315 次插入309 次删除
  1. 2 0
      .settings/org.eclipse.core.resources.prefs
  2. 30 17
      DMonde.ppr
  3. 3 16
      DMonde.py
  4. 3 1
      lib/AEtoile.py
  5. 122 63
      lib/Actions.py
  6. 45 71
      lib/Case.py
  7. 2 2
      lib/EcranEditionCombattant.py
  8. 0 1
      lib/Forme.py
  9. 2 3
      lib/Modes.py
  10. 14 5
      lib/Pion.py
  11. 83 112
      lib/Plateau.py
  12. 2 2
      lib/ProjectionDep.py
  13. 二进制
      lib/biblio/combattant
  14. 二进制
      lib/biblio/decor
  15. 4 2
      lib/br.py
  16. 0 10
      lib/ui/dm.py
  17. 1 1
      lib/ui/mainwindow.ui
  18. 二进制
      parties/Partie1/svg/0.p
  19. 二进制
      parties/Partie1/svg/1.p
  20. 二进制
      parties/Partie1/svg/2.p
  21. 二进制
      parties/Partie1/svg/3.p
  22. 二进制
      parties/Partie1/svg/4.p
  23. 2 3
      parties/Partie1/svg/infos_sauvegarde

+ 2 - 0
.settings/org.eclipse.core.resources.prefs

@@ -1,4 +1,6 @@
 eclipse.preferences.version=1
 eclipse.preferences.version=1
+encoding//lib/Actions.py=utf-8
+encoding//lib/Case.py=utf-8
 encoding//lib/Combattant.py=utf-8
 encoding//lib/Combattant.py=utf-8
 encoding//lib/Plateau.py=utf-8
 encoding//lib/Plateau.py=utf-8
 encoding/DMonde.py=utf-8
 encoding/DMonde.py=utf-8

+ 30 - 17
DMonde.ppr

@@ -107,7 +107,7 @@ DMonde
 				-tags
 				-tags
 		+lib
 		+lib
 			-biblio
 			-biblio
-			-ui
+			+ui
 				-corbeille_ui
 				-corbeille_ui
 					lib\ui\corbeille_ui\dmOngletsH.py
 					lib\ui\corbeille_ui\dmOngletsH.py
 					lib\ui\corbeille_ui\dmtableattaques - Copie.py
 					lib\ui\corbeille_ui\dmtableattaques - Copie.py
@@ -138,17 +138,20 @@ DMonde
 				lib\ui\ecran_selectionPj.py
 				lib\ui\ecran_selectionPj.py
 				lib\ui\panneauImage.py
 				lib\ui\panneauImage.py
 				lib\ui\ressource_rc.py
 				lib\ui\ressource_rc.py
+				lib\dmK.py
 			lib\__init__.py
 			lib\__init__.py
 			lib\Actions.py
 			lib\Actions.py
 			lib\AEtoile.py
 			lib\AEtoile.py
 			lib\afficherSousMenu.py
 			lib\afficherSousMenu.py
 			lib\Boucle.py
 			lib\Boucle.py
+			lib\br.py
 			lib\Cache - Copie.py
 			lib\Cache - Copie.py
 			lib\Cache.py
 			lib\Cache.py
 			lib\Case.py
 			lib\Case.py
 			lib\Combattant.py
 			lib\Combattant.py
 			lib\Creature.py
 			lib\Creature.py
 			lib\Decor.py
 			lib\Decor.py
+			lib\dmF.py
 			lib\EcranAffichageTexte.py
 			lib\EcranAffichageTexte.py
 			lib\EcranChargerPlateau.py
 			lib\EcranChargerPlateau.py
 			lib\EcranCreerPlateau.py
 			lib\EcranCreerPlateau.py
@@ -159,6 +162,7 @@ DMonde
 			lib\EcranFondPlateau.py
 			lib\EcranFondPlateau.py
 			lib\EcranGestionCombat.py
 			lib\EcranGestionCombat.py
 			lib\EcranSelectionPj.py
 			lib\EcranSelectionPj.py
+			lib\EcranVol.py
 			lib\EffetsCase.py
 			lib\EffetsCase.py
 			lib\EntreeSortie.py
 			lib\EntreeSortie.py
 			lib\fonctionsCommunes.py
 			lib\fonctionsCommunes.py
@@ -179,10 +183,8 @@ DMonde
 			lib\regles.py
 			lib\regles.py
 			lib\rsc.py
 			lib\rsc.py
 			lib\Terrain.py
 			lib\Terrain.py
-			lib\br.py
 			lib\test.py
 			lib\test.py
 			lib\VueEditionForme.py
 			lib\VueEditionForme.py
-			lib\dmF.py
 		-parties
 		-parties
 			-Partie1
 			-Partie1
 				-journal
 				-journal
@@ -199,24 +201,35 @@ DMonde
 0=DMonde.py
 0=DMonde.py
 1=lib\Plateau.py
 1=lib\Plateau.py
 2=lib\Modes.py
 2=lib\Modes.py
-3=lib\Case.py
-4=lib\Actions.py
+3=lib\br.py
+4=lib\Case.py
+5=lib\Actions.py
+6=lib\Pion.py
+7=lib\ui\dm.py
 [Selected Project Files]
 [Selected Project Files]
 Main=
 Main=
-Selected=DMonde.py
+Selected=lib\Actions.py
 [DMonde.py]
 [DMonde.py]
-TopLine=16
-Caret=27,29
+TopLine=15
+Caret=15,26
 [lib\Plateau.py]
 [lib\Plateau.py]
-TopLine=660
-Caret=44,673
-BookMark1=9,1486
+TopLine=662
+Caret=34,676
 [lib\Modes.py]
 [lib\Modes.py]
-TopLine=580
-Caret=24,595
+TopLine=604
+Caret=23,621
+[lib\br.py]
+TopLine=9
+Caret=1,22
 [lib\Case.py]
 [lib\Case.py]
-TopLine=162
-Caret=15,168
+TopLine=240
+Caret=22,231
 [lib\Actions.py]
 [lib\Actions.py]
-TopLine=483
-Caret=45,494
+TopLine=548
+Caret=19,557
+[lib\Pion.py]
+TopLine=151
+Caret=35,158
+[lib\ui\dm.py]
+TopLine=535
+Caret=47,538

+ 3 - 16
DMonde.py

@@ -2,33 +2,20 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 """Interface principale du programme DMonde
 """Interface principale du programme DMonde
 """
 """
-from __future__ import division
-import os
-from sys import exit, argv, getsizeof, settrace
-from time import time, sleep, strftime, localtime
-import pydoc
-
+from sys import exit, argv
 from PyQt4.QtCore import *
 from PyQt4.QtCore import *
 from PyQt4.QtGui import *
 from PyQt4.QtGui import *
 
 
 from lib.ui.ecran_principal import Ui_principal
 from lib.ui.ecran_principal import Ui_principal
-import lib.rsc as rsc
-
 from lib.EcranCreerPlateau import EcranCreerPlateau
 from lib.EcranCreerPlateau import EcranCreerPlateau
 from lib.EcranChargerPlateau import EcranChargerPlateau
 from lib.EcranChargerPlateau import EcranChargerPlateau
 from lib.EcranFondPlateau import EcranFondPlateau
 from lib.EcranFondPlateau import EcranFondPlateau
-from lib.Plateau import Plateau
 from lib.EcranEditionCombattant import EcranEditionCombattant
 from lib.EcranEditionCombattant import EcranEditionCombattant
 from lib.framePj import FramePj
 from lib.framePj import FramePj
-from lib.outilsSvg import *
 
 
-from lib.Case import Case
-from lib.Combattant import Combattant
-from lib.Decor import Decor
-from lib.Terrain import Terrain
+from lib.Plateau import Plateau
 
 
-from lib.Cache import Cache
-from lib.EntreeSortie import EntreeSortie
+from lib.outilsSvg import *
 
 
 class DMonde(QMainWindow):
 class DMonde(QMainWindow):
     """interface comprenant: chat ecrit, fenetre d'infos, lancer de des, echange de fichiers, lancement du chat vocal"""
     """interface comprenant: chat ecrit, fenetre d'infos, lancer de des, echange de fichiers, lancement du chat vocal"""

+ 3 - 1
lib/AEtoile.py

@@ -33,12 +33,14 @@ class N():
         self.cout =  self.coutG + self.coutH
         self.cout =  self.coutG + self.coutH
 
 
 class Chemin():
 class Chemin():
-    def __init__(self, plateau, origine, cible):
+    def __init__(self, plateau, origine, cible, z1 = 0, z2 = 0):
         self.plateau = plateau
         self.plateau = plateau
         self.origine = origine
         self.origine = origine
         self.cible = cible
         self.cible = cible
         self.echec = False
         self.echec = False
         self.stop = False
         self.stop = False
+        self._z1 = z1
+        self._z2 = z2
 
 
         ###active l'evolution sur le plateau
         ###active l'evolution sur le plateau
         self.debug = False
         self.debug = False

+ 122 - 63
lib/Actions.py

@@ -5,7 +5,10 @@ from PyQt4.QtGui import *
 import regles
 import regles
 import AEtoile
 import AEtoile
 import time, threading
 import time, threading
-
+import br
+from Pion import Pion
+from Combattant import Combattant
+from Decor import Decor
 
 
 class Action(object):
 class Action(object):
     """action effectuee par un combattant sur le plateau de jeu"""
     """action effectuee par un combattant sur le plateau de jeu"""
@@ -16,6 +19,18 @@ class Action(object):
         self._sourceCurseur = ""
         self._sourceCurseur = ""
         self._nomBouton = ""
         self._nomBouton = ""
         self._enCours = False
         self._enCours = False
+        self._desactivationDemandee = False
+
+    #decorateur
+    def autorise(f):
+        def _autorise(self, *args):
+            def fVide(*args):
+                pass
+            retour = fVide
+            if not self._desactivationDemandee:
+                retour = f
+            retour(self, *args)                            
+        return _autorise
 
 
     def typeAtt(self):
     def typeAtt(self):
         return ""
         return ""
@@ -38,6 +53,7 @@ class Action(object):
             self.maj()
             self.maj()
 
 
     def desactiver(self):
     def desactiver(self):
+        self._desactivationDemandee = True
         self.afficherCibles(False)
         self.afficherCibles(False)
         self.detruireItemsGraphiques()
         self.detruireItemsGraphiques()
         self.desactiverCurseur()
         self.desactiverCurseur()
@@ -100,6 +116,8 @@ class Action(object):
     def pivoter(self, modRotation):
     def pivoter(self, modRotation):
         pass
         pass
 
 
+         
+        
 class Deplacement(Action):
 class Deplacement(Action):
     ### a completer avec des icones de deplacement,
     ### a completer avec des icones de deplacement,
     #la prise en compte de la nage et de l'escalade
     #la prise en compte de la nage et de l'escalade
@@ -109,6 +127,7 @@ class Deplacement(Action):
         self._chemin = []  #liste des coord des cases a traverser
         self._chemin = []  #liste des coord des cases a traverser
         self._chercheurChemin = None
         self._chercheurChemin = None
         self._cout = 0     #cout en points de dep
         self._cout = 0     #cout en points de dep
+        self._zCible = 0
         self.cible_aConfirmer = None
         self.cible_aConfirmer = None
         self._sourceCurseur = ""
         self._sourceCurseur = ""
         self._nomBouton = "pi_deplacement" 
         self._nomBouton = "pi_deplacement" 
@@ -130,10 +149,12 @@ class Deplacement(Action):
     def valider(self):
     def valider(self):
         if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible:             
         if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible:             
             self.cible_aConfirmer = self._coordCible
             self.cible_aConfirmer = self._coordCible
-            self.creerChemin()
+            self.recupZCible()
+            self.creerChemin() 
         else:
         else:
             if self.estValide() and self.plateau.proj.projectionValide():
             if self.estValide() and self.plateau.proj.projectionValide():
                 self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
                 self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
+                self.acteur().majZ(self._zCible)
                 super(Deplacement, self).valider()
                 super(Deplacement, self).valider()
 
 
     def estValide(self):
     def estValide(self):
@@ -156,7 +177,7 @@ class Deplacement(Action):
         if self._chercheurChemin:
         if self._chercheurChemin:
             self._chercheurChemin.arreter()
             self._chercheurChemin.arreter()
             self._chercheurChemin = None
             self._chercheurChemin = None
-        self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible)
+        self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible, self.acteur().z, self._zCible)
         self._chemin = self._chercheurChemin.liste()
         self._chemin = self._chercheurChemin.liste()
         self.afficherCibles(True)        
         self.afficherCibles(True)        
 
 
@@ -173,6 +194,25 @@ class Deplacement(Action):
         cout = self._chemin[-1][1]  #cout de deplacement retenu pour la derniere case
         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)
         print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)
 
 
+    def recupZCible(self):
+        self._zCible = self.acteur().z    
+
+
+class Vol(Deplacement):
+    """idem que Deplacement, mais affiche en plus la boite de dialogue Vol
+       (et n'utilise pas le meme algo de deplacement?)"""
+    def __init__(self):
+        super(Vol, self).__init__()
+        self._zCible = 0
+        self._nomBouton = "pi_vol" 
+
+    def typeAtt(self):
+        return "vol"
+        
+    def recupZCible(self):
+        nouveauZ = self.plateau.dialogueVol(self.acteur().z)
+        self._zCible = nouveauZ 
+
 class Attaque(Action):
 class Attaque(Action):
     """attaque pre-parametree affectee a un pion, un personnage ou une creature"""
     """attaque pre-parametree affectee a un pion, un personnage ou une creature"""
     def __init__(self):
     def __init__(self):
@@ -263,7 +303,7 @@ class Cac(Attaque):
       
       
     def maj(self):
     def maj(self):
         self.afficherCibles(False)
         self.afficherCibles(False)
-        pionCible = self.plateau.cases[self._coordCible].pionOccupant()
+        pionCible = self.plateau.cases[self._coordCible].occupant()
         if pionCible != None and pionCible != self.plateau.pionSelectionne():
         if pionCible != None and pionCible != self.plateau.pionSelectionne():
             self._pionCible = pionCible
             self._pionCible = pionCible
         else:
         else:
@@ -308,39 +348,26 @@ class Distance(Attaque):
     def maj(self):
     def maj(self):
         """met a jour la ligne de mire representant l'attaque a distance"""
         """met a jour la ligne de mire representant l'attaque a distance"""
         self.afficherCibles(False)
         self.afficherCibles(False)
-        pionCible = self.plateau.cases[self._coordCible].pionOccupant()
-
+        pionCible = self.plateau.cases[self._coordCible].occupant()
         self.majItemsGraphiques()
         self.majItemsGraphiques()
         if pionCible != None and pionCible != self.plateau.pionSelectionne():
         if pionCible != None and pionCible != self.plateau.pionSelectionne():
             self._pionCible = pionCible
             self._pionCible = pionCible
         else:
         else:
             self._pionCible = None
             self._pionCible = None
-
         self.afficherCibles(True)
         self.afficherCibles(True)
 
 
     def estValide(self):
     def estValide(self):
-        x1, y1 = self.plateau.pionSelectionne().position
-        z1 = self.plateau.pionSelectionne().z + self.plateau.pionSelectionne().hauteur
-        x2, y2 = self._coordCible
-        listeZ2 = []
-        if self._pionCible != None:
-            for h in range(0, self._pionCible.hauteur):
-                listeZ2.append((self._pionCible.z + h))
-        else:
-            listeZ2 = [self.plateau.cases[self._coordCible].altitude]   
-        valide = True
-        for z2 in listeZ2:
-            if not self.plateau.estCibleAttaqueDistValide((x1, y1, z1), (x2, y2, z2)):
-                valide = False
-                break
-        return valide
+        return self.plateau.estCibleAttaqueDistValide(self._coordCible)
 
 
     def afficherCibles(self, actif):
     def afficherCibles(self, actif):
+        valide = True
+        if actif: valide = self.estValide()
+        
         if self._pionCible:
         if self._pionCible:
-            self._pionCible.estCibleAttaque(actif, self.estValide())
+            self._pionCible.estCibleAttaque(actif, valide)
         else:
         else:
             #si pas de pion vise, on affiche la case cible comme visee
             #si pas de pion vise, on affiche la case cible comme visee
-            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, self.estValide())            
+            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, valide)            
 
 
     def creerItemsGraphiques(self):
     def creerItemsGraphiques(self):
         self._itemLigne = QGraphicsLineItem()
         self._itemLigne = QGraphicsLineItem()
@@ -382,32 +409,37 @@ class Zone(Attaque):
 
 
     def valider(self):
     def valider(self):
         if self.estValide() and len(self._casesCibles) > 0:
         if self.estValide() and len(self._casesCibles) > 0:
-            super(Zone, self).valider()
+            super(Zone, self).valider() 
 
 
-    def desactiver(self):
-        self.afficherCibles(False)
-        self.detruireItemsGraphiques()
+#     def desactiver(self):
+#         self.detruireItemsGraphiques()
+#         super(Zone, self).desactiver() 
 
 
     def maj(self):
     def maj(self):
         """maj la forme de l'attaque de zone et les items cibles"""
         """maj la forme de l'attaque de zone et les items cibles"""
         self.afficherCibles(False)
         self.afficherCibles(False)
         self.majItemsGraphiques()
         self.majItemsGraphiques()
         self.majCibles()
         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)            
+        self.afficherCibles(True)      
 
 
     def afficherCibles(self, actif):
     def afficherCibles(self, actif):
         for coord in self._casesCibles:
         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)    
+            self.plateau.cases[(coord[0], coord[1])].majEstCibleCurseur(actif)
+            z = 0 if len(coord) == 2 else coord[2]
+            if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
+                pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
+                pion.estCibleAttaque(actif) 
+
+    def listePionsCibles(self):
+        retour = []
+        print self._casesCibles
+        for coord in self._casesCibles:
+            z = 0 if len(coord) == 2 else coord[2]
+            if self.plateau.cases[(coord[0], coord[1])].estOccupee(z):
+                pion = self.plateau.cases[(coord[0], coord[1])].occupant(z)
+                if not pion in retour:
+                    retour.append(pion)
+        return retour
 
 
     def creerItemsGraphiques(self):
     def creerItemsGraphiques(self):
         self._itemLigne = QGraphicsLineItem()
         self._itemLigne = QGraphicsLineItem()
@@ -425,7 +457,7 @@ class Zone(Attaque):
             self._itemCible.prepareGeometryChange()
             self._itemCible.prepareGeometryChange()
             self.plateau.removeItem(self._itemCible)
             self.plateau.removeItem(self._itemCible)
             self._itemCible = None
             self._itemCible = None
-
+        
         if self._itemLigne != None:
         if self._itemLigne != None:
             self._itemLigne.prepareGeometryChange()
             self._itemLigne.prepareGeometryChange()
             self.plateau.removeItem(self._itemLigne)
             self.plateau.removeItem(self._itemLigne)
@@ -433,8 +465,8 @@ class Zone(Attaque):
 
 
     def envoiSignal(self):
     def envoiSignal(self):
         touches = ""
         touches = ""
-        for num in self.plateau.pionsSurListeCase(self._casesCibles):
-            touches += "{}, ".format(self.plateau.combattants[num].txtId())
+        for pion in self.listePionsCibles():
+            touches += "{}, ".format(pion.txtId())
         touches = touches[:-2]
         touches = touches[:-2]
         print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)
         print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)
 
 
@@ -449,46 +481,75 @@ class Ligne(Zone):
         return "ligne"
         return "ligne"
 
 
     def majItemsGraphiques(self):
     def majItemsGraphiques(self):
-        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
-                                       self.plateau.cases[self._coordCible].centreGraphique))
+        if not self._desactivationDemandee:
+            self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
+                                           self.plateau.cases[self._coordCible].centreGraphique))
 
 
     def majCibles(self):
     def majCibles(self):
         """met a jour la liste des cases cibles"""
         """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:
+        if not self._desactivationDemandee:
+            self._casesCibles = []
+            x1, y1 = self.acteur().position
+            z1 = self.acteur().zAbs() + self.acteur().hauteur
+            x2, y2 = self._coordCible
+            if self.plateau.cases[(x2, y2)].estOccupee():
+                z2 = self.plateau.cases[(x2, y2)].occupant().zAbs()
+            else:
+                z2 = self.plateau.cases[(x2, y2)].altitude   
+             
+            for coord in br.ligne((x1, y1, z1), (x2, y2, z2)):
+                if coord != (x1, y1, z1):
                     self._casesCibles.append(coord)  
                     self._casesCibles.append(coord)  
-
+            
+            if not self.estValide(): self._casesCibles = []
+        
     def estValide(self):
     def estValide(self):
         retour = True
         retour = True
         for coord in self._casesCibles:
         for coord in self._casesCibles:
-            if self.plateau.cases[coord].estObstacleVision():
-                retour = False
-                break
+            x, y, z = coord
+            if not self.plateau.cases[(x, y)].estFranchissable(z):
+                if not isinstance(self.plateau.cases[(x, y)].occupant(z), Combattant):
+                    retour = False
+                    break
         return retour
         return retour
             
             
-
 class Disque(Zone):
 class Disque(Zone):
     """attaque de zone de forme circulaire"""
     """attaque de zone de forme circulaire"""
     def __init__(self):
     def __init__(self):
         super(Disque, self).__init__()
         super(Disque, self).__init__()
         self._nom = "Attaque de zone: disque"
         self._nom = "Attaque de zone: disque"
 
 
+    #decorateur
+    def autorise(f):
+        def _autorise(self, *args):
+            def fVide(*args):
+                pass
+            retour = fVide
+            if not self._desactivationDemandee:
+                retour = f
+            retour(self, *args)                            
+        return _autorise
+
     def typeAttZone(self):
     def typeAttZone(self):
         return "disque"
         return "disque"
 
 
     def activer(self, plateau, numPion):
     def activer(self, plateau, numPion):
         super(Disque, self).activer(plateau, numPion)
         super(Disque, self).activer(plateau, numPion)
         self._rayon = self.plateau.fenetre.ui.pi_rayonAttaqueZone.value()
         self._rayon = self.plateau.fenetre.ui.pi_rayonAttaqueZone.value()
-        
+    
+    @autorise  
     def majCoordCible(self, coord):
     def majCoordCible(self, coord):
         if self._coordCible in self.plateau.cases:    
         if self._coordCible in self.plateau.cases:    
             self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
             self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
         super(Disque, self).majCoordCible(coord)    
         super(Disque, self).majCoordCible(coord)    
 
 
+    @autorise
     def majCibles(self):
     def majCibles(self):
-        self._casesCibles = self.plateau.zone(self._coordCible, self._rayon, 0)
+        if self.plateau.cases[self._coordCible].estOccupee():
+            zCible = self.plateau.cases[self._coordCible].occupant().zAbs()
+        else:
+            zCible = self.plateau.cases[self._coordCible].altitude   
+        self._casesCibles = self.plateau.zone3d(self._coordCible, self._rayon, zCible)
 
 
     def afficherCibles(self, actif):
     def afficherCibles(self, actif):
         if self.estValide():
         if self.estValide():
@@ -496,11 +557,13 @@ class Disque(Zone):
         else:
         else:
             super(Disque, self).afficherCibles(False)
             super(Disque, self).afficherCibles(False)
             self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)
             self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)
-
+    
+    @autorise
     def majRayon(self, val):
     def majRayon(self, val):
         self._rayon = val
         self._rayon = val
         self.maj()
         self.maj()
 
 
+    @autorise
     def majItemsGraphiques(self):
     def majItemsGraphiques(self):
         self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
         self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
                                        self.plateau.cases[self._coordCible].centreGraphique))
                                        self.plateau.cases[self._coordCible].centreGraphique))
@@ -511,12 +574,9 @@ class Disque(Zone):
         self._itemCible.setVisible(self.estValide() and rect != None)
         self._itemCible.setVisible(self.estValide() and rect != None)
 
 
     def estValide(self):
     def estValide(self):
-        x1, y1 = self.plateau.pionSelectionne().position
-        z1 = self.plateau.pionSelectionne().z + self.plateau.pionSelectionne().hauteur
-        x2, y2 = self._coordCible
-        z2 = self.plateau.cases[self._coordCible].altitude
-        return self.plateau.estCibleAttaqueDistValide((x1, y1, z1), (x2, y2, z2))
+        return self.plateau.estCibleAttaqueDistValide(self._coordCible)
 
 
+    @autorise
     def rectEllipseCirculaire(self, centre, rayon):
     def rectEllipseCirculaire(self, centre, rayon):
         """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
         """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
            attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
@@ -531,7 +591,6 @@ class Disque(Zone):
                 rect.setBottomRight(p2)
                 rect.setBottomRight(p2)
         return rect
         return rect
 
 
-
 class Cone(Zone):
 class Cone(Zone):
     """attaque de zone de forme conique"""
     """attaque de zone de forme conique"""
     def __init__(self):
     def __init__(self):

+ 45 - 71
lib/Case.py

@@ -8,6 +8,9 @@ from PyQt4.QtGui import *
 from outilsSvg import *
 from outilsSvg import *
 from Terrain import Terrain
 from Terrain import Terrain
 import Modes
 import Modes
+from Pion import Pion
+from Combattant import Combattant
+from Decor import Decor
 
 
 class Case(QGraphicsPolygonItem):
 class Case(QGraphicsPolygonItem):
     """objet graphique representant une case du plateau"""
     """objet graphique representant une case du plateau"""
@@ -21,11 +24,10 @@ class Case(QGraphicsPolygonItem):
         self.y = 0        
         self.y = 0        
         self.altitude = 0                   
         self.altitude = 0                   
         self.terrain = Terrain()                       #terrain par defaut 
         self.terrain = Terrain()                       #terrain par defaut 
-##        self.couleur = None                            #couleur du fond par defaut
         self.bordure = QColor(85, 85, 85, 85)          #couleur de la bordure par defaut
         self.bordure = QColor(85, 85, 85, 85)          #couleur de la bordure par defaut
         self.centreGraphique = None
         self.centreGraphique = None
 
 
-        self.occupeePar = {}    #objet: altitudes occupees (sous forme de tuple, ex: (0,1,2) pour une creature occupant les cases d'altitude 0, 1 et 2)
+        self.occupation = {}    #z: num pion
         self.cachesActifs = []       #liste des caches places par le MJ (cache le terrain, les decors, les pions aux joueurs...)
         self.cachesActifs = []       #liste des caches places par le MJ (cache le terrain, les decors, les pions aux joueurs...)
         self.cachesInactifs = []
         self.cachesInactifs = []
 
 
@@ -67,7 +69,7 @@ class Case(QGraphicsPolygonItem):
 
 
         #enregistrement des cases voisines: 
         #enregistrement des cases voisines: 
         self.voisins = self.lstVoisins(self.x, self.y)
         self.voisins = self.lstVoisins(self.x, self.y)
-        self.occupeePar = {}
+        self.occupation = {}
    
    
         #enregistrement du centre
         #enregistrement du centre
         if self.plateau.formeCases == "H":  #refPlateau
         if self.plateau.formeCases == "H":  #refPlateau
@@ -90,7 +92,7 @@ class Case(QGraphicsPolygonItem):
 
 
 #        #pour afficher les coordonnees des cases:  
 #        #pour afficher les coordonnees des cases:  
         self.etiquette = None
         self.etiquette = None
-#         self.afficherEtiquette("{}-{}".format(self.x,self.y))     
+        self.afficherEtiquette("{}-{}".format(self.x,self.y))     
 
 
         self.logoDep = LogoDep(self)
         self.logoDep = LogoDep(self)
         self.logoDep.creer()
         self.logoDep.creer()
@@ -178,79 +180,56 @@ class Case(QGraphicsPolygonItem):
     ########################
     ########################
 
 
     ### deplacement
     ### deplacement
-    def estFranchissable(self, z=0):
-        """la case est-elle franchissable?"""
-        retour = True
-        if self.terrain.franchissable == False:
-            retour = False
-        else:
-            if self.estOccupee(z) == True:
-                retour = False
-        return retour
-
     def coutDep(self):
     def coutDep(self):
         #a implementer, en fonction des
         #a implementer, en fonction des
         #capacites de deplacement du pion actuellement selectionne
         #capacites de deplacement du pion actuellement selectionne
         return 1
         return 1
 
 
     ### occupation
     ### occupation
-    def majOccupation(self, objet, nouveauZ = None):
-        """met a jour l'occupation de la case par les pions, decors..."""
-        if objet != None:
-            if not objet in self.occupeePar and nouveauZ != None:
-                #on ajoute l'objet a la liste des objets occupant la case ou on met a jour son altitude
-                casesOccupees = []
-                for i in range(0, objet.hauteur):
-                    casesOccupees.append(self.altitude + nouveauZ + i)
-                self.occupeePar[objet] = casesOccupees
-                
-            elif objet in self.occupeePar and nouveauZ == None:
-                #on supprime l'objet de la liste des objets occupant la case
-                del self.occupeePar[objet]
-            else:
-                pass
+    def occuper(self, numPion, z):
+        """un pion vient occuper la case a l'altitude z"""
+        self.occupation[z] = numPion
+
+    def liberer(self, z):
+        """aucun pion n'occupe plus la case a l'altitude z"""
+        if z in self.occupation:
+            del self.occupation[z]
             
             
-    def estOccupee(self, z=0):
+    def estOccupee(self, z=None):
         """renvoie vrai si la case correspondant a la hauteur z est occupee"""
         """renvoie vrai si la case correspondant a la hauteur z est occupee"""
-        retour = False
-        for objet in self.occupeePar:
-            if objet.hauteur > 0 and z in self.occupeePar[objet]:
-                retour = True
-        return retour        
+        if z:
+            retour = (z in self.occupation) 
+        else:
+            retour = len(self.occupation) > 0
+        return retour       
 
 
-    def estOccupeePar(self, z=0):
+    def occupant(self, z=None, classe = Pion):
         """si la case correspondant a la hauteur z est occupee, renvoie l'objet en question
         """si la case correspondant a la hauteur z est occupee, renvoie l'objet en question
            sinon renvoie None"""
            sinon renvoie None"""
+        num = None
+        if z:
+            if z in self.occupation:
+                num = self.occupation[z]   
+        else:
+            #si aucune altitude n'est donnee, renvoie le premier occupant
+            for z in self.occupation:
+                num = self.occupation[z]
+                break
         retour = None
         retour = None
-        for objet in self.occupeePar:
-            if objet.hauteur > 0 and z in self.occupeePar[objet]:
-                retour = objet
-        return retour  
+        if num:
+            if num < 10000:
+                retour = self.plateau.combattants[num]
+            else:
+                retour = self.plateau.decors[num] 
+        if retour:
+            if not isinstance(retour, classe): retour = None        
+        return retour                          
 
 
-    def pionOccupant(self):
-        """si un pion occupe cette case, le renvoie"""
-        retour = None
-        for objet in self.occupeePar:
-            if objet.__class__.__name__ == "Combattant":
-                retour = objet
-        return retour          
-
-
-    #autres interaction de combat
-    def estObstacleVision(self, hauteurObs):
-        """renvoie vrai si la case et l'eventuel decor qui l'occupe bloquent le champ de
-           vision d'un observateur situe a la hauteur precisee"""
-        retour = False
-        if self.altitude > hauteurObs:
-            retour = True
-        else:
-            hauteurObstacle = 0
-            for objet in self.occupeePar:
-                if objet.hauteur > hauteurObstacle:
-                    hauteurObstacle = objet.hauteur
-            if (self.altitude + hauteurObstacle) > hauteurObs:
-                retour = True
-        return retour                
+    def estFranchissable(self, zAbs = None):
+        """a l'altitude absolue demandee, 
+        la case est-elle franchissable pour une ligne de mire ou un deplacement"""
+        if not zAbs: zAbs = self.altitude
+        return (not self.estOccupee( (zAbs - self.altitude) ) and (zAbs >= self.altitude))
 
 
     ########## fonctions de maj ###########
     ########## fonctions de maj ###########
     def majTerrain(self, terrain = Terrain()):
     def majTerrain(self, terrain = Terrain()):
@@ -269,7 +248,7 @@ class Case(QGraphicsPolygonItem):
     def majAltitude(self, altitude):
     def majAltitude(self, altitude):
         """met a jour l'altitude de la case"""
         """met a jour l'altitude de la case"""
         self.altitude = altitude  
         self.altitude = altitude  
-        self.afficherEtiquette(altitude)   
+#         self.afficherEtiquette(altitude)   
 
 
     def majAffichageDeplacement(self, cout, valide = True):
     def majAffichageDeplacement(self, cout, valide = True):
         """lorsque cette case est sur le chemin d'un pion,
         """lorsque cette case est sur le chemin d'un pion,
@@ -618,10 +597,5 @@ class PolygoneCache(QGraphicsPolygonItem):
             event.ignore()
             event.ignore()
         return autorise
         return autorise
 
 
-#     def hoverEnterEvent(self, event):
-#         print "1"
-#         if not self.case.estCachee():
-#             print "2"
-#             self.case.plateau.caseSurvol(self.case.x, self.case.y)
-#         event.accept()    
+
         
         

+ 2 - 2
lib/EcranEditionCombattant.py

@@ -111,7 +111,7 @@ class EcranEditionCombattant(QDialog):
         self.vueForme.chargerEtiquetteDef(self.combattant.etiquette)
         self.vueForme.chargerEtiquetteDef(self.combattant.etiquette)
 
 
         #page deplacements
         #page deplacements
-        self.ui.edc_taille.setValue(self.combattant.taille)
+        self.ui.edc_taille.setValue(self.combattant.hauteur)
         self.ui.edc_depMarche.setValue(self.combattant.depMarche)
         self.ui.edc_depMarche.setValue(self.combattant.depMarche)
         self.ui.edc_depNage.setValue(self.combattant.depNage)
         self.ui.edc_depNage.setValue(self.combattant.depNage)
         self.ui.edc_depEscalade.setValue(self.combattant.depEscalade)
         self.ui.edc_depEscalade.setValue(self.combattant.depEscalade)
@@ -329,7 +329,7 @@ class EcranEditionCombattant(QDialog):
         self.combattant.etiquette = self.vueForme.etiquetteDef()
         self.combattant.etiquette = self.vueForme.etiquetteDef()
 
 
         #page dep
         #page dep
-        self.combattant.taille = self.ui.edc_taille.value()
+        self.combattant.hauteur = self.ui.edc_taille.value()
         self.combattant.depMarche = self.ui.edc_depMarche.value()
         self.combattant.depMarche = self.ui.edc_depMarche.value()
         self.combattant.depNage = self.ui.edc_depNage.value()
         self.combattant.depNage = self.ui.edc_depNage.value()
         self.combattant.depEscalade = self.ui.edc_depEscalade.value()
         self.combattant.depEscalade = self.ui.edc_depEscalade.value()

+ 0 - 1
lib/Forme.py

@@ -150,5 +150,4 @@ class Forme():
                     if 1==(coordRelatives[0]%2):
                     if 1==(coordRelatives[0]%2):
                         cy = -1
                         cy = -1
                 retour.append((coordCibles[0]+coordRelatives[0], coordCibles[1]+coordRelatives[1]+cy))
                 retour.append((coordCibles[0]+coordRelatives[0], coordCibles[1]+coordRelatives[1]+cy))
-##                retour.append((coordCibles[0]+coordRelatives[0], coordCibles[1]+coordRelatives[1]))
         return retour
         return retour

+ 2 - 3
lib/Modes.py

@@ -418,7 +418,7 @@ class CreationPion(ModeBaseCp):
 
 
     def clic_case(self, coord):
     def clic_case(self, coord):
         if self._pion:
         if self._pion:
-            if not self.plateau.cases[coord].pionOccupant():
+            if not self.plateau.cases[coord].estOccupee():
                 if isinstance(self._pion, Combattant) and dmK.touchesEnfoncees() == ["maj"]:
                 if isinstance(self._pion, Combattant) and dmK.touchesEnfoncees() == ["maj"]:
                     nouveauZ = self.plateau.dialogueVol(self._pion.z)
                     nouveauZ = self.plateau.dialogueVol(self._pion.z)
                     self._pion.majZ(nouveauZ)
                     self._pion.majZ(nouveauZ)
@@ -533,8 +533,7 @@ class DeplacementPion(ModeBaseCp):
             elif event.key() == Qt.Key_Left:
             elif event.key() == Qt.Key_Left:
                 self.plateau.proj.majRotation(-1)
                 self.plateau.proj.majRotation(-1)
                 self.deplace = True
                 self.deplace = True
-
-
+        
 #-----------------------------------------------
 #-----------------------------------------------
 #-----------------------------------------------
 #-----------------------------------------------
 
 

+ 14 - 5
lib/Pion.py

@@ -92,6 +92,10 @@ class Pion(QGraphicsItem):
         if valeur != self.z:
         if valeur != self.z:
             self.z = valeur    
             self.z = valeur    
 
 
+    def zAbs(self):
+        """retourne la coord z absolue du pion"""
+        return (self.plateau.cases[self.position].altitude + self.z)
+
     ########### fonctions graphiques et geometriques   ##############
     ########### fonctions graphiques et geometriques   ##############
     def ajouterAuPlateau(self, plateau):
     def ajouterAuPlateau(self, plateau):
         """cerre l'objet graphique representant le pion et le place sur le plateau"""
         """cerre l'objet graphique representant le pion et le place sur le plateau"""
@@ -154,8 +158,9 @@ class Pion(QGraphicsItem):
         if self.plateau:
         if self.plateau:
             #on met a jour l'occupation des cases
             #on met a jour l'occupation des cases
             if self.position != (-1,-1):
             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)
+                for coord in self.forme.listeCases(self.position, self.nbRotations):
+                    for z in range(self.z, (self.z + self.hauteur)):
+                        self.plateau.cases[coord].liberer(z)
 
 
             #on met a jour la position du pion        
             #on met a jour la position du pion        
             self.position = nouvellePosition
             self.position = nouvellePosition
@@ -176,8 +181,9 @@ class Pion(QGraphicsItem):
             self.majImage()
             self.majImage()
             
             
             #on met a jour l'occupation des cases
             #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)
+            for coord in self.forme.listeCases(self.position, self.nbRotations):
+                for z in range(self.z, (self.z + self.hauteur)):
+                    self.plateau.cases[coord].occuper(self.numero, z)
                  
                  
     def majImage(self):
     def majImage(self):
         """met a jour la taille, la position et l'orientation de l'image"""
         """met a jour la taille, la position et l'orientation de l'image"""
@@ -236,6 +242,10 @@ class Pion(QGraphicsItem):
 
 
     def retirerDuPlateau(self):
     def retirerDuPlateau(self):
         """'deconnecte' les items enfants avant de supprimer du pion du plateau"""
         """'deconnecte' les items enfants avant de supprimer du pion du plateau"""
+        for coord in self.forme.listeCases(self.position, self.nbRotations):
+            for z in range(self.z, (self.z + self.hauteur)):
+                self.plateau.cases[coord].liberer(z)
+
         self.polygoneBrillance.prepareGeometryChange()
         self.polygoneBrillance.prepareGeometryChange()
         self.polygoneBrillance.setParentItem(None)
         self.polygoneBrillance.setParentItem(None)
         if self.pixGraphique != None:
         if self.pixGraphique != None:
@@ -291,7 +301,6 @@ class Pion(QGraphicsItem):
     ###############   evenements clavier et souris    ##############
     ###############   evenements clavier et souris    ##############
     def boundingRect(self):
     def boundingRect(self):
         return QRectF()
         return QRectF()
-
         
         
      #######################
      #######################
 
 

+ 83 - 112
lib/Plateau.py

@@ -1,14 +1,9 @@
 #from __future__ import unicode_literals
 #from __future__ import unicode_literals
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 from __future__ import division
 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.QtCore import *
 from PyQt4.QtGui import *
 from PyQt4.QtGui import *
-from PyQt4 import QtOpenGL
 
 
 ##from ui.ecran_editionAttaques import Ui_editionAttaques
 ##from ui.ecran_editionAttaques import Ui_editionAttaques
 
 
@@ -17,11 +12,9 @@ import Actions
 from Case import Case
 from Case import Case
 from Combattant import Combattant
 from Combattant import Combattant
 from Decor import Decor
 from Decor import Decor
-from Forme import Forme
 from Pinceau import Pinceau
 from Pinceau import Pinceau
 from ProjectionDep import ProjectionDep
 from ProjectionDep import ProjectionDep
 from Cache import Cache
 from Cache import Cache
-from EntreeSortie import EntreeSortie
 from Terrain import Terrain
 from Terrain import Terrain
 
 
 from EcranEditionCombattant import EcranEditionCombattant
 from EcranEditionCombattant import EcranEditionCombattant
@@ -34,11 +27,9 @@ from EcranVol import EcranVol
 
 
 import regles as regles
 import regles as regles
 from outilsSvg import *
 from outilsSvg import *
-from lancer import jet, estJetValide
 import br
 import br
 
 
-from operator import itemgetter, attrgetter
-from math import *
+from math import sqrt
 
 
 m_couleursRapides = [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \
 m_couleursRapides = [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \
                    (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \
                    (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \
@@ -177,7 +168,7 @@ class Plateau(QGraphicsScene):
         img = QPixmap(1024, 768)
         img = QPixmap(1024, 768)
         img.fill(QColor("white"))
         img.fill(QColor("white"))
         peintre = QPainter(img)
         peintre = QPainter(img)
-        rendu = self.render(peintre)
+        self.render(peintre)
         peintre.end()
         peintre.end()
         img.scaledToHeight(128, Qt.FastTransformation)
         img.scaledToHeight(128, Qt.FastTransformation)
         
         
@@ -240,12 +231,13 @@ class Plateau(QGraphicsScene):
         self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
 
 
         self.fenetre.connect(self.fenetre.ui.pi_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection)
+        self.fenetre.connect(self.fenetre.ui.pi_vol, SIGNAL("clicked()"), self.majModeCombatVol, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_formeAttaqueZone, SIGNAL("activated (int)"), self.majModeCombatZone, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_formeAttaqueZone, SIGNAL("activated (int)"), self.majModeCombatZone, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_rayonAttaqueZone, SIGNAL("valueChanged(int)"), self.majRayonZone, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_rayonAttaqueZone, SIGNAL("valueChanged(int)"), self.majRayonZone, Qt.UniqueConnection)
-##        self.fenetre.connect(self.fenetre.ui.pi_vol, SIGNAL("clicked()"), self.fenetre.barreCombatVol, Qt.UniqueConnection)
+
         
         
         self.fenetre.connect(self.fenetre.ui.pi_finTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection)
         self.fenetre.connect(self.fenetre.ui.pi_finTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection)
         
         
@@ -344,7 +336,7 @@ class Plateau(QGraphicsScene):
         """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies"""
         """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies"""
         affichageTexte = EcranAffichageTexte(self.notes)
         affichageTexte = EcranAffichageTexte(self.notes)
         affichageTexte.setAttribute(Qt.WA_DeleteOnClose)
         affichageTexte.setAttribute(Qt.WA_DeleteOnClose)
-        r = affichageTexte.exec_()
+        affichageTexte.exec_()
         self.notes = affichageTexte.recupererTexte()
         self.notes = affichageTexte.recupererTexte()
         
         
     ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees""""     
     ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees""""     
@@ -656,6 +648,10 @@ class Plateau(QGraphicsScene):
         """active le mode de combat 'deplacement' (mode standard)"""
         """active le mode de combat 'deplacement' (mode standard)"""
         self.modeActif.nouvelleAction(Actions.Deplacement)
         self.modeActif.nouvelleAction(Actions.Deplacement)
 
 
+    def majModeCombatVol(self):
+        """active le mode de combat 'vol'"""
+        self.modeActif.nouvelleAction(Actions.Vol)
+
     def majModeCombatAttaqueCaC(self):
     def majModeCombatAttaqueCaC(self):
         """active le mode de combat 'corps-a-corps'"""
         """active le mode de combat 'corps-a-corps'"""
         self.modeActif.nouvelleAction(Actions.Cac)
         self.modeActif.nouvelleAction(Actions.Cac)
@@ -922,17 +918,6 @@ class Plateau(QGraphicsScene):
             numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))        
             numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))        
             self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_notesAttaqueEC.toPlainText().toUtf8())
             self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_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 majNotesCombattant(self):
     def majNotesCombattant(self):
         """les notes du pion ont ete mises a jour"""
         """les notes du pion ont ete mises a jour"""
         if self.pionSelectionne() != None:
         if self.pionSelectionne() != None:
@@ -966,40 +951,37 @@ class Plateau(QGraphicsScene):
             else:
             else:
                 voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
                 voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
         else:
         else:
-##            voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x+1, y+1), (x,   y+1), (x-1, y+1), (x-1, y), (x-1, y-1)]
             voisins = [(x, y-1), (x+1, y), (x,   y+1), (x-1, y)]
             voisins = [(x, y-1), (x+1, y), (x,   y+1), (x-1, y)]
         return voisins      
         return voisins      
 
 
-    def zone(self, origine, distance, z=0, conditionFranchissable = False, conditionVisible = False):
+    def zone(self, origine, rayon, z=0, conditionFranchissable = False, conditionVisible = False):
         """renvoie un dictionnaire representant la liste des coordonnees des cases comprises dans la zone
         """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
            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
            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
            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)]"""
-        
+           conditionVisible = Vrai -> les cases bloquant la visibilite ne sont pas prises en compte"""
         aVerifier = []
         aVerifier = []
         aVerifier2 = []
         aVerifier2 = []
         resultat = {}
         resultat = {}
-        k = 0           
-        #on part de la premiere case, puis on itere a partir de chaque nouveau depart
+        k = 0        
+        #on part de la premiere case, puis on itere a partir de chaque nouveau depart sur les voisins
         if origine in self.cases:
         if origine in self.cases:
             aVerifier.append(origine)
             aVerifier.append(origine)
-            while k <= distance:
+            while k <= rayon:
                 for depart in aVerifier:
                 for depart in aVerifier:
                     for coord in self.cases[depart].voisins:
                     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)      
+                        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:
                 for elt in aVerifier:
                     resultat[elt] = k
                     resultat[elt] = k
                 aVerifier = aVerifier2
                 aVerifier = aVerifier2
@@ -1008,39 +990,16 @@ class Plateau(QGraphicsScene):
          
          
         return resultat
         return resultat
 
 
-#     def casesEntre(self, coord1, coord2):
-#         """renvoie la liste des cases qui composent le chemin le plus direct
-#             entre les 2 cases en parametre"""
-#         #on determine le secteur et on calcule l'angle du chemin
-#         if coord2[0] != coord1[0]:
-#             if coord2[0] > coord1[0] and coord2[1] <= coord1[1] #0 a 3h
-#                 secteur = 1
-#             elif coord2[0] > coord1[0] and coord2[1] > coord1[1] #3 a 6h
-#                 secteur = 2           
-#             elif coord2[0] < coord1[0] and coord2[1] >= coord1[1] #6 a 9h
-#                 secteur = 3             
-#             elif coord2[0] < coord1[0] and coord2[1] < coord1[1] #9 a 12h
-#                 secteur = 4             
-#             angle = (coord2[1] - coord1[1]) / (coord2[0] - coord1[0])
-#         else:
-#             s = 0
-#             angle = 1
-# 
-#         #on preselectionne les cases concernees
-#         preselect = []
-#         xmin = mini(coord1[0], coord2[0]); xmax = maxi(coord1[0], coord2[0])
-#         ymin = mini(coord1[1], coord2[1]); ymax = maxi(coord1[1], coord2[1])
-#         for coord in self.cases:
-#             if xmin <= coord[0] <= xmax and ymin <= coord[1] <= ymax:
-#                 preselect.append()
-#         
-#         #on progresse de case en case en avancant selon l'angle
-#         coordTest = coord1
-#         while coordTest != coord2:
-#             for coord in preselect: 
-#                 pass
-#         
-
+    def zone3d(self, origine, rayon, zCible=0):
+        """renvoie les cases de la zone au format (x, y, z)"""
+        retour = []
+        zone = self.zone(origine, rayon)
+        for coord in zone:
+            x, y = coord
+            dz = rayon - zone[coord]
+            for z in range(-dz, dz + 1):
+                retour.append( (x, y, (zCible+z) ) )
+        return retour            
 
 
     def polygoneAgglo(self, listeCases):
     def polygoneAgglo(self, listeCases):
         """renvoie un polygone contruit par agglomeration des polygones des cases de la liste
         """renvoie un polygone contruit par agglomeration des polygones des cases de la liste
@@ -1065,10 +1024,10 @@ class Plateau(QGraphicsScene):
                 
                 
                 for i in range(0, len(voisins)):
                 for i in range(0, len(voisins)):
                     if not voisins[i] in listeCases:
                     if not voisins[i] in listeCases:
-                       j = i+1
-                       if j > len(voisins) - 1:
-                           j = 0
-                       segments.append(QLineF(polygone[i], polygone[j]))
+                        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
             #on 'accroche' les segments les uns aux autres, dans l'ordre
             segments2 = [segments[0]]
             segments2 = [segments[0]]
@@ -1086,7 +1045,7 @@ class Plateau(QGraphicsScene):
             for segment in segments2:
             for segment in segments2:
                 pointSuivant = segment.p2()
                 pointSuivant = segment.p2()
                 if pointSuivant != premierPoint:
                 if pointSuivant != premierPoint:
-                     pointsPolygone.append(pointSuivant)
+                    pointsPolygone.append(pointSuivant)
 
 
             #creation du polygone
             #creation du polygone
             polygone = QPolygonF()
             polygone = QPolygonF()
@@ -1157,7 +1116,7 @@ class Plateau(QGraphicsScene):
                             contenu = False
                             contenu = False
                             break
                             break
                     if contenu == False:
                     if contenu == False:
-                         tmp.append(coord)    
+                        tmp.append(coord)    
         #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
         #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
         if not plein and epaisseur > 0:
         if not plein and epaisseur > 0:
             for coord in tmp:
             for coord in tmp:
@@ -1190,22 +1149,46 @@ class Plateau(QGraphicsScene):
             preSelection = self.cases
             preSelection = self.cases
         return preSelection
         return preSelection
     
     
+    def listeZCible(self, coord):
+        """retourne l'altitude absolue a prendre en compte en fonction de la case ciblee
+            c'est l'altitude la case si aucun pion n'occupe la case
+            c'est la liste des cases occupees en hauteur par le pion sinon
+            'coord' est de la forme (x, y)"""
+        if self.cases[coord].estOccupee():
+            retour = range(self.cases[coord].occupant().zAbs(), \
+                            self.cases[coord].occupant().zAbs() + self.cases[coord].occupant().hauteur)
+        else:
+            retour = [self.cases[coord].altitude]             
+        return retour
 
 
-    def estCibleAttaqueDistValide(self, coordOrigine, coordCible):
-         """la case cible est elle valide pour une attaque a distance depuis la position et hauteur
+    def estCibleAttaqueDistValide(self, coordCible):
+        """la case cible est elle valide pour une attaque a distance depuis la position et hauteur
             du pion selectionne
             du pion selectionne
-            les coord sont de la forme (x, y, z)"""
-         valide = True
-         if coordOrigine[0] != coordCible[0] and coordOrigine[1] != coordCible[1]:
-             casesLigneMire = br.ligne(coordOrigine, coordCible, self.formeCases)
-             casesLigneMire.remove(coordOrigine)
-             casesLigneMire.remove(coordCible)
-             for coord in casesLigneMire:
-                x, y, z = coord
-                if self.cases[(x,y)].estOccupee(z): 
-                    valide = False
+            les coord sont de la forme (x, y)"""
+        valide = False
+        x1, y1 = self.pionSelectionne().position
+        coordOrigine = (x1, y1, (self.pionSelectionne().zAbs() + self.pionSelectionne().hauteur))
+        
+        x2, y2 = coordCible
+        cible = self.cases[coordCible].occupant()
+        listeZ2 = self.listeZCible(coordCible)      
+        if coordOrigine[0] != coordCible[0] or coordOrigine[1] != coordCible[1]:
+            for z2 in listeZ2:
+                zValide = True
+                casesLigneMire = br.ligne(coordOrigine, (x2, y2, z2), self.formeCases)
+                casesLigneMire.remove(coordOrigine)
+                casesLigneMire.remove((x2, y2, z2))
+                for coord in casesLigneMire:
+                    if zValide:
+                        x, y, z = coord
+                        if self.cases[(x,y)].estOccupee(z): 
+                            if self.cases[(x,y)].occupant(z) not in [self.pionSelectionne(), cible]:
+                                zValide = False
+                if zValide: 
+                    valide = True #si au moins un des z cibles est valide, la ligne de mire est valide
                     break
                     break
-         return valide       
+                
+        return valide       
                       
                       
     def pionSurCase(self, coord):
     def pionSurCase(self, coord):
         """renvoie le pion present sur la case, none sinon"""
         """renvoie le pion present sur la case, none sinon"""
@@ -1219,7 +1202,7 @@ class Plateau(QGraphicsScene):
         """renvoie la liste des num des pions presents sur la liste de cases"""
         """renvoie la liste des num des pions presents sur la liste de cases"""
         retour = []
         retour = []
         for coord in listeCases:
         for coord in listeCases:
-            pion = self.cases[coord].pionOccupant()
+            pion = self.cases[coord].occupant()
             if pion != None and not pion.numero in retour:
             if pion != None and not pion.numero in retour:
                 retour.append(pion.numero)
                 retour.append(pion.numero)
         return retour   
         return retour   
@@ -1287,7 +1270,6 @@ class Plateau(QGraphicsScene):
 
 
     def pionClique(self, num):
     def pionClique(self, num):
         """on a clique sur ce pion"""
         """on a clique sur ce pion"""
-        accepte = False
         if num < 10000:
         if num < 10000:
             self.modeActif.clic_combattant(num)
             self.modeActif.clic_combattant(num)
         else:
         else:
@@ -1375,8 +1357,8 @@ class Plateau(QGraphicsScene):
             pion = self.pionSelectionne()
             pion = self.pionSelectionne()
         
         
         if pion != None:
         if pion != None:
-           if self.proj.projectionValide():        
-               pion.majPosition(self.proj.coord(), self.proj.nbRotations())
+            if self.proj.projectionValide():        
+                pion.majPosition(self.proj.coord(), self.proj.nbRotations())
 
 
     def majZPion(self, valeur):
     def majZPion(self, valeur):
         """met a jour l'altitude du pion selectionne"""
         """met a jour l'altitude du pion selectionne"""
@@ -1384,7 +1366,6 @@ class Plateau(QGraphicsScene):
             self.pionSelectionne().majZ(valeur)
             self.pionSelectionne().majZ(valeur)
 
 
     def dialogueVol(self, actuelle):
     def dialogueVol(self, actuelle):
-        nouvelle = actuelle
         ecran = EcranVol(actuelle)
         ecran = EcranVol(actuelle)
         ecran.exec_() 
         ecran.exec_() 
         nouvelle = ecran.resultat()
         nouvelle = ecran.resultat()
@@ -1395,20 +1376,12 @@ class Plateau(QGraphicsScene):
         """supprime le pion entre en parametre"""
         """supprime le pion entre en parametre"""
         #settrace(trace_calls)
         #settrace(trace_calls)
         if num in self.combattants:    
         if num in self.combattants:    
-            for coord in self.combattants[num].forme.listeCases(self.combattants[num].position, self.combattants[num].nbRotations):
-                 self.cases[coord].majOccupation(self.combattants[num])
             self.pionDeplacerDansOrdreJeu(num, 0)
             self.pionDeplacerDansOrdreJeu(num, 0)
             pionSuppr = self.combattants.pop(num)
             pionSuppr = self.combattants.pop(num)
-            pionSuppr.retirerDuPlateau()
-            
         elif num in self.decors:    
         elif 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])
             pionSuppr = self.decors.pop(num)
             pionSuppr = self.decors.pop(num)
-            pionSuppr.retirerDuPlateau()
             
             
-        else:
-            print("erreur: ce pion n'est pas dans la liste des pions")
+        pionSuppr.retirerDuPlateau()
             
             
     ###############
     ###############
 
 
@@ -1470,7 +1443,6 @@ class Plateau(QGraphicsScene):
     def supprimerCache(self):
     def supprimerCache(self):
         ligne = self.fenetre.ui.cp_listeCaches.currentRow()
         ligne = self.fenetre.ui.cp_listeCaches.currentRow()
         idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0)) 
         idCache = int(self.fenetre.ui.cp_listeCaches.texte(ligne, 0)) 
-        nouveauNom = self.fenetre.ui.cp_listeCaches.texte(ligne, 1)
         for coord in self.cases:
         for coord in self.cases:
             self.cases[coord].supprimerCache(idCache)
             self.cases[coord].supprimerCache(idCache)
         self.fenetre.ui.cp_listeCaches.removeRow(idCache)
         self.fenetre.ui.cp_listeCaches.removeRow(idCache)
@@ -1530,7 +1502,6 @@ class Plateau(QGraphicsScene):
 
 
     def keyPressEvent(self, event):
     def keyPressEvent(self, event):
         """gestion des evenements clavier"""
         """gestion des evenements clavier"""
-        toucheClavier = event.key()
         self.modeActif.toucheClavier(event)
         self.modeActif.toucheClavier(event)
 
 
     ################   
     ################   

+ 2 - 2
lib/ProjectionDep.py

@@ -66,10 +66,10 @@ class ProjectionDep():
                     ok += 1
                     ok += 1
                 else:
                 else:
                     #si la case est occupee par le pion lui-meme
                     #si la case est occupee par le pion lui-meme
-                    if self.plateau.cases[coord].estOccupeePar(self.z()) == None:
+                    if not self.plateau.cases[coord].estOccupee(self.z()):
                         ok += 1
                         ok += 1
                     else:
                     else:
-                        if self.plateau.cases[coord].estOccupeePar(self.z()) == self._pion:
+                        if self.plateau.cases[coord].occupant(self.z()) == self._pion:
                             ok += 1
                             ok += 1
         valide = (ok == compte and compte > 0)
         valide = (ok == compte and compte > 0)
         return valide        
         return valide        

二进制
lib/biblio/combattant


二进制
lib/biblio/decor


+ 4 - 2
lib/br.py

@@ -4,7 +4,7 @@ from math import *
 from dmF import *
 from dmF import *
 
 
 def ligne(coord1, coord2, formeCases = "H"):
 def ligne(coord1, coord2, formeCases = "H"):
-    if coord1[0] != coord2[0] and coord1[1] != coord2[1]:
+    if coord1[0] != coord2[0] or coord1[1] != coord2[1]:
         if len(coord1) == 2 and len(coord2) == 2:
         if len(coord1) == 2 and len(coord2) == 2:
             retour = _ligne2d(coord1, coord2, formeCases)
             retour = _ligne2d(coord1, coord2, formeCases)
         elif len(coord1) == 3 and len(coord2) == 3:
         elif len(coord1) == 3 and len(coord2) == 3:
@@ -18,7 +18,8 @@ def ligne(coord1, coord2, formeCases = "H"):
         else:
         else:
             retour = [coord1]   
             retour = [coord1]   
     else:            
     else:            
-        retour = [coord1]         
+        retour = [coord1]
+         
     return retour    
     return retour    
                 
                 
 def _ligne2d(coord1, coord2, formeCases = "H"):
 def _ligne2d(coord1, coord2, formeCases = "H"):
@@ -196,3 +197,4 @@ def _brH_v(x1, y1, x2, y2):
             break
             break
 
 
     return retour 
     return retour 
+

+ 0 - 10
lib/ui/dm.py

@@ -17,13 +17,6 @@ except:
         import regles as regles
         import regles as regles
     except:
     except:
         print "dm: impossible de charger regles"
         print "dm: impossible de charger regles"
-try:
-    from lib.Actions import *
-except:
-    try:
-        from Actions import *
-    except:
-        print "dm: impossible de charger Actions"
 
 
 class Biblio():
 class Biblio():
     """cette classe fournit une liste spreciale"""
     """cette classe fournit une liste spreciale"""
@@ -154,9 +147,6 @@ class DmTabInventaire(QTabWidget):
         utilisee pour filtrer les types d'objets affiches"""
         utilisee pour filtrer les types d'objets affiches"""
     def __init__(self, parent = None):
     def __init__(self, parent = None):
         super(DmTabInventaire, self).__init__(parent)
         super(DmTabInventaire, self).__init__(parent)
-##        self.setStyleSheet(QString.fromUtf8("""QTabWidget::tab-bar { alignment: right;
-##                                               background: rgba(0,248,248,200) }"""))
-
         self.setStyleSheet(QString.fromUtf8("""
         self.setStyleSheet(QString.fromUtf8("""
                                              QTabWidget::pane { border-top: 2px solid #C2C7CB; }
                                              QTabWidget::pane { border-top: 2px solid #C2C7CB; }
                                              QTabWidget::tab-bar { alignment: right; }
                                              QTabWidget::tab-bar { alignment: right; }

+ 1 - 1
lib/ui/mainwindow.ui

@@ -1279,7 +1279,7 @@
                </size>
                </size>
               </property>
               </property>
               <property name="currentIndex">
               <property name="currentIndex">
-               <number>1</number>
+               <number>2</number>
               </property>
               </property>
               <widget class="QWidget" name="cbt_panneauDroite0"/>
               <widget class="QWidget" name="cbt_panneauDroite0"/>
               <widget class="QWidget" name="cbt_panneauDroite1">
               <widget class="QWidget" name="cbt_panneauDroite1">

二进制
parties/Partie1/svg/0.p


二进制
parties/Partie1/svg/1.p


二进制
parties/Partie1/svg/2.p


二进制
parties/Partie1/svg/3.p


二进制
parties/Partie1/svg/4.p


+ 2 - 3
parties/Partie1/svg/infos_sauvegarde

@@ -1,3 +1,2 @@
-€}q(U1}q(UnomUsfUdateCreationGAÕe¦Ï+SøUdateSvgGAÕe§
--/UchapitreU1UenCours‰Upublic‰uU0}q(UnomUtestUdateCreationGAÕe¤/c•�UdateSvgGAÕe¤4iº^UchapitreU1UenCours‰Upublic‰uU3}q(UnomqUghjqUdateCreationqGAÕg ŠŠ-UdateSvgqGAÕg¡^G;dUchapitreq	U1UenCoursq
-‰Upublicq‰uU2}q(UnomUfsdfUdateCreationGAÕe§9Õ`BUdateSvgGAÕe§E>{UchapitreU1UenCours‰Upublic‰uu.
+€}q(U1}q(UnomqUtestqUdateCreationqGAÕgíƒUdateSvgqGAÕgöÕ“uUchapitreqU1UenCoursq‰Upublicq	‰uU4}q
+(UnomUdfgUdateCreationGAÕgìï�©üUdateSvgGAÕgìù!%UchapitreU1UenCours‰Upublic‰uu.