Plateau.py 76 KB

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