Plateau.py 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513
  1. #from __future__ import unicode_literals
  2. # -*- coding: utf-8 -*-
  3. from __future__ import division
  4. import os
  5. from sys import exit, argv, getsizeof, settrace
  6. from time import time, sleep, strftime, localtime
  7. from threading import Thread
  8. from PyQt4.QtCore import *
  9. from PyQt4.QtGui import *
  10. from PyQt4 import QtOpenGL
  11. ##from ui.ecran_editionAttaques import Ui_editionAttaques
  12. import Modes
  13. import Actions
  14. from Case import Case
  15. from Combattant import Combattant
  16. from Decor import Decor
  17. from Forme import Forme
  18. from Pinceau import Pinceau
  19. from ProjectionDep import ProjectionDep
  20. from Cache import Cache
  21. from EntreeSortie import EntreeSortie
  22. from Terrain import Terrain
  23. from EcranEditionCombattant import EcranEditionCombattant
  24. from EcranEditionDecor import EcranEditionDecor
  25. from EcranEditionTerrain import EcranEditionTerrain
  26. from EcranAffichageTexte import EcranAffichageTexte
  27. from EcranGestionCombat import EcranGestionCombat
  28. from EcranSelectionPj import EcranSelectionPj
  29. import regles as regles
  30. from outilsSvg import *
  31. from lancer import jet, estJetValide
  32. from operator import itemgetter, attrgetter
  33. from math import *
  34. m_couleursRapides = [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \
  35. (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \
  36. (255,255,127), (240,80,0), (85,170,255), (85,85,255), (85,0,255), (0,255,255)]
  37. class Plateau(QGraphicsScene):
  38. """plateau de jeu contenant les cases, decors et pions"""
  39. def __init__(self, fenetre, parent=None):
  40. super(Plateau, self).__init__()
  41. #parametres et variables
  42. self.fenetre = fenetre
  43. ##partie et infos plateau
  44. self.id = ""
  45. self.nom = ""
  46. self.chapitre = 0
  47. self.tour = 1
  48. self.enCours = False
  49. self.public = False
  50. self.dateCreation = ""
  51. self.dateSvg = ""
  52. self.notes = ""
  53. #carac
  54. self.nbCasesX = 0
  55. self.nbCasesY = 0
  56. self.hCase = 0
  57. #objets
  58. self.pinceau = Pinceau(self)
  59. self.cases = {} #dict des cases du plateau (coordonnées: case)
  60. self.combattants = {} #liste de combattants positionnes sur le plateau
  61. self.decors = {} #liste des decors places sur le plateau
  62. self.cacheEnCours = 1
  63. self.caches = {}
  64. self.polygonesCaches = {}
  65. for i in range(1,5):
  66. self.caches[i] = {"actif":False,"listeCases":[]}
  67. self.polygonesCaches[i] = None
  68. self.listeCasesZonePlacement = []
  69. self.polygoneZonePlacement = None
  70. self.entreesSorties = []
  71. #infos combat
  72. self.numCombattantEnCours = 0
  73. self.ordreJeu = {} #numero du pion: ordre de jeu
  74. #note: la hauteur Z (qui gere l'empilement des objets graphiques est distribuee de cette maniere:
  75. #cases : 0 a 9
  76. #pions : 10 et +
  77. def __getstate__(self):
  78. self.dateSvg = time()
  79. state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", "cacheEnCours", \
  80. "editionTerrain", "editionCreature", "editionDecor", \
  81. "polygoneZonePlacement", "gestionCombat", "polygonesCaches", \
  82. "editionAttaques", "pinceau"]}
  83. return (state)
  84. def __setstate__(self, state):
  85. self.__dict__ = state
  86. def vue(self):
  87. return self.fenetre.ui.cbt_vue
  88. def creer(self, idPlateau, nom, chapitre, formeCases, nbCasesX, nbCasesY, couleur = QColor(0, 255, 0, 80)):
  89. """cree le plateau"""
  90. self.id = idPlateau
  91. self.nom = nom
  92. self.chapitre = chapitre
  93. self.dateCreation = time()
  94. self.hCase = 120 #hauteur d'une case
  95. self.nbCasesX = nbCasesX #nb cases en x
  96. self.nbCasesY = nbCasesY #nb cases en y
  97. self.formeCases = formeCases
  98. self.gestionCombat = None
  99. self.initialisationGraphique()
  100. self.connexions()
  101. #cree les cases hexagonales
  102. for x in range(nbCasesX):
  103. for y in range(nbCasesY):
  104. c = Case(self)
  105. c.creer(x, y, couleur)
  106. self.cases[(x,y)] = c
  107. self.plateauModeCreation()
  108. def recreer(self, fenetre):
  109. self.fenetre = fenetre
  110. self.gestionCombat = None
  111. super(Plateau, self).__init__()
  112. self.connexions()
  113. self.initialisationGraphique()
  114. #recreation des cases
  115. for coord in self.cases:
  116. self.cases[coord].recreer(self)
  117. #recreation des pions
  118. for numCombattant in self.combattants:
  119. self.combattants[numCombattant].ajouterAuPlateau(self)
  120. self.majOrdreJeu()
  121. #recreation des decors
  122. for num in self.decors:
  123. self.decors[num].ajouterAuPlateau(self)
  124. #recreation des marqueurs entree/sortie
  125. for entreeSortie in self.entreesSorties:
  126. entreeSortie.recreer(self)
  127. #recreation de la zone de placement:
  128. if len(self.listeCasesZonePlacement) > 0:
  129. self.polygoneZonePlacement = None
  130. self.majZonePlacement(self.listeCasesZonePlacement)
  131. #recreation des caches
  132. self.polygonesCaches = {}
  133. for i in range(1,5):
  134. self.polygonesCaches[i] = None
  135. self.plateauModeCombat()
  136. def fermer(self):
  137. """ferme le plateau 'proprement'"""
  138. self.miniature()
  139. self.pinceau = None
  140. for item in self.items():
  141. item.prepareGeometryChange()
  142. self.removeItem(item)
  143. if self.gestionCombat != None:
  144. del self.gestionCombat
  145. self.fenetre.reinitialiserPanneauxPlateau()
  146. def miniature(self):
  147. """renvoie une miniature du plateau (QPixMap compresse) qui sera enregistree avec les infos de la sauvegarde"""
  148. ## img = QImage(128, 128, QImage.Format_ARGB32_Premultiplied)
  149. img = QPixmap(1024, 768)
  150. img.fill(QColor("white"))
  151. peintre = QPainter(img)
  152. rendu = self.render(peintre)
  153. peintre.end()
  154. img.scaledToHeight(128, Qt.FastTransformation)
  155. def connexions(self):
  156. """connecte le plateau aux differents widgets de la fenetre principale"""
  157. #modes d'interaction
  158. self.fenetre.connect(self.fenetre.ui.cbt_modeCreation, SIGNAL("clicked()"), self.plateauModeCreation, Qt.UniqueConnection)
  159. self.fenetre.connect(self.fenetre.ui.cbt_modeCombat, SIGNAL("clicked()"), self.plateauModeCombat, Qt.UniqueConnection)
  160. ## self.fenetre.connect(self.fenetre.ui.modeAffichagePlateau, SIGNAL("currentIndexChanged(int)"), self.majModeAffichage, Qt.UniqueConnection)
  161. #affichage de fenetres
  162. self.fenetre.connect(self.fenetre.ui.cbt_afficherGestion, SIGNAL("clicked()"), self.afficheEcranGestionCombat, Qt.UniqueConnection)
  163. self.fenetre.connect(self.fenetre.ui.cbt_ajouterPj, SIGNAL("clicked()"), self.ajouterPj, Qt.UniqueConnection)
  164. self.fenetre.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee, Qt.UniqueConnection)
  165. self.fenetre.connect(self.fenetre.ui.cp_dialogueCouleurs, SIGNAL("clicked()"), self.modePeintureCase, Qt.UniqueConnection)
  166. self.fenetre.connect(self.fenetre.ui.cp_pipetteCouleur, SIGNAL("clicked()"), self.modeCopieTerrain, Qt.UniqueConnection)
  167. self.fenetre.connect(self.fenetre.ui.cp_afficherNotes, SIGNAL("clicked()"), self.agrandirNotesMjPlateau, Qt.UniqueConnection)
  168. #listes
  169. self.fenetre.connect(self.fenetre.ui.inf_listeOrdreJeu, SIGNAL("cellClicked(int,int)"), self.clicListOrdreJeu, Qt.UniqueConnection)
  170. self.fenetre.connect(self.fenetre.ui.cp_listeTerrains, SIGNAL("cellClicked(int,int)"), self.modeMajTerrainCase, Qt.UniqueConnection)
  171. self.fenetre.connect(self.fenetre.ui.cp_listeCreatures, SIGNAL("cellClicked(int,int)"), self.modeCreationCombattant, Qt.UniqueConnection)
  172. self.fenetre.connect(self.fenetre.ui.cp_listeDecors, SIGNAL("cellClicked(int,int)"), self.modeCreationDecor, Qt.UniqueConnection)
  173. self.fenetre.connect(self.fenetre.ui.cp_editerTerrain, SIGNAL("clicked()"), self.terrainEdit, Qt.UniqueConnection)
  174. self.fenetre.connect(self.fenetre.ui.cp_nouveauTerrain, SIGNAL("clicked()"), self.terrainNouveau, Qt.UniqueConnection)
  175. self.fenetre.connect(self.fenetre.ui.cp_editerCombattant, SIGNAL("clicked()"), self.creatureEdit, Qt.UniqueConnection)
  176. self.fenetre.connect(self.fenetre.ui.cp_nouveauCombattant, SIGNAL("clicked()"), self.creatureNouveau, Qt.UniqueConnection)
  177. self.fenetre.connect(self.fenetre.ui.cp_editerDecor, SIGNAL("clicked()"), self.decorEdit, Qt.UniqueConnection)
  178. self.fenetre.connect(self.fenetre.ui.cp_nouveauDecor, SIGNAL("clicked()"), self.decorNouveau, Qt.UniqueConnection)
  179. ## self.fenetre.connect(self.fenetre.ui.editerAttaques, SIGNAL("clicked()"), self.afficheEcranEditionAttaques, Qt.UniqueConnection)
  180. self.fenetre.connect(self.fenetre.ui.cp_supprimerPion, SIGNAL("clicked()"), self.majModePionSupprimer, Qt.UniqueConnection)
  181. #creation
  182. self.fenetre.connect(self.fenetre.ui.cp_epaisseurPinceau, SIGNAL("valueChanged(int)"), self.majEpaisseurPinceau, Qt.UniqueConnection)
  183. ## self.fenetre.connect(self.fenetre.ui.altitudeCase, SIGNAL("valueChanged(double)"), self.modeMajAltitudeCase, Qt.UniqueConnection)
  184. #autres:
  185. #ajouter effet
  186. self.fenetre.connect(self.fenetre.ui.cp_placerEntree, SIGNAL("clicked()"), self.majModeDefinirEntree, Qt.UniqueConnection)
  187. self.fenetre.connect(self.fenetre.ui.cp_placerSortie, SIGNAL("clicked()"), self.majModeDefinirSortie, Qt.UniqueConnection)
  188. self.fenetre.connect(self.fenetre.ui.cp_defPlacement, SIGNAL("clicked()"), self.majModeZonePlacement, Qt.UniqueConnection)
  189. ## self.fenetre.connect(self.fenetre.ui.cacheActif, SIGNAL("clicked()"), self.majEtatCacheEnCours, Qt.UniqueConnection)
  190. ## self.fenetre.connect(self.fenetre.ui.cacheVoir, SIGNAL("clicked()"), self.voirCacheEnCours, Qt.UniqueConnection)
  191. ## self.fenetre.connect(self.fenetre.ui.cachePlacer, SIGNAL("clicked()"), self.placerCacheEnCours, Qt.UniqueConnection)
  192. ## self.fenetre.connect(self.fenetre.ui.notesMjPlateau, SIGNAL("textChanged()"), self.majNotesPlateau, Qt.UniqueConnection)
  193. self.fenetre.connect(self.fenetre.ui.pi_notes, SIGNAL("textChanged()"), self.majNotesCombattant, Qt.UniqueConnection)
  194. #formes (dessin)
  195. self.fenetre.connect(self.fenetre.ui.cp_formeSimple, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  196. self.fenetre.connect(self.fenetre.ui.cp_formeLigne, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  197. self.fenetre.connect(self.fenetre.ui.cp_formeLigneOrientee, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  198. self.fenetre.connect(self.fenetre.ui.cp_formeEllipseVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  199. self.fenetre.connect(self.fenetre.ui.cp_formeEllipsePlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  200. self.fenetre.connect(self.fenetre.ui.cp_formeRectVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  201. self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  202. self.fenetre.connect(self.fenetre.ui.pi_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection)
  203. self.fenetre.connect(self.fenetre.ui.pi_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection)
  204. self.fenetre.connect(self.fenetre.ui.pi_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection)
  205. self.fenetre.connect(self.fenetre.ui.pi_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection)
  206. self.fenetre.connect(self.fenetre.ui.pi_formeAttaqueZone, SIGNAL("activated (int)"), self.majModeCombatZone, Qt.UniqueConnection)
  207. ## self.fenetre.connect(self.fenetre.ui.pi_vol, SIGNAL("clicked()"), self.fenetre.barreCombatVol, Qt.UniqueConnection)
  208. self.fenetre.connect(self.fenetre.ui.pi_finTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection)
  209. #self.fenetre.connect(self.fenetre.ui.combatVol_altitude, SIGNAL("editingFinished()"), self.majVisibiliteBarreCombat)
  210. def initialisationGraphique(self):
  211. """cree la scene graphique et les parametres necessaires a son fonctionnement, et met a jour l'interface"""
  212. #on cree la scene graphique
  213. kx = 1
  214. if self.formeCases == "H":
  215. kx = 0.866
  216. marge = 240
  217. self.setSceneRect(0 - marge, 0 - marge, (kx*self.hCase*(self.nbCasesX+2)) + marge, (self.hCase*(self.nbCasesY+2)) + marge)
  218. self.vue().setScene(self)
  219. self.vue().scale(0.25, 0.25)
  220. self.vue().centerOn(QPointF(0,0))
  221. self.vue().setDragMode(1)
  222. self.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
  223. self.polygoneZonePlacement = None
  224. self.polygonesCaches = {}
  225. for i in range(1,5):
  226. self.polygonesCaches[i] = None
  227. #gestion du mode d'interaction avec le plateau
  228. self.modeActif = Modes.StandardCp(self)
  229. self.pinceau = Pinceau(self)
  230. self.proj = ProjectionDep(self)
  231. #mise a jour de l'interface de creation
  232. self.fenetre.majVisibilitePanneauxPlateau("creation")
  233. ## self.fenetre.ui.cbt_nomPlateau.setText(QString.fromUtf8(self.nom))
  234. self.majBoutonsCouleursPerso()
  235. ## self.majBoutonsCaches()
  236. self.fenetre.ui.cp_listeTerrains.defFichier("lib\\biblio\\terrain")
  237. self.fenetre.ui.cp_listeTerrains.initAffichage()
  238. self.fenetre.ui.cp_listeCreatures.defFichier("lib\\biblio\\combattant")
  239. self.fenetre.ui.cp_listeCreatures.initAffichage()
  240. self.fenetre.ui.cp_listeDecors.defFichier("lib\\biblio\\decor")
  241. self.fenetre.ui.cp_listeDecors.initAffichage()
  242. self.majListeTerrains()
  243. self.majListeCreatures()
  244. self.majListeDecors()
  245. self.initListeOrdreJeu()
  246. self.initListeAttaques()
  247. self.fenetre.ui.pi_deplacement.setCheckable(True)
  248. self.fenetre.ui.pi_attaqueCac.setCheckable(True)
  249. self.fenetre.ui.pi_attaqueDist.setCheckable(True)
  250. self.fenetre.ui.pi_attaqueZone.setCheckable(True)
  251. #mise a jour de l'interface d'informations
  252. self.majInfosCombattant(None)
  253. self.majInfosDecor(None)
  254. def estCree(self):
  255. """renvoie vrai si des cases ont ete creees"""
  256. return (len(self.cases) > 0)
  257. def majBoutonsCouleursPerso(self):
  258. """met a jour l'affichage des couleurs customisees dans la boite de dialogue de selection de couleur"""
  259. for i in range(0,18):
  260. couleur = QColor()
  261. r, g, b = m_couleursRapides[i]
  262. couleur.setRgb(r, g, b)
  263. bouton = self.fenetre.ui.cp_boiteCouleurs.findChild(QToolButton, "cp_couleur{}".format(i+1))
  264. if couleur.isValid():
  265. bouton.setStyleSheet("QToolButton {backGround:%s}"%(couleur.name()))
  266. self.fenetre.connect(bouton, SIGNAL("clicked()"), self.modePeintureCase_perso)
  267. def chercherCouleur(self):
  268. """ouvre la boite de dialogue de selection de couleur"""
  269. couleur = QColorDialog(self.vue()).getColor(QColor("white"), self.vue())
  270. return couleur
  271. ## def majBoutonsCaches(self):
  272. ## """met a jour l'affichage et connecte les boutons de caches"""
  273. ## for i in range(1,5):
  274. ## bouton = self.fenetre.ui.outilsEditionPlateau.findChild(QToolButton, "plateauCache{}".format(i))
  275. ## self.fenetre.connect(bouton, SIGNAL("clicked()"), self.majAffichageMenuCache)
  276. def majListesPions(self, numCombattant = None):
  277. """met a jour les listes contenant des donnees liees aux pions"""
  278. ## self.majListeOrdreJeu()
  279. ##
  280. ## if numCombattant == None or numCombattant == self.pionSelectionne().numero:
  281. ## self.majListeAttributs()
  282. ## QApplication.processEvents()
  283. pass
  284. def ajouterPj(self):
  285. """affiche la fenetre de selection des pj, et recupere l'eventuel pj selectionne"""
  286. self.ecranSelPj = EcranSelectionPj(self.fenetre)
  287. self.ecranSelPj.setAttribute(Qt.WA_DeleteOnClose)
  288. listePj = chargerUnique("parties\\{}\\groupe".format(self.fenetre.partie))
  289. self.ecranSelPj.charger(listePj)
  290. r = self.ecranSelPj.exec_()
  291. if r == 1:
  292. idPj = int(self.ecranSelPj.selection())
  293. if idPj != None:
  294. pj = listePj[idPj]
  295. self.activerMode(Modes.CreationPion, pj)
  296. self.ecranSelPj = None
  297. def agrandirNotesMjPlateau(self):
  298. """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies"""
  299. affichageTexte = EcranAffichageTexte(self.notes)
  300. affichageTexte.setAttribute(Qt.WA_DeleteOnClose)
  301. r = affichageTexte.exec_()
  302. self.notes = affichageTexte.recupererTexte()
  303. ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees""""
  304. def afficheEcranEditionTerrains(self, terrain = None):
  305. """affiche l'ecran d'edition/creation de terrains"""
  306. self.editionTerrain = EcranEditionTerrain(terrain)
  307. self.editionTerrain.setAttribute(Qt.WA_DeleteOnClose)
  308. r = self.editionTerrain.exec_()
  309. if r == 1:
  310. self.majListeTerrains()
  311. def majListeTerrains(self):
  312. """mise a jour de la liste des terrains depuis la sauvegarde"""
  313. self.fenetre.ui.cp_listeTerrains.maj()
  314. self.activerMode(Modes.StandardCp)
  315. def terrainEdit(self):
  316. """ouvre la fenetre 'terrains' en mode edition"""
  317. index = self.fenetre.ui.cp_listeTerrains.item(self.fenetre.ui.cp_listeTerrains.currentRow(), 0)
  318. if index > 0:
  319. terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
  320. self.afficheEcranEditionTerrains(terrain)
  321. def terrainNouveau(self):
  322. """ouvre la fenetre 'terrains' en mode edition"""
  323. self.afficheEcranEditionTerrains()
  324. ###############
  325. ##### affichage de la liste des creatures enregistrees, et fonctions d'acces aux donnees""""
  326. def afficheEcranEditionCombattants(self, creature = None):
  327. """affiche l'ecran d'edition/creation de creatures"""
  328. self.editionCreature = EcranEditionCombattant(creature, 0, self.formeCases)
  329. self.editionCreature.setAttribute(Qt.WA_DeleteOnClose)
  330. r = self.editionCreature.exec_()
  331. if r == 1:
  332. combattant = self.editionCreature.combattant
  333. enregistrer(combattant.id, combattant, "lib\\biblio\\combattant")
  334. self.majListeCreatures()
  335. self.editionCreature = None
  336. def majListeCreatures(self):
  337. """mise a jour de la liste des creatures depuis la sauvegarde"""
  338. self.fenetre.ui.cp_listeCreatures.maj()
  339. self.activerMode(Modes.StandardCp)
  340. def creatureEdit(self):
  341. """ouvre la fenetre 'creatures' en mode edition"""
  342. index = self.fenetre.ui.cp_listeCreatures.item(self.fenetre.ui.cp_listeCreatures.currentRow(), 0)
  343. if index > 0:
  344. creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
  345. self.afficheEcranEditionCombattants(creature)
  346. def creatureNouveau(self):
  347. """ouvre la fenetre 'creatures' en mode edition"""
  348. self.afficheEcranEditionCombattants()
  349. ###############
  350. ##### affichage de la liste des decors enregistrees, et fonctions d'acces aux donnees""""
  351. def afficheEcranEditionDecors(self, decor = None):
  352. """affiche l'ecran d'edition/creation de decors"""
  353. self.editionDecor = EcranEditionDecor(decor, 0, self.formeCases)
  354. self.editionDecor.setAttribute(Qt.WA_DeleteOnClose)
  355. r = self.editionDecor.exec_()
  356. if r == 1:
  357. decor = self.editionDecor.decor
  358. enregistrer(decor.id, decor, "lib\\biblio\\decor")
  359. self.majListeDecors()
  360. def majListeDecors(self):
  361. """mise a jour de la liste des decors depuis la sauvegarde"""
  362. self.fenetre.ui.cp_listeDecors.maj()
  363. self.activerMode(Modes.StandardCp)
  364. def decorEdit(self):
  365. """ouvre la fenetre 'decors' en mode edition"""
  366. self.afficheEcranEditionDecors(self.fenetre.ui.cp_listeDecors.actuel())
  367. def decorNouveau(self):
  368. """ouvre la fenetre 'decors' en mode edition"""
  369. self.afficheEcranEditionDecors()
  370. ###############
  371. ############### maj des infos du panneau Pi a la selection/deselection d'un pion
  372. #voir a balancer tout ca dans une classe a part
  373. def majPanneauPi(self):
  374. if self.pionSelectionne():
  375. ### maj la selection dans la liste d'ordre de jeu
  376. for i in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
  377. if str(self.fenetre.ui.inf_listeOrdreJeu.item(i, 0).text().toUtf8()) == str(self.pionSelectionne().numero):
  378. self.fenetre.ui.inf_listeOrdreJeu.setCurrentCell(i,0)
  379. ### maj des infos dans le panneau pi
  380. self.fenetre.ui.pi_nom.majTexte(self.pionSelectionne().txtId())
  381. self.fenetre.ui.pi_img.chargerImage("img\\"+self.pionSelectionne().img.nomFichier)
  382. ### maj de la liste des attributs
  383. self.fenetre.ui.pi_listeAttributs.setColumnWidth(0, 50)
  384. self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  385. #on vide la liste
  386. while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
  387. self.fenetre.ui.pi_listeAttributs.removeRow(0)
  388. #creation des lignes de base
  389. lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans listeAttributCelluleModifiee
  390. for i in range(0, 10): #10 premieres colonnes reservees pour les infos de base
  391. self.fenetre.ui.pi_listeAttributs.insertRow(i)
  392. item = QTableWidgetItem()
  393. if i < len(lignesBase):
  394. item.setText(QString.fromUtf8(lignesBase[i]))
  395. item.setFlags(Qt.NoItemFlags)
  396. self.fenetre.ui.pi_listeAttributs.setItem(i, 0, item)
  397. self.fenetre.ui.pi_listeAttributs.setRowHidden(i, (i >= len(lignesBase)))
  398. #maj des donnees de base
  399. self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom))))
  400. self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat))))
  401. self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().z))))
  402. #attributs issus des regles utilisees
  403. ordre = regles.ordreAttributs()
  404. for elt in ordre:
  405. ligne = 10 + ordre.index(elt)
  406. self.fenetre.ui.pi_listeAttributs.insertRow(ligne)
  407. item = QTableWidgetItem(QString.fromUtf8(elt))
  408. item.setFlags(Qt.NoItemFlags)
  409. self.fenetre.ui.pi_listeAttributs.setItem(ligne, 0, item)
  410. self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[elt]))))
  411. self.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  412. ###affiche les notes du combattant
  413. self.fenetre.ui.pi_notes.majTexte(self.pionSelectionne().notes)
  414. ###maj la liste des attaques du pion
  415. #on vide la liste
  416. while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
  417. self.fenetre.ui.pi_listeAttaques.removeRow(0)
  418. i = 0
  419. for attaque in self.pionSelectionne().attaques:
  420. self.fenetre.ui.pi_listeAttaques.insertRow(i)
  421. self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
  422. icone = None
  423. if attaque.typ == "cac":
  424. icone = QIcon(":/interface/16/ressource/epee_16.png")
  425. if attaque.typ == "dist":
  426. icone = QIcon(":/interface/16/ressource/arc_16.png")
  427. if attaque.typ == "zone":
  428. icone = QIcon(":/interface/16/ressource/baguette_16.png")
  429. if icone != None:
  430. self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
  431. self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))
  432. else:
  433. #maj des infos dans le panneau pi
  434. self.fenetre.ui.pi_img.clear()
  435. self.fenetre.ui.pi_nom.majTexte("Pas de pion\nselectionné")
  436. #vide la liste des attributs
  437. self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  438. while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
  439. self.fenetre.ui.pi_listeAttributs.removeRow(0)
  440. #vide la liste des attaques du pion
  441. while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
  442. self.fenetre.ui.pi_listeAttaques.removeRow(0)
  443. self.majInfosAttaqueEC()
  444. ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres #######
  445. def plateauModeCreation(self):
  446. self.fenetre.majVisibilitePanneauxPlateau("creation")
  447. self.activerMode(Modes.StandardCp)
  448. def plateauModeCombat(self):
  449. self.fenetre.majVisibilitePanneauxPlateau("combat")
  450. self.activerMode(Modes.StandardPi)
  451. def activerMode(self, mode, param = None):
  452. """desactive le mode actif et active le nouveau a la place"""
  453. self.modeActif.desactiver()
  454. self.modeActif = mode(self)
  455. self.modeActif.activer(param)
  456. ## def majModeAffichage(self, index):
  457. ## """met a jour le mode d'affichage"""
  458. ## nouveauMode = ""
  459. ## if index == 0:
  460. ## #passe a l'affichage standard
  461. ## pass
  462. ## elif index == 1:
  463. ## #passe en mode affichage de l'altitude
  464. ## nouveauMode = "altitude"
  465. ## elif index == 2:
  466. ## #affichage des terrains slt
  467. ## nouveauMode = "terrain"
  468. ## elif index == 3:
  469. ## #affichage tactique
  470. ## nouveauMode = "tactique"
  471. ##
  472. ## for coord in self.cases:
  473. ## self.cases[coord].majAffichageSpecial(nouveauMode)
  474. def modePeintureCase(self):
  475. """enclenche le mode peinture de case a partir de la couleur selectionnee"""
  476. couleur = self.chercherCouleur()
  477. if couleur.isValid():
  478. terrain = Terrain()
  479. terrain.couleur = couleur
  480. self.activerMode(Modes.MajCases, terrain)
  481. else:
  482. self.activerMode(Modes.StandardCp)
  483. def modePeintureCase_perso(self):
  484. origine = self.sender().objectName()
  485. index = int(origine.replace("cp_couleur",""))-1
  486. couleur = QColor()
  487. r, g, b = m_couleursRapides[index]
  488. couleur.setRgb(r, g, b)
  489. if couleur.isValid():
  490. terrain = Terrain()
  491. terrain.couleur = couleur
  492. self.activerMode(Modes.MajCases, terrain)
  493. else:
  494. self.activerMode(Modes.StandardCp)
  495. def modeCopieTerrain(self):
  496. """enclenche le mode copie de case"""
  497. self.activerMode(Modes.Pipette)
  498. def modeCaseEffet(self, index):
  499. """enclenche le mode de mise a jour de l'effet actif des cases"""
  500. effets = ["brule", "eau", "glace", "poison", "aucun"]
  501. self.activerMode(Modes.MajCasesEffet, effets[index])
  502. def modeCreationPion(self):
  503. """enclenche le mode de creation de pions simples"""
  504. self.majMode("pionCreation")
  505. def majModePionSupprimer(self):
  506. """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)"""
  507. self.activerMode(Modes.SuppressionPion)
  508. def modeCreationDecor(self, ligne, col):
  509. """enclenche le mode de creation de decors depuis la liste des decors"""
  510. index = self.fenetre.ui.cp_listeDecors.item(ligne, 0)
  511. decor = charger("lib\\biblio\\decor", str(index.text().toUtf8()))
  512. self.activerMode(Modes.CreationPion, decor)
  513. def modeCreationCombattant(self, ligne, col):
  514. """enclenche le mode de creation de pions depuis la liste des creatures"""
  515. index = self.fenetre.ui.cp_listeCreatures.item(ligne, 0)
  516. creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
  517. self.activerMode(Modes.CreationPion, creature)
  518. def modeMajTerrainCase(self, ligne, col):
  519. """enclenche le mode permettant la mise a jour du terrain des cases"""
  520. index = self.fenetre.ui.cp_listeTerrains.item(ligne, 0)
  521. terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
  522. if terrain:
  523. self.activerMode(Modes.MajCases, terrain)
  524. else:
  525. print "terrain invalide"
  526. def majEpaisseurPinceau(self, epaisseur):
  527. """met a jour l'epaisseur du pinceau (en cases)"""
  528. self.fenetre.ui.cp_valeurEpaisseurPinceau.majTexte(str(epaisseur))
  529. self.pinceau.majEpaisseur(int(epaisseur))
  530. def modeMajAltitudeCase(self):
  531. self.majMode("caseMajAltitude")
  532. def majModeForme(self):
  533. """met a jour la forme utilisee pour la peinture"""
  534. formes = {"cp_formeSimple": "simple", \
  535. "cp_formeLigne": "ligne", \
  536. "cp_formeLigneOrientee": "frontiere", \
  537. "cp_formeEllipseVide": "ellipseV", \
  538. "cp_formeEllipsePlein": "ellipseP", \
  539. "cp_formeRectVide": "rectV", \
  540. "cp_formeRectPlein": "rectP"}
  541. self.pinceau.majForme(formes[str(self.sender().objectName())])
  542. def majModeCombatDeplacement(self):
  543. """active le mode de combat 'deplacement' (mode standard)"""
  544. self.modeActif.nouvelleAction(Actions.Deplacement)
  545. def majModeCombatAttaqueCaC(self):
  546. """active le mode de combat 'corps-a-corps'"""
  547. self.modeActif.nouvelleAction(Actions.Cac)
  548. def majModeCombatAttaqueDist(self):
  549. """active le mode de combat 'attaque a distance'"""
  550. self.modeActif.nouvelleAction(Actions.Distance)
  551. def majModeCombatZone(self):
  552. if self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 0:
  553. action = Actions.Ligne
  554. elif self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 1:
  555. action = Actions.Disque
  556. elif self.fenetre.ui.pi_formeAttaqueZone.currentIndex() == 2:
  557. action = Actions.Cone
  558. if action:
  559. self.modeActif.nouvelleAction(action)
  560. def majModeDefinirEntree(self):
  561. entree = EntreeSortie(self, "E")
  562. self.activerMode(Modes.EntreesSorties, entree)
  563. def majModeDefinirSortie(self):
  564. sortie = EntreeSortie(self, "S")
  565. self.activerMode(Modes.EntreesSorties, sortie)
  566. def majModeZonePlacement(self):
  567. self.activerMode(Modes.ZonePlacement)
  568. ###############
  569. ########## Gestion du combat ##############
  570. def majAffichageTour(self):
  571. """met a jour l'affichage du tour en cours"""
  572. self.fenetre.ui.cbt_tour.majTexte("Tour: {}".format(self.tour))
  573. def initListeOrdreJeu(self):
  574. """cree les colonnes et met en forme la table ordre jeu"""
  575. self.fenetre.ui.inf_listeOrdreJeu.setColumnWidth(2, 30)
  576. self.fenetre.ui.inf_listeOrdreJeu.hideColumn(0)
  577. self.fenetre.ui.inf_listeOrdreJeu.hideColumn(2)
  578. self.fenetre.ui.inf_listeOrdreJeu.setIconSize(QSize(30,20))
  579. def majListeOrdreJeu(self):
  580. """met a jour la liste des pions infoOrdreJeu"""
  581. while self.fenetre.ui.inf_listeOrdreJeu.rowCount() > 0:
  582. self.fenetre.ui.inf_listeOrdreJeu.removeRow(0)
  583. index = 0
  584. for num in self.ordreJeu:
  585. self.fenetre.ui.inf_listeOrdreJeu.insertRow(int(index))
  586. self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 0, QTableWidgetItem(QString.fromUtf8(str(num))))
  587. icon = QIcon("img\\"+self.combattants[num].logo)
  588. item = QTableWidgetItem(icon,QString.fromUtf8(self.combattants[num].txtId()))
  589. self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 1, item)
  590. self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 2, QTableWidgetItem(QString.fromUtf8(str(self.ordreJeu[num]))))
  591. index += 1
  592. self.fenetre.ui.inf_listeOrdreJeu.sizeHintForColumn(1)
  593. ## trierTable(self.fenetre.ui.infoOrdreJeu, 2, 0)
  594. def clicListOrdreJeu(self, ligne, col):
  595. """on a clique dans la liste d'ordre de jeu, le pion correspondant est selectionne et centre sur la carte"""
  596. numCombattant = int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8())
  597. self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
  598. self.modeActif.clic_combattant(numCombattant)
  599. def pionSuivant(self):
  600. """selection du pion suivant dans la liste d'ordre de jeu"""
  601. if self.numPionEnCours in self.combattants:
  602. suivant = self.ordreJeu[self.numPionEnCours] + 1
  603. else:
  604. suivant = 1
  605. if suivant > len(self.ordreJeu):
  606. self.tour += 1
  607. self.majAffichageTour()
  608. suivant = 1
  609. for num in self.ordreJeu:
  610. if self.ordreJeu[num] == suivant:
  611. numCombattant = num
  612. break
  613. for ligne in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
  614. item = self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0)
  615. item.setSelected(int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8()) == numCombattant)
  616. if int(item.text().toUtf8()) == numCombattant:
  617. self.fenetre.ui.inf_listeOrdreJeu.scrollToItem(item)
  618. self.vue().centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
  619. self.pionSaisir(numCombattant)
  620. def afficheEcranGestionCombat(self):
  621. """affiche l'ecran de gestion du combat"""
  622. self.gestionCombat = EcranGestionCombat(self)
  623. self.gestionCombat.show()
  624. self.connect(self.fenetre, SIGNAL("majListesPions"), self.majListesPions)
  625. self.connect(self.gestionCombat, SIGNAL("majListesPions"), self.majListesPions)
  626. QApplication.processEvents()
  627. ## r = self.gestionCombat.exec_()
  628. def majOrdreJeu(self):
  629. """met a jour l'ordre de jeu des pions en fonction de l'attribut prevu par les regles s'il existe,
  630. ou en fonction de l'ordre de jeu parametre sinon"""
  631. attribut = regles.attributOrdreJeu()
  632. if attribut != None:
  633. dico = {}
  634. for numCombattant in self.combattants:
  635. dico[numCombattant] = int(self.combattants[numCombattant].listeAttributs[attribut])
  636. ordre = sorted(dico, key = dico.get, reverse=(regles.sensTriOrdreJeu() == 1))
  637. self.ordreJeu = {}
  638. for numCombattant in self.combattants:
  639. self.ordreJeu[numCombattant] = ordre.index(numCombattant) + 1
  640. self.majListeOrdreJeu()
  641. def pionDeplacerDansOrdreJeu(self, numCombattant, nouvellePosition):
  642. """deplace un pion dans le dictionnaire gerant l'ordre de jeu de maniere a assurer sa coherence
  643. nouvellePosition = 0 supprime le pion de la liste"""
  644. if numCombattant in self.ordreJeu:
  645. if nouvellePosition == 0:
  646. del self.ordreJeu[numCombattant]
  647. if len(self.ordreJeu) > 0:
  648. i = 0
  649. tmp = sorted(self.ordreJeu, key=self.ordreJeu.get)
  650. if numCombattant in tmp:
  651. tmp.remove(numCombattant)
  652. for num in tmp:
  653. i += 1
  654. if i == nouvellePosition:
  655. self.ordreJeu[numCombattant] = i
  656. i += 1
  657. self.ordreJeu[num] = i
  658. if i < nouvellePosition:
  659. self.ordreJeu[numCombattant] = i + 1
  660. elif nouvellePosition > 0:
  661. self.ordreJeu[numCombattant] = 1
  662. self.majOrdreJeu()
  663. ## def majListeAttributs(self):
  664. ## """met a jour la liste des attributs dans le panneau de combat"""
  665. ## self.fenetre.ui.pi_listeAttributs.setColumnWidth(0, 50)
  666. ## self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  667. ##
  668. ## #on vide la liste
  669. ## while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
  670. ## self.fenetre.ui.pi_listeAttributs.removeRow(0)
  671. ## self.fenetre.ui.pi_listeAttributs.setVisible((self.pionSelectionne() != None))
  672. ## if self.pionSelectionne() != None:
  673. ## #creation des lignes de base
  674. ## lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans listeAttributCelluleModifiee
  675. ## for i in range(0, 10): #10 premieres colonnes reservees pour les infos de base
  676. ## self.fenetre.ui.pi_listeAttributs.insertRow(i)
  677. ## item = QTableWidgetItem()
  678. ## if i < len(lignesBase):
  679. ## item.setText(QString.fromUtf8(lignesBase[i]))
  680. ## item.setFlags(Qt.NoItemFlags)
  681. ## self.fenetre.ui.pi_listeAttributs.setItem(i, 0, item)
  682. ## self.fenetre.ui.pi_listeAttributs.setRowHidden(i, (i >= len(lignesBase)))
  683. ##
  684. ## #maj des donnees de base
  685. ## self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom))))
  686. ## self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat))))
  687. ## self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().z))))
  688. ##
  689. ## #attributs issus des regles utilisees
  690. ## ordre = regles.ordreAttributs()
  691. ## for elt in ordre:
  692. ## ligne = 10 + ordre.index(elt)
  693. ## self.fenetre.ui.pi_listeAttributs.insertRow(ligne)
  694. ## item = QTableWidgetItem(QString.fromUtf8(elt))
  695. ## item.setFlags(Qt.NoItemFlags)
  696. ## self.fenetre.ui.pi_listeAttributs.setItem(ligne, 0, item)
  697. ## self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[elt]))))
  698. ##
  699. ## self.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  700. ##
  701. def listeAttributCelluleModifiee(self, ligne, colonne):
  702. """une cellule de la liste des attributs a ete modifiee"""
  703. if colonne != 1:
  704. print("valeur non modifiable")
  705. else:
  706. #on verifie la validite de la donnee entree
  707. lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans majListeAttribut
  708. if ligne < len(lignesBase):
  709. pass
  710. elif ligne >= 10:
  711. attribut = regles.ordreAttributs()[(ligne - 10)]
  712. nouvelleVal = str(self.fenetre.ui.pi_listeAttributs.item(ligne, 1).text().toUtf8())
  713. valVerifiee = regles.listeControle()[attribut].controler(nouvelleVal)
  714. if valVerifiee != None:
  715. self.pionSelectionne().listeAttributs[attribut] = valVerifiee
  716. if attribut == regles.attributOrdreJeu():
  717. print("maj ordre (a implementer)")
  718. else:
  719. self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[attribut]))))
  720. def initListeAttaques(self):
  721. """met en forme et connecte la liste des attaques du pion"""
  722. self.fenetre.ui.pi_listeAttaques.setColumnWidth(0, 0)
  723. self.fenetre.ui.pi_listeAttaques.setColumnWidth(1, (0.3*self.fenetre.ui.pi_listeAttaques.width()))
  724. self.fenetre.ui.pi_listeAttaques.setColumnWidth(2, (0.7*self.fenetre.ui.pi_listeAttaques.width()))
  725. self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("itemSelectionChanged()"), self.majInfosAttaqueEC)
  726. self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("cellClicked(int, int)"), self.listeAttaquesCelluleCliquee)
  727. self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
  728. self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(0, (0.49*self.fenetre.ui.pi_listeAttributsAttaqueEC.width()))
  729. self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(1, (0.5*self.fenetre.ui.pi_listeAttributsAttaqueEC.width()))
  730. def majListeAttaques(self):
  731. """met a jour la liste des attaques du pion dans le panneau de combat"""
  732. #on vide la liste
  733. while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
  734. self.fenetre.ui.pi_listeAttaques.removeRow(0)
  735. self.fenetre.ui.pi_listeAttaques.setVisible((self.pionSelectionne() != None))
  736. ## self.fenetre.ui.editerAttaques.setVisible((self.pionSelectionne() != None))
  737. self.fenetre.ui.pi_panneauAttaqueEC.setVisible((self.pionSelectionne() != None))
  738. i = 0
  739. if self.pionSelectionne() != None:
  740. for attaque in self.pionSelectionne().attaques:
  741. self.fenetre.ui.pi_listeAttaques.insertRow(i)
  742. self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
  743. icone = None
  744. if attaque.typ == "cac":
  745. icone = QIcon(":/interface/16/ressource/epee_16.png")
  746. if attaque.typ == "dist":
  747. icone = QIcon(":/interface/16/ressource/arc_16.png")
  748. if attaque.typ == "zone":
  749. icone = QIcon(":/interface/16/ressource/baguette_16.png")
  750. if icone != None:
  751. self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
  752. self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))
  753. self.majInfosAttaqueEC()
  754. def listeAttaquesCelluleCliquee(self, ligne, colonne):
  755. """on a clique sur une cellule de la liste des attaques"""
  756. numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
  757. if numAttaque >= 0:
  758. self.utiliserAttaque(numAttaque)
  759. def utiliserAttaque(self, numAttaque):
  760. """le pion selectionne utilise son attaque n"""
  761. if self.pionSelectionne() != None:
  762. if numAttaque < len(self.pionSelectionne().attaques):
  763. attaque = self.pionSelectionne().attaques[numAttaque]
  764. if attaque.typ == "cac":
  765. self.majModeCombat("combatAttaqueCaC")
  766. if attaque.typ == "dist":
  767. self.majModeCombat("combatAttaqueDist")
  768. if attaque.typ == "zone":
  769. self.modeParam["typeAttaqueZone"] = attaque.formeZone
  770. self.fenetre.ui.pi_rayonAttaqueZone.setValue(attaque.rayon)
  771. self.majModeCombat("combatAttaqueZone")
  772. def majInfosAttaqueEC(self):
  773. """met a jour les infos de l'attaque en cours (selectionnee)"""
  774. selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
  775. self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
  776. if self.pionSelectionne() != None and len(selection) > 0:
  777. ligne = selection[0].row()
  778. numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
  779. self.disconnect(self.fenetre.ui.pi_panneauAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
  780. #on vide la liste
  781. while self.fenetre.ui.pi_listeAttributsAttaqueEC.rowCount() > 0:
  782. self.fenetre.ui.pi_listeAttributsAttaqueEC.removeRow(0)
  783. self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(0)
  784. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 0, QTableWidgetItem(QString.fromUtf8("numAtt")))
  785. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 1, QTableWidgetItem(QString.fromUtf8(str(numAttaque))))
  786. self.fenetre.ui.pi_listeAttributsAttaqueEC.setRowHidden(0, True)
  787. #attributs issus des regles utilisees
  788. ordre = regles.ordreAttributsAttaques()
  789. for elt in ordre:
  790. ligne = 1 + ordre.index(elt)
  791. self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(ligne)
  792. item = QTableWidgetItem(QString.fromUtf8(elt))
  793. item.setFlags(Qt.NoItemFlags)
  794. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 0, item)
  795. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques[numAttaque].attributs[elt]))))
  796. self.connect(self.fenetre.ui.pi_listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
  797. #maj des notes
  798. self.disconnect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
  799. self.fenetre.ui.pi_notesAttaqueEC.majTexte(self.pionSelectionne().attaques[numAttaque].notes)
  800. self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
  801. def attaqueECCelluleModifiee(self, ligne, colonne):
  802. """une cellule de la liste d'attributs de l'attaque en cours a ete modifiee"""
  803. pass
  804. def majNotesAttaqueEC(self):
  805. """met a jour les notes de l'attaque en cours (selectionnee)"""
  806. selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
  807. self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
  808. if self.pionSelectionne() != None and len(selection) > 0:
  809. ligne = selection[0].row()
  810. numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
  811. self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_notesAttaqueEC.toPlainText().toUtf8())
  812. def afficheEcranEditionAttaques(self):
  813. """affiche l'ecran d'edition/creation d'attaques"""
  814. if self.pionSelectionne() != None:
  815. self.editionAttaques = QDialog()
  816. frame = EcranEditionAttaques(self.pionSelectionne())
  817. frame.setParent(self.editionAttaques)
  818. self.editionAttaques.setAttribute(Qt.WA_DeleteOnClose)
  819. r = self.editionAttaques.exec_()
  820. del self.editionAttaques
  821. self.majListeAttaques()
  822. def majNotesCombattant(self):
  823. """les notes du pion ont ete mises a jour"""
  824. if self.pionSelectionne() != None:
  825. self.pionSelectionne().notes = str(self.fenetre.ui.pi_notes.toPlainText().toUtf8())
  826. else:
  827. pass
  828. ###############
  829. ### panneau d'info
  830. def majInfosCombattant(self, combattant=None):
  831. self.fenetre.ui.inf_boitePion.maj(combattant)
  832. def majInfosDecor(self, decor=None):
  833. self.fenetre.ui.inf_boiteDecor.maj(decor)
  834. def majInfosCase(self, case=None):
  835. self.fenetre.ui.inf_boiteCase.maj(case)
  836. ############### fonctions de calcul ################
  837. def coordonneesValides(self, coord):
  838. """les coordonnees entrees en parametre sont elles celles d'une case du plateau"""
  839. return (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.nbCasesX and coord[1] < self.nbCasesY)
  840. def lstCoordAdjacentes(self, x, y):
  841. """renvoie la liste des coordonnees adjacentes, !!!! sans condition d'existence sur le plateau !!!!
  842. attention: l'ordre est important"""
  843. if self.formeCases == "H":
  844. if 1 == (x % 2):
  845. voisins = [(x, y-1), (x+1, y), (x+1, y+1), (x, y+1), (x-1, y+1), (x-1, y)]
  846. else:
  847. voisins = [(x, y-1), (x+1, y-1), (x+1, y), (x, y+1), (x-1, y), (x-1, y-1)]
  848. else:
  849. 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)]
  850. return voisins
  851. def zone(self, origine, distance, z=0, conditionFranchissable = False, conditionVisible = False):
  852. """renvoie un dictionnaire representant la liste des coordonnees des cases comprises dans la zone
  853. la zone en question est la liste des cases situees a une distance d des coordonnees d'origine
  854. z = 0 -> hauteur z de l'origine par rapport a l'altitude de la case
  855. conditionFranchissable = Vrai -> les cases infranchissables ne sont pas prises en compte
  856. conditionVisible = Vrai -> les cases bloquant la visibilite ne sont pas prises en compte
  857. [cf methode A* (A-star)]"""
  858. aVerifier = []
  859. aVerifier2 = []
  860. resultat = {}
  861. k = 0
  862. #on part de la premiere case, puis on itere a partir de chaque nouveau depart
  863. if origine in self.cases:
  864. aVerifier.append(origine)
  865. while k <= distance:
  866. for depart in aVerifier:
  867. for coord in self.cases[depart].voisins:
  868. if not coord in aVerifier and not coord in aVerifier2 and not coord in resultat:
  869. if conditionFranchissable and not conditionVisible:
  870. if self.cases[coord].estFranchissable(z):
  871. aVerifier2.append(coord)
  872. elif not conditionFranchissable and conditionVisible:
  873. if self.cases[coord].terrain.visibilite:
  874. aVerifier2.append(coord)
  875. elif conditionFranchissable and conditionVisible:
  876. if self.cases[coord].estFranchissable(z) and self.cases[coord].terrain.visibilite:
  877. aVerifier2.append(coord)
  878. else:
  879. aVerifier2.append(coord)
  880. for elt in aVerifier:
  881. resultat[elt] = k
  882. aVerifier = aVerifier2
  883. aVerifier2 = []
  884. k += 1
  885. return resultat
  886. def polygoneAgglo(self, listeCases):
  887. """renvoie un polygone contruit par agglomeration des polygones des cases de la liste
  888. les cases doivent etre adjacentes (cases hexagonales ou carrees)"""
  889. pointsPolygone = []
  890. segments = []
  891. case = Case(self)
  892. #on verifie que toutes les cases sont adjacentes les unes aux autres
  893. valide = True
  894. if len(listeCases) > 1:
  895. for coord in listeCases:
  896. if not len(set(listeCases).intersection(self.lstCoordAdjacentes(coord[0], coord[1]))) > 0: valide = False
  897. if not len(listeCases) > 0:
  898. valide = False
  899. if valide:
  900. #on parcourt les faces des polygones des cases, et on ne garde que ceux qui n'ont pas de case 'en face'
  901. for coord in listeCases:
  902. polygone = case.polygone(coord[0], coord[1])
  903. voisins = self.lstCoordAdjacentes(coord[0], coord[1])
  904. for i in range(0, len(voisins)):
  905. if not voisins[i] in listeCases:
  906. j = i+1
  907. if j > len(voisins) - 1:
  908. j = 0
  909. segments.append(QLineF(polygone[i], polygone[j]))
  910. #on 'accroche' les segments les uns aux autres, dans l'ordre
  911. segments2 = [segments[0]]
  912. for segment2 in segments2:
  913. for segment in segments:
  914. if not QLineF(segment.p1(), segment.p2()) in segments2 and not QLineF(segment.p2(), segment.p1()) in segments2:
  915. if sqrt((segment.p1().x()-segment2.p2().x())**2+(segment.p1().y()-segment2.p2().y())**2) < 1:
  916. segments2.append(QLineF(segment.p1(), segment.p2()))
  917. elif sqrt((segment.p2().x()-segment2.p2().x())**2+(segment.p2().y()-segment2.p2().y())**2) < 1:
  918. segments2.append(QLineF(segment.p2(), segment.p1()))
  919. pointsPolygone = []
  920. premierPoint = segments2[0].p1()
  921. pointsPolygone.append(premierPoint)
  922. for segment in segments2:
  923. pointSuivant = segment.p2()
  924. if pointSuivant != premierPoint:
  925. pointsPolygone.append(pointSuivant)
  926. #creation du polygone
  927. polygone = QPolygonF()
  928. for point in pointsPolygone:
  929. polygone.append(point)
  930. else:
  931. polygone = None
  932. return polygone
  933. def coordCentreListeCases(self, listeCases):
  934. """renvoie les coordonnees centrales d'une liste de cases"""
  935. retour = None
  936. if len(listeCases) > 0:
  937. listeTriee = sorted(listeCases)
  938. posMilieu = int(len(listeCases)/2)
  939. retour = listeTriee[posMilieu]
  940. return retour
  941. def coordonneesAuPoint(self, point):
  942. """renvoie les coordonnees de la case situee au QPointF entre en parametre"""
  943. coord = None
  944. if point != None:
  945. lstObjets = self.vue().scene().items(point)
  946. for objet in lstObjets:
  947. if objet:
  948. if objet.__class__.__name__ == "Case":
  949. coord = (objet.x, objet.y)
  950. break
  951. return coord
  952. def casesSousForme(self, forme, plein = True, epaisseur = 0):
  953. """renvoie la liste des cases en collision avec un QGraphicsItem en parametre
  954. plein = False: pas le contenu de la forme
  955. epaisseur = renvoie aussi les cases voisines jusqu'a la distance demandee"""
  956. tmp = []
  957. listeCases = []
  958. point1 = None
  959. point2 = None
  960. #point 1 et 2
  961. if forme.__class__.__name__ == "QGraphicsLineItem":
  962. point1 = forme.line().p1()
  963. point2 = forme.line().p2()
  964. elif forme.__class__.__name__ == "QGraphicsRectItem" or forme.__class__.__name__ == "QGraphicsEllipseItem":
  965. point1 = forme.rect().topLeft()
  966. point2 = forme.rect().bottomRight()
  967. else:
  968. point1 = forme.boundingRect().topLeft()
  969. point2 = forme.boundingRect().bottomRight()
  970. #preselection des cases (meilleures perf)
  971. if point1 != None and point2 != None and point1 != point2:
  972. preSelection = self.preSelectionCollision(point1, point2)
  973. else:
  974. preSelection = []
  975. for coord in self.cases:
  976. preSelection.append(coord)
  977. #on liste les cases en collision avec la forme
  978. for coord in preSelection:
  979. if self.cases[coord].collidesWithItem(forme, Qt.IntersectsItemShape):
  980. if plein:
  981. tmp.append(coord)
  982. else:
  983. contenu = True
  984. for i in range(0,len(self.cases[coord].polygon())):
  985. if not forme.contains(self.cases[coord].polygon().at(i)):
  986. contenu = False
  987. break
  988. if contenu == False:
  989. tmp.append(coord)
  990. #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
  991. if not plein and epaisseur > 0:
  992. for coord in tmp:
  993. zone = self.zone(coord, epaisseur)
  994. for coord2 in zone:
  995. if not coord2 in listeCases:
  996. listeCases.append(coord2)
  997. else:
  998. listeCases = tmp
  999. #si la liste est vide, on ajoute l'origine de la forme
  1000. if len(listeCases) == 0:
  1001. listeCases = [self.coordonneesAuPoint(point1)]
  1002. return listeCases
  1003. def preSelectionCollision(self, point1, point2):
  1004. """renvoie une liste des cases qui peuvent etre concernees par une collision avec
  1005. un graphicsItem (pour des raisons de performance)"""
  1006. preSelection = []
  1007. coord1 = self.coordonneesAuPoint(point1)
  1008. coord2 = self.coordonneesAuPoint(point2)
  1009. if coord1 != None and coord2 != None:
  1010. minX = min(coord1[0], coord2[0]) - 1
  1011. maxX = max(coord1[0], coord2[0]) + 1
  1012. minY = min(coord1[1], coord2[1]) - 1
  1013. maxY = max(coord1[1], coord2[1]) + 1
  1014. for coord in self.cases:
  1015. if coord[0] >= minX and coord[0] <= maxX and coord[1] >= minY and coord[1] <= maxY :
  1016. preSelection.append(coord)
  1017. else:
  1018. preSelection = self.cases
  1019. return preSelection
  1020. def estCibleAttaqueDistValide(self, coordOrigine, coordCible, zPion = 0):
  1021. """la case cible est elle valide pour une attaque a distance depuis la position et hauteur
  1022. du pion selectionne? on compare pour ce faire les altitudes des cases sur la ligne de mire"""
  1023. casesLigneMire = []
  1024. #on preselectionne les cases concernees
  1025. preSelection = self.preSelectionCollision(self.cases[coordOrigine].centreGraphique, self.cases[coordCible].centreGraphique)
  1026. if coordOrigine in preSelection:
  1027. preSelection.remove(coordOrigine)
  1028. if coordCible in preSelection:
  1029. preSelection.remove(coordCible)
  1030. for coord in preSelection:
  1031. ligne = QLineF(self.cases[coordOrigine].centreGraphique, self.cases[coordCible].centreGraphique)
  1032. ligneGraphique = QGraphicsLineItem(ligne)
  1033. ligneGraphique.prepareGeometryChange()
  1034. self.addItem(ligneGraphique)
  1035. if self.cases[coord].collidesWithItem(ligneGraphique, Qt.IntersectsItemShape):
  1036. casesLigneMire.append(coord)
  1037. self.removeItem(ligneGraphique)
  1038. del ligneGraphique
  1039. #on trie les cases par distance au point d'origine (de la plus proche a la plus eloignee)
  1040. casesLigneMireDistance = {} #distance: coord
  1041. for coord in casesLigneMire:
  1042. distance = sqrt((coordOrigine[0] - coord[0])**2 + (coordOrigine[1] - coord[1])**2)
  1043. casesLigneMireDistance[coord] = distance
  1044. #on compare enfin les altitudes de chaque case en fonction de la distance
  1045. zOrigine = self.cases[coordOrigine].altitude + self.pionSelectionne().z + self.pionSelectionne().hauteur
  1046. zCible = self.cases[coordCible].altitude + zPion
  1047. distanceTot = sqrt((coordCible[0] - coordOrigine[0])**2 + (coordCible[1] - coordOrigine[1])**2)
  1048. valide = True
  1049. for coord in casesLigneMireDistance:
  1050. if self.cases[coord].terrain.visibilite == False:
  1051. valide = False
  1052. break
  1053. else:
  1054. if zOrigine >= zCible:
  1055. z = (zOrigine - zCible) * (casesLigneMireDistance[coord] / distanceTot)
  1056. else:
  1057. z = (zCible - zOrigine) * ((distanceTot - casesLigneMireDistance[coord]) / distanceTot)
  1058. if self.cases[coord].estOccupee(int(z)):
  1059. if self.modeParam["pionCibleAttaqueDist"] != None:
  1060. if self.cases[coord].estOccupeePar(int(z)) != self.modeParam["pionCibleAttaqueDist"]:
  1061. valide = False
  1062. else:
  1063. valide = False
  1064. break
  1065. return valide
  1066. def pionSurCase(self, coord):
  1067. """renvoie le pion present sur la case, none sinon"""
  1068. retour = None
  1069. for num in self.combattants:
  1070. if self.combattants[num].position == coord:
  1071. retour = num
  1072. return retour
  1073. def pionsSurListeCase(self, listeCases):
  1074. """renvoie la liste des num des pions presents sur la liste de cases"""
  1075. retour = []
  1076. for coord in listeCases:
  1077. pion = self.cases[coord].pionOccupant()
  1078. if pion != None and not pion.numero in retour:
  1079. retour.append(pion.numero)
  1080. return retour
  1081. def majZonePlacement(self, listeCases):
  1082. """met a jour la forme et l'affichage de la zone de placement initale des joueurs"""
  1083. if len(listeCases) > 0:
  1084. if self.polygoneZonePlacement == None:
  1085. self.polygoneZonePlacement = QGraphicsPolygonItem(scene=self)
  1086. self.polygoneZonePlacement.setZValue(0)
  1087. qCouleurFond = QColor("white")
  1088. qCouleurFond.setAlpha(50)
  1089. self.polygoneZonePlacement.setBrush(qCouleurFond)
  1090. pinceau = QPen(QColor("orange"))
  1091. pinceau.setWidth(20)
  1092. self.polygoneZonePlacement.setPen(pinceau)
  1093. self.polygoneZonePlacement.setAcceptedMouseButtons(Qt.NoButton)
  1094. self.polygoneZonePlacement.setAcceptHoverEvents(False)
  1095. self.addItem(self.polygoneZonePlacement)
  1096. listeCases2 = []
  1097. for coord in listeCases:
  1098. if self.cases[coord].estFranchissable():
  1099. listeCases2.append(coord)
  1100. self.polygoneZonePlacement.setPolygon(self.polygoneAgglo(listeCases2))
  1101. self.listeCasesZonePlacement = listeCases
  1102. def materialiserPions(self,actif):
  1103. """avtive/desactive la reception par les pions (autres que le pion selectionne) des hover events"""
  1104. for numCombattant in self.combattants:
  1105. if numCombattant != self.modeParam["numPionSelectionne"]:
  1106. self.combattants[numCombattant].setAcceptsHoverEvents(actif)
  1107. self.combattants[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
  1108. for numCombattant in self.decors:
  1109. self.decors[numCombattant].setAcceptsHoverEvents(actif)
  1110. self.decors[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
  1111. #######################
  1112. ######## interaction avec les cases, decors et pions #############
  1113. def pionSelectionne(self):
  1114. """renvoie le pion actuellement selectionne"""
  1115. retour = None
  1116. if self.modeActif.__class__.__name__ == "PionSelectionne":
  1117. retour = self.modeActif.pion()
  1118. return retour
  1119. def caseCliquee(self, x, y):
  1120. """on a clique sur la case (clic gauche)"""
  1121. coord = (x, y)
  1122. self.modeActif.clic_case(coord)
  1123. def caseSurvolClicEnfonce(self, coord):
  1124. """une case est survolee par le curseur (le clic gauche est enfonce)"""
  1125. self.modeActif.survolClic_case(coord)
  1126. def caseSurvol(self, x, y):
  1127. """une case est survole par le curseur, on affiche ses informations dans la zone prevue"""
  1128. self.majInfosCase(self.cases[(x,y)])
  1129. self.modeActif.survol_case((x,y))
  1130. def afficherListeCases(self, listeCases, actif):
  1131. """met ou non en evidence les cases selectionnees"""
  1132. for coord in listeCases:
  1133. self.cases[coord].majEstCibleCurseur(actif)
  1134. def pionClique(self, num):
  1135. """on a clique sur ce pion"""
  1136. accepte = False
  1137. if num < 10000:
  1138. self.modeActif.clic_combattant(num)
  1139. else:
  1140. self.modeActif.clic_decor(num)
  1141. def combattantSurvol(self, num):
  1142. """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
  1143. if num in self.combattants:
  1144. self.modeActif.survol_combattant(num)
  1145. pion = self.combattants[num]
  1146. self.majInfosCombattant(pion)
  1147. self.caseSurvol(pion.position[0], pion.position[1])
  1148. else:
  1149. self.modeActif.finSurvol_combattant(num)
  1150. self.majInfosCombattant(None)
  1151. def decorSurvol(self, num):
  1152. """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
  1153. if num in self.decors:
  1154. self.modeActif.survol_decor(num)
  1155. pion = self.decors[num]
  1156. self.majInfosDecor(pion)
  1157. self.caseSurvol(pion.position[0], pion.position[1])
  1158. else:
  1159. self.modeActif.finSurvol_decor(num)
  1160. self.majInfosDecor(None)
  1161. def pionDoubleClic(self, numCombattant):
  1162. """on a double-clique sur le pion"""
  1163. self.modeActif.doubleClic_combattant(numCombattant)
  1164. def creerPion(self, pionModele):
  1165. """creer un pion (combattant ou decor) aux coordonnees indiquees"""
  1166. cree = False
  1167. if self.proj.projectionValide():
  1168. if pionModele.__class__.__name__ == "Combattant":
  1169. pion = Combattant()
  1170. elif pionModele.__class__.__name__ == "Decor":
  1171. pion = Decor()
  1172. for elt in pionModele.__dict__:
  1173. pion.__dict__[elt] = pionModele.__dict__[elt]
  1174. if pionModele.__class__.__name__ == "Combattant":
  1175. numero = 1
  1176. if len(self.combattants) > 0:
  1177. numero = max(self.combattants) + 1
  1178. pion.numero = numero
  1179. pion.numComplementaire = self.numeroterNom(pion.nom)
  1180. self.combattants[numero] = pion
  1181. self.pionDeplacerDansOrdreJeu(numero, len(self.ordreJeu) + 2)
  1182. elif pionModele.__class__.__name__ == "Decor":
  1183. numero = 10001
  1184. if len(self.decors) > 0:
  1185. numero = max(self.decors) + 10001
  1186. pion.numero = numero
  1187. self.decors[numero] = pion
  1188. pion.position = self.proj.coord()
  1189. pion.nbRotations = self.proj.nbRotations()
  1190. pion.ajouterAuPlateau(self)
  1191. cree = True
  1192. return cree
  1193. def numeroterNom(self, nom):
  1194. """renvoie le nom du pion avec un numero complementaire si necessaire """
  1195. i = 1
  1196. for numCombattant in self.combattants:
  1197. if self.combattants[numCombattant].nom == nom:
  1198. i += 1
  1199. if i == 1:
  1200. retour = ""
  1201. else:
  1202. retour = str(i)
  1203. return retour
  1204. def pionDeposer(self, coordCase):
  1205. """on depose le pion sur la case voulue"""
  1206. if self.pionSelectionne() != None:
  1207. pion = self.pionSelectionne()
  1208. if pion != None:
  1209. if self.proj.projectionValide():
  1210. pion.majPosition(self.proj.coord(), self.proj.nbRotations())
  1211. def majZPion(self, valeur):
  1212. """met a jour l'altitude du pion selectionne"""
  1213. if self.pionSelectionne() != None:
  1214. self.pionSelectionne().majZ(valeur)
  1215. def pionSupprimer(self, num):
  1216. """supprime le pion entre en parametre"""
  1217. #settrace(trace_calls)
  1218. if num in self.combattants:
  1219. for coord in self.combattants[num].forme.listeCases(self.combattants[num].position, self.combattants[num].nbRotations):
  1220. self.cases[coord].majOccupation(self.combattants[num])
  1221. self.pionDeplacerDansOrdreJeu(num, 0)
  1222. pionSuppr = self.combattants.pop(num)
  1223. pionSuppr.retirerDuPlateau()
  1224. elif num in self.decors:
  1225. for coord in self.decors[num].forme.listeCases(self.decors[num].position, self.decors[num].nbRotations):
  1226. self.cases[coord].majOccupation(self.decors[num])
  1227. pionSuppr = self.decors.pop(num)
  1228. pionSuppr.retirerDuPlateau()
  1229. else:
  1230. print("erreur: ce pion n'est pas dans la liste des pions")
  1231. ###############
  1232. ######### caches ###############
  1233. def voirCacheEnCours(self):
  1234. """centre la vue sur et met en evidence le cache actif"""
  1235. if len(self.caches[self.cacheEnCours]["listeCases"]) > 0:
  1236. #centre la vue sur le premier point du polygone d'une case du milieu de la liste
  1237. indiceMilieu = int((len(self.caches[self.cacheEnCours]["listeCases"])/2))
  1238. self.vue().centerOn(self.cases[self.caches[self.cacheEnCours]["listeCases"][indiceMilieu]].polygon()[0])
  1239. #mettre en surbrillance
  1240. #for coord in self.caches[self.cacheEnCours]["listeCases"]:
  1241. # self.
  1242. def placerCacheEnCours(self):
  1243. """active le mode de mise a jour de la liste des cases cachees par ce cache"""
  1244. self.majMode("cachePlacer")
  1245. self.fenetre.ui.cacheActif.setChecked(True)
  1246. self.majEtatCacheEnCours()
  1247. def majEtatCacheEnCours(self):
  1248. """met a jour l'etat (actif ou non) du cache selon l'etat de la case correspondante"""
  1249. self.caches[self.cacheEnCours]["actif"] = self.fenetre.ui.cacheActif.isChecked()
  1250. self.majAffichageCache(self.cacheEnCours, self.caches[self.cacheEnCours]["actif"])
  1251. def majAffichageCache(self, numCache, afficher = True):
  1252. """met a jour l'affichage des cases selon les parametres enregistres pour le cache"""
  1253. if self.polygonesCaches[numCache] == None:
  1254. self.polygonesCaches[numCache] = Cache(self, numCache)
  1255. self.polygonesCaches[numCache].afficher(afficher, self.pinceau.selection())
  1256. ###############"
  1257. ######### gestion des evenements souris et clavier ###############
  1258. def mouseMoveEvent(self, event):
  1259. super(Plateau, self).mouseMoveEvent(event)
  1260. if event.buttons() == Qt.LeftButton and self.vue().dragMode() != QGraphicsView.ScrollHandDrag:
  1261. coord = self.coordonneesAuPoint(event.scenePos())
  1262. if coord != None:
  1263. self.caseSurvolClicEnfonce(coord)
  1264. else:
  1265. self.modeActif.mouvementSouris(event)
  1266. event.ignore()
  1267. def mousePressEvent(self, event):
  1268. super(Plateau, self).mousePressEvent(event)
  1269. if event.button() == 1:
  1270. self.modeActif.clicGauche(event)
  1271. elif event.button() == 2:
  1272. self.modeActif.clicDroit(event)
  1273. event.accept()
  1274. def mouseReleaseEvent(self, event):
  1275. super(Plateau, self).mouseReleaseEvent(event)
  1276. self.modeActif.finClicGauche(event)
  1277. def keyPressEvent(self, event):
  1278. """gestion des evenements clavier"""
  1279. toucheClavier = event.key()
  1280. self.modeActif.toucheClavier(event)
  1281. ################