Plateau.py 102 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101
  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. from Case import Case
  14. from Combattant import Combattant
  15. from Decor import Decor
  16. from Forme import Forme
  17. from Pinceau import Pinceau
  18. from ProjectionDep import ProjectionDep
  19. from Cache import Cache
  20. from EntreeSortie import EntreeSortie
  21. from EcranEditionCombattant import EcranEditionCombattant
  22. from EcranEditionDecors import EcranEditionDecors
  23. from EcranEditionTerrain import EcranEditionTerrain
  24. from EcranAffichageTexte import EcranAffichageTexte
  25. from EcranGestionCombat import EcranGestionCombat
  26. from EcranEditionAttaques import EcranEditionAttaques
  27. import regles as regles
  28. from outilsSvg import *
  29. from lancer import jet, estJetValide
  30. from operator import itemgetter, attrgetter
  31. from math import *
  32. m_couleursRapides = [(255,255,255), (200,200,200), (130,130,130), (90,90,90), (15,15,15), \
  33. (0,85,0), (170,255,0), (170,255,127), (85,85,0), (85,0,0), (170,85,0), (100,50,0), \
  34. (255,255,127), (240,80,0), (85,170,255), (85,85,255), (85,0,255), (0,255,255)]
  35. class Plateau(QGraphicsScene):
  36. """plateau de jeu contenant les cases, decors et pions"""
  37. def __init__(self, fenetre, parent=None):
  38. super(Plateau, self).__init__()
  39. #parametres et variables
  40. self.fenetre = fenetre
  41. ##partie et infos plateau
  42. self.id = ""
  43. self.nom = ""
  44. self.chapitre = 0
  45. self.tour = 1
  46. self.enCours = False
  47. self.public = False
  48. self.dateCreation = ""
  49. self.dateSvg = ""
  50. self.notes = ""
  51. #carac
  52. self.nbCasesX = 0
  53. self.nbCasesY = 0
  54. self.hCase = 0
  55. self.modePrincipal = "creation"
  56. self.modeCombat = ""
  57. #interface
  58. self.nbZoomActuel = 0
  59. self.epaisseurpinceau = 0
  60. #objets
  61. self.pinceau = Pinceau(self)
  62. self.cases = {} #dict des cases du plateau (coordonnées: case)
  63. self.combattants = {} #liste de combattants positionnes sur le plateau
  64. self.decors = {} #liste des decors places sur le plateau
  65. self.cacheEnCours = 1
  66. self.caches = {}
  67. self.polygonesCaches = {}
  68. for i in range(1,5):
  69. self.caches[i] = {"actif":False,"listeCases":[]}
  70. self.polygonesCaches[i] = None
  71. self.listeCasesZonePlacement = []
  72. self.polygoneZonePlacement = None
  73. self.entreesSorties = []
  74. #infos combat
  75. self.numCombattantEnCours = 0
  76. self.ordreJeu = {} #numero du pion: ordre de jeu
  77. #note: la hauteur Z (qui gere l'empilement des objets graphiques est distribuee de cette maniere:
  78. #cases : 0 a 9
  79. #pions : 10 et +
  80. def __getstate__(self):
  81. self.dateSvg = time()
  82. state = {key:value for key, value in self.__dict__.items() if not key in ["fenetre", "modeActif", "listMode", "cacheEnCours", \
  83. "modeParam", "nbZoomActuel", "epaisseurPinceau", \
  84. "editionTerrain", "editionCreature", "editionDecor", \
  85. "polygoneZonePlacement", "gestionCombat", "polygonesCaches", \
  86. "editionAttaques", "pinceau"]}
  87. return (state)
  88. def __setstate__(self, state):
  89. self.__dict__ = state
  90. def creer(self, idPlateau, nom, chapitre, formeCases, nbCasesX, nbCasesY, couleur = QColor(0, 255, 0, 80)):
  91. """cree le plateau"""
  92. self.id = idPlateau
  93. self.nom = nom
  94. self.chapitre = chapitre
  95. self.dateCreation = time()
  96. self.hCase = 120 #hauteur d'une case
  97. self.nbCasesX = nbCasesX #nb cases en x
  98. self.nbCasesY = nbCasesY #nb cases en y
  99. self.formeCases = formeCases
  100. self.gestionCombat = None
  101. self.initialisationGraphique()
  102. self.connexions()
  103. #cree les cases hexagonales
  104. for x in range(nbCasesX):
  105. for y in range(nbCasesY):
  106. if formeCases == "H":
  107. if 1 == (x % 2):
  108. y += 0.5
  109. c = Case(self)
  110. c.creer(x, y, couleur)
  111. self.cases[(x,y)] = c
  112. def recreer(self, fenetre):
  113. self.fenetre = fenetre
  114. self.gestionCombat = None
  115. super(Plateau, self).__init__()
  116. self.connexions()
  117. self.initialisationGraphique()
  118. #recreation des cases
  119. for coord in self.cases:
  120. self.cases[coord].recreer(self)
  121. #recreation des pions
  122. for numCombattant in self.combattants:
  123. self.combattants[numCombattant].ajouterAuPlateau(self)
  124. self.majOrdreJeu()
  125. #recreation des decors
  126. for num in self.decors:
  127. self.decors[num].ajouterAuPlateau(self)
  128. #recreation des marqueurs entree/sortie
  129. for entreeSortie in self.entreesSorties:
  130. entreeSortie.recreer(self)
  131. #recreation de la zone de placement:
  132. if len(self.listeCasesZonePlacement) > 0:
  133. self.polygoneZonePlacement = None
  134. self.majZonePlacement(self.listeCasesZonePlacement)
  135. #recreation des caches
  136. self.polygonesCaches = {}
  137. for i in range(1,5):
  138. self.polygonesCaches[i] = None
  139. def fermer(self):
  140. """ferme le plateau 'proprement'"""
  141. self.miniature()
  142. self.pinceau = None
  143. for item in self.items():
  144. item.prepareGeometryChange()
  145. self.removeItem(item)
  146. if self.gestionCombat != None:
  147. del self.gestionCombat
  148. self.fenetre.reinitialiserPanneauxPlateau()
  149. def miniature(self):
  150. """renvoie une miniature du plateau (QPixMap compresse) qui sera enregistree avec les infos de la sauvegarde"""
  151. ## img = QImage(128, 128, QImage.Format_ARGB32_Premultiplied)
  152. img = QPixmap(1024, 768)
  153. img.fill(QColor("white"))
  154. peintre = QPainter(img)
  155. rendu = self.render(peintre)
  156. peintre.end()
  157. img.scaledToHeight(128, Qt.FastTransformation)
  158. def connexions(self):
  159. """connecte le plateau aux differents widgets de la fenetre principale"""
  160. #modes d'interaction
  161. self.fenetre.connect(self.fenetre.ui.cbt_modeCreation, SIGNAL("clicked()"), self.plateauModeCreation, Qt.UniqueConnection)
  162. self.fenetre.connect(self.fenetre.ui.cbt_modeCombat, SIGNAL("clicked()"), self.plateauModeCombat, Qt.UniqueConnection)
  163. ## self.fenetre.connect(self.fenetre.ui.modeAffichagePlateau, SIGNAL("currentIndexChanged(int)"), self.majModeAffichage, Qt.UniqueConnection)
  164. #affichage de fenetres
  165. self.fenetre.connect(self.fenetre.ui.cbt_afficherGestion, SIGNAL("clicked()"), self.afficheEcranGestionCombat, Qt.UniqueConnection)
  166. self.fenetre.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee, Qt.UniqueConnection)
  167. self.fenetre.connect(self.fenetre.ui.cp_dialogueCouleurs, SIGNAL("clicked()"), self.modePeintureCase, Qt.UniqueConnection)
  168. self.fenetre.connect(self.fenetre.ui.cp_pipetteCouleur, SIGNAL("clicked()"), self.modeCopieTerrain, Qt.UniqueConnection)
  169. self.fenetre.connect(self.fenetre.ui.cp_afficherNotes, SIGNAL("clicked()"), self.agrandirNotesMjPlateau, Qt.UniqueConnection)
  170. #listes
  171. self.fenetre.connect(self.fenetre.ui.inf_listeOrdreJeu, SIGNAL("cellClicked(int,int)"), self.clicListOrdreJeu, Qt.UniqueConnection)
  172. self.fenetre.connect(self.fenetre.ui.cp_listeTerrains, SIGNAL("cellClicked(int,int)"), self.modeMajTerrainCase, Qt.UniqueConnection)
  173. self.fenetre.connect(self.fenetre.ui.cp_listeCreatures, SIGNAL("cellClicked(int,int)"), self.modeCreationCombattant, Qt.UniqueConnection)
  174. self.fenetre.connect(self.fenetre.ui.cp_listeDecors, SIGNAL("cellClicked(int,int)"), self.modeCreationDecor, Qt.UniqueConnection)
  175. self.fenetre.connect(self.fenetre.ui.cp_editerTerrain, SIGNAL("clicked()"), self.terrainEdit, Qt.UniqueConnection)
  176. self.fenetre.connect(self.fenetre.ui.cp_nouveauTerrain, SIGNAL("clicked()"), self.terrainNouveau, Qt.UniqueConnection)
  177. self.fenetre.connect(self.fenetre.ui.cp_editerCombattant, SIGNAL("clicked()"), self.creatureEdit, Qt.UniqueConnection)
  178. self.fenetre.connect(self.fenetre.ui.cp_nouveauCombattant, SIGNAL("clicked()"), self.creatureNouveau, Qt.UniqueConnection)
  179. ## self.fenetre.connect(self.fenetre.ui.decorEdit, SIGNAL("clicked()"), self.decorEdit, Qt.UniqueConnection)
  180. ## self.fenetre.connect(self.fenetre.ui.decorNouveau, SIGNAL("clicked()"), self.decorNouveau, Qt.UniqueConnection)
  181. ## self.fenetre.connect(self.fenetre.ui.editerAttaques, SIGNAL("clicked()"), self.afficheEcranEditionAttaques, Qt.UniqueConnection)
  182. #creation
  183. self.fenetre.connect(self.fenetre.ui.cp_epaisseurPinceau, SIGNAL("valueChanged(int)"), self.majEpaisseurPinceau, Qt.UniqueConnection)
  184. ## self.fenetre.connect(self.fenetre.ui.altitudeCase, SIGNAL("valueChanged(double)"), self.modeMajAltitudeCase, Qt.UniqueConnection)
  185. #autres:
  186. #ajouter effet
  187. self.fenetre.connect(self.fenetre.ui.cp_placerEntree, SIGNAL("clicked()"), self.majModeDefinirEntree, Qt.UniqueConnection)
  188. self.fenetre.connect(self.fenetre.ui.cp_placerSortie, SIGNAL("clicked()"), self.majModeDefinirSortie, Qt.UniqueConnection)
  189. self.fenetre.connect(self.fenetre.ui.cp_defPlacement, SIGNAL("clicked()"), self.majModeZonePlacement, Qt.UniqueConnection)
  190. ## self.fenetre.connect(self.fenetre.ui.cacheActif, SIGNAL("clicked()"), self.majEtatCacheEnCours, Qt.UniqueConnection)
  191. ## self.fenetre.connect(self.fenetre.ui.cacheVoir, SIGNAL("clicked()"), self.voirCacheEnCours, Qt.UniqueConnection)
  192. ## self.fenetre.connect(self.fenetre.ui.cachePlacer, SIGNAL("clicked()"), self.placerCacheEnCours, Qt.UniqueConnection)
  193. ## self.fenetre.connect(self.fenetre.ui.notesMjPlateau, SIGNAL("textChanged()"), self.majNotesPlateau, Qt.UniqueConnection)
  194. self.fenetre.connect(self.fenetre.ui.pi_notes, SIGNAL("textChanged()"), self.majNotesCombattant, Qt.UniqueConnection)
  195. #formes (dessin)
  196. self.fenetre.connect(self.fenetre.ui.cp_formeSimple, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  197. self.fenetre.connect(self.fenetre.ui.cp_formeLigne, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  198. self.fenetre.connect(self.fenetre.ui.cp_formeLigneOrientee, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  199. self.fenetre.connect(self.fenetre.ui.cp_formeEllipseVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  200. self.fenetre.connect(self.fenetre.ui.cp_formeEllipsePlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  201. self.fenetre.connect(self.fenetre.ui.cp_formeRectVide, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  202. self.fenetre.connect(self.fenetre.ui.cp_formeRectPlein, SIGNAL("clicked()"), self.majModeForme, Qt.UniqueConnection)
  203. ## self.fenetre.connect(self.fenetre.ui.effFeu, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection)
  204. ## self.fenetre.connect(self.fenetre.ui.effEau, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection)
  205. ## self.fenetre.connect(self.fenetre.ui.effGlace, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection)
  206. ## self.fenetre.connect(self.fenetre.ui.effPoison, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection)
  207. ## self.fenetre.connect(self.fenetre.ui.effEffacer, SIGNAL("clicked()"), self.modeCaseEffet, Qt.UniqueConnection)
  208. self.fenetre.connect(self.fenetre.ui.pi_deplacement, SIGNAL("clicked()"), self.majModeCombatDeplacement, Qt.UniqueConnection)
  209. self.fenetre.connect(self.fenetre.ui.pi_attaqueCac, SIGNAL("clicked()"), self.majModeCombatAttaqueCaC, Qt.UniqueConnection)
  210. self.fenetre.connect(self.fenetre.ui.pi_attaqueDist, SIGNAL("clicked()"), self.majModeCombatAttaqueDist, Qt.UniqueConnection)
  211. ## self.fenetre.connect(self.fenetre.ui.combatAttaqueZone, SIGNAL("clicked()"), self.fenetre.barreCombatZone, Qt.UniqueConnection)
  212. self.fenetre.connect(self.fenetre.ui.pi_attaqueZone, SIGNAL("clicked()"), self.majModeCombatZone, Qt.UniqueConnection)
  213. ## self.fenetre.connect(self.fenetre.ui.pi_vol, SIGNAL("clicked()"), self.fenetre.barreCombatVol, Qt.UniqueConnection)
  214. ## self.fenetre.connect(self.fenetre.ui.combatVol_altitude, SIGNAL("valueChanged(int)"), self.majZPion, Qt.UniqueConnection)
  215. ## self.fenetre.connect(self.fenetre.ui.combatZone_ligne, SIGNAL("clicked()"), self.majModeCombatZoneForme, Qt.UniqueConnection)
  216. ## self.fenetre.connect(self.fenetre.ui.combatZone_disque, SIGNAL("clicked()"), self.majModeCombatZoneForme, Qt.UniqueConnection)
  217. ## self.fenetre.connect(self.fenetre.ui.combatZone_cone, SIGNAL("clicked()"), self.majModeCombatZoneForme, Qt.UniqueConnection)
  218. self.fenetre.connect(self.fenetre.ui.pi_finTour, SIGNAL("clicked()"), self.pionSuivant, Qt.UniqueConnection)
  219. #self.fenetre.connect(self.fenetre.ui.combatVol_altitude, SIGNAL("editingFinished()"), self.majVisibiliteBarreCombat)
  220. def initialisationGraphique(self):
  221. """cree la scene graphique et les parametres necessaires a son fonctionnement, et met a jour l'interface"""
  222. #on cree la scene graphique
  223. kx = 1
  224. if self.formeCases == "H":
  225. kx = 0.866
  226. marge = 240
  227. self.setSceneRect(0 - marge, 0 - marge, (kx*self.hCase*(self.nbCasesX+2)) + marge, (self.hCase*(self.nbCasesY+2)) + marge)
  228. self.fenetre.ui.cbt_vue.setScene(self)
  229. self.fenetre.ui.cbt_vue.scale(0.25, 0.25)
  230. self.fenetre.ui.cbt_vue.centerOn(QPointF(0,0))
  231. self.fenetre.ui.cbt_vue.setDragMode(1)
  232. self.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
  233. #self.setItemIndexMethod(QGraphicsScene.NoIndex)
  234. self.nbZoomActuel = 0
  235. self.epaisseurPinceau = 1
  236. self.polygoneZonePlacement = None
  237. self.polygonesCaches = {}
  238. for i in range(1,5):
  239. self.polygonesCaches[i] = None
  240. #gestion du mode d'interaction avec le plateau
  241. self.modeActif = Modes.Standard(self)
  242. self.modeActif_old = ""
  243. self.pinceau = Pinceau(self)
  244. self.proj = ProjectionDep(self)
  245. self.modeParam = {"numPionSelectionne": 0, "pionNouveau": None, "creature": None, "decor": None, \
  246. "formeCoordEnCours": (0,0), \
  247. "zoneAttaqueCaC": [], "cibleAttaqueCaC": None, "cibleAttaqueDist": None, "pionCibleAttaqueDist": None, "ligneAttaqueDist": None, \
  248. "typeAttaqueZone": "", "formeAttaqueZone": None, "origineAttaqueZone": None, "point2AttaqueZone": None, \
  249. "listeCasesAttaqueZone": [], "ligneMireAttaqueZone": None}
  250. #mise a jour de l'interface de creation
  251. self.fenetre.majVisibilitePanneauxPlateau("creation")
  252. ## self.fenetre.ui.cbt_nomPlateau.setText(QString.fromUtf8(self.nom))
  253. self.majBoutonsCouleursPerso()
  254. ## self.majBoutonsCaches()
  255. self.fenetre.ui.cp_listeTerrains.defFichier("lib\\biblio\\terrain")
  256. self.fenetre.ui.cp_listeTerrains.initAffichage()
  257. self.fenetre.ui.cp_listeCreatures.defFichier("lib\\biblio\\combattant")
  258. self.fenetre.ui.cp_listeCreatures.initAffichage()
  259. self.fenetre.ui.cp_listeDecors.defFichier("lib\\biblio\\decor")
  260. self.fenetre.ui.cp_listeDecors.initAffichage()
  261. self.majListeTerrains()
  262. self.majListeCreatures()
  263. self.majListeDecors()
  264. self.initListeOrdreJeu()
  265. self.initListeAttaques()
  266. ## self.fenetre.ui.notesMjPlateau.setText(QString.fromUtf8(self.notes))
  267. self.fenetre.ui.pi_deplacement.setCheckable(True)
  268. self.fenetre.ui.pi_attaqueCac.setCheckable(True)
  269. self.fenetre.ui.pi_attaqueDist.setCheckable(True)
  270. self.fenetre.ui.pi_attaqueZone.setCheckable(True)
  271. #mise a jour de l'interface d'informations
  272. self.majInfosPion(None)
  273. self.majInfosDecor(None)
  274. def estCree(self):
  275. """renvoie vrai si des cases ont ete creees"""
  276. return (len(self.cases) > 0)
  277. def majBoutonsCouleursPerso(self):
  278. """met a jour l'affichage des couleurs customisees dans la boite de dialogue de selection de couleur"""
  279. for i in range(0,18):
  280. couleur = QColor()
  281. r, g, b = m_couleursRapides[i]
  282. couleur.setRgb(r, g, b)
  283. bouton = self.fenetre.ui.cp_boiteCouleurs.findChild(QToolButton, "cp_couleur{}".format(i+1))
  284. if couleur.isValid():
  285. bouton.setStyleSheet("QToolButton {backGround:%s}"%(couleur.name()))
  286. self.fenetre.connect(bouton, SIGNAL("clicked()"), self.modePeintureCase_perso)
  287. def chercherCouleur(self):
  288. """ouvre la boite de dialogue de selection de couleur"""
  289. couleur = QColorDialog(self.fenetre.ui.cbt_vue).getColor(QColor("white"), self.fenetre.ui.cbt_vue)
  290. return couleur
  291. ## def majBoutonsCaches(self):
  292. ## """met a jour l'affichage et connecte les boutons de caches"""
  293. ## for i in range(1,5):
  294. ## bouton = self.fenetre.ui.outilsEditionPlateau.findChild(QToolButton, "plateauCache{}".format(i))
  295. ## self.fenetre.connect(bouton, SIGNAL("clicked()"), self.majAffichageMenuCache)
  296. def majListesPions(self, numCombattant = None):
  297. """met a jour les listes contenant des donnees liees aux pions"""
  298. ## self.majListeOrdreJeu()
  299. ##
  300. ## if numCombattant == None or numCombattant == self.pionSelectionne().numero:
  301. ## self.majListeAttributs()
  302. ## QApplication.processEvents()
  303. pass
  304. ## def majNotesPlateau(self):
  305. ## """les notes du plateau ont ete maj a l'ecran"""
  306. ## self.notes = str(self.fenetre.ui.notesMjPlateau.toPlainText().toUtf8())
  307. def agrandirNotesMjPlateau(self):
  308. """affiche les notes du plateau dans une QDialog, puis recupere les donnees qui y sont saisies"""
  309. affichageTexte = EcranAffichageTexte(self.notes)
  310. affichageTexte.setAttribute(Qt.WA_DeleteOnClose)
  311. r = affichageTexte.exec_()
  312. self.notes = affichageTexte.recupererTexte()
  313. ## self.fenetre.ui.notesMjPlateau.setText(QString.fromUtf8(affichageTexte.recupererTexte()))
  314. ##### affichage de la liste des terrains enregistres, et fonctions d'acces aux donnees""""
  315. def afficheEcranEditionTerrains(self, terrain = None):
  316. """affiche l'ecran d'edition/creation de terrains"""
  317. self.editionTerrain = EcranEditionTerrain(terrain)
  318. self.editionTerrain.setAttribute(Qt.WA_DeleteOnClose)
  319. r = self.editionTerrain.exec_()
  320. if r == 1:
  321. self.majListeTerrains()
  322. def majListeTerrains(self):
  323. """mise a jour de la liste des terrains depuis la sauvegarde"""
  324. self.fenetre.ui.cp_listeTerrains.maj()
  325. self.activerMode(Modes.Standard)
  326. def terrainEdit(self):
  327. """ouvre la fenetre 'terrains' en mode edition"""
  328. index = self.fenetre.ui.cp_listeTerrains.item(self.fenetre.ui.cp_listeTerrains.currentRow(), 0)
  329. if index > 0:
  330. terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
  331. self.afficheEcranEditionTerrains(terrain)
  332. def terrainNouveau(self):
  333. """ouvre la fenetre 'terrains' en mode edition"""
  334. self.afficheEcranEditionTerrains()
  335. ###############
  336. ##### affichage de la liste des creatures enregistrees, et fonctions d'acces aux donnees""""
  337. def afficheEcranEditionCombattants(self, creature = None):
  338. """affiche l'ecran d'edition/creation de creatures"""
  339. self.editionCreature = EcranEditionCombattant(creature, self.formeCases)
  340. self.editionCreature.setAttribute(Qt.WA_DeleteOnClose)
  341. r = self.editionCreature.exec_()
  342. if r == 1:
  343. self.majListeCreatures()
  344. def majListeCreatures(self):
  345. """mise a jour de la liste des creatures depuis la sauvegarde"""
  346. self.fenetre.ui.cp_listeCreatures.maj()
  347. self.activerMode(Modes.Standard)
  348. def creatureEdit(self):
  349. """ouvre la fenetre 'creatures' en mode edition"""
  350. index = self.fenetre.ui.cp_listeCreatures.item(self.fenetre.ui.cp_listeCreatures.currentRow(), 0)
  351. if index > 0:
  352. creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
  353. self.afficheEcranEditionCombattants(creature)
  354. def creatureNouveau(self):
  355. """ouvre la fenetre 'creatures' en mode edition"""
  356. self.afficheEcranEditionCombattants()
  357. ###############
  358. ##### affichage de la liste des decors enregistrees, et fonctions d'acces aux donnees""""
  359. def afficheEcranEditionDecors(self, decor = None):
  360. """affiche l'ecran d'edition/creation de decors"""
  361. self.editionDecor = EcranEditionDecors(decor, self.formeCases)
  362. self.editionDecor.setAttribute(Qt.WA_DeleteOnClose)
  363. r = self.editionDecor.exec_()
  364. if r == 1:
  365. self.majListeDecors()
  366. def majListeDecors(self):
  367. """mise a jour de la liste des decors depuis la sauvegarde"""
  368. self.fenetre.ui.cp_listeDecors.maj()
  369. self.activerMode(Modes.Standard)
  370. def decorEdit(self):
  371. """ouvre la fenetre 'decors' en mode edition"""
  372. self.afficheEcranEditionDecors(self.fenetre.ui.cp_listeDecors.actuel())
  373. def decorNouveau(self):
  374. """ouvre la fenetre 'decors' en mode edition"""
  375. self.afficheEcranEditionDecors()
  376. ###############
  377. ########### affichage des curseurs personnalises ########
  378. def curseurGomme(self):
  379. self.fenetre.ui.cbt_vue.setDragMode(0)
  380. curseurPix = QPixmap("img\\gomme.png")#.scaledToHeight(55, Qt.FastTransformation)
  381. curseurGomme = QCursor(curseurPix, 0, 0)
  382. self.fenetre.ui.cbt_vue.setCursor(curseurGomme)
  383. def curseurEpee(self, valide = True):
  384. self.fenetre.ui.cbt_vue.setDragMode(0)
  385. if valide:
  386. curseurPix = QPixmap("img\\curseurEpee.png")
  387. curseurSeringue = QCursor(curseurPix, 0, 0)
  388. self.fenetre.ui.cbt_vue.setCursor(curseurSeringue)
  389. def curseurArc(self):
  390. self.fenetre.ui.cbt_vue.setDragMode(0)
  391. curseurPix = QPixmap("img\\arc.png")
  392. curseurSeringue = QCursor(curseurPix, curseurPix.width(), 0)
  393. self.fenetre.ui.cbt_vue.setCursor(curseurSeringue)
  394. def curseurBaguette(self):
  395. self.fenetre.ui.cbt_vue.setDragMode(0)
  396. curseurPix = QPixmap("img\\baguette.png")
  397. curseurBaguette = QCursor(curseurPix, curseurPix.width(), 0)
  398. self.fenetre.ui.cbt_vue.setCursor(curseurBaguette)
  399. ############
  400. ##### activation des differents modes d'interaction avec le plateau et mises a jour des principaux parametres #######
  401. def plateauModeCreation(self):
  402. self.fenetre.majVisibilitePanneauxPlateau("creation")
  403. self.modePrincipal = "creation"
  404. def plateauModeCombat(self):
  405. self.fenetre.majVisibilitePanneauxPlateau("combat")
  406. self.modePrincipal = "combat"
  407. def activerMode(self, mode, param = None):
  408. """desactive le mode actif et active le nouveau a la place"""
  409. self.modeActif.desactiver()
  410. self.modeActif = mode(self)
  411. self.modeActif.activer(param)
  412. ## def majModeAffichage(self, index):
  413. ## """met a jour le mode d'affichage"""
  414. ## nouveauMode = ""
  415. ## if index == 0:
  416. ## #passe a l'affichage standard
  417. ## pass
  418. ## elif index == 1:
  419. ## #passe en mode affichage de l'altitude
  420. ## nouveauMode = "altitude"
  421. ## elif index == 2:
  422. ## #affichage des terrains slt
  423. ## nouveauMode = "terrain"
  424. ## elif index == 3:
  425. ## #affichage tactique
  426. ## nouveauMode = "tactique"
  427. ##
  428. ## for coord in self.cases:
  429. ## self.cases[coord].majAffichageSpecial(nouveauMode)
  430. def modePeintureCase(self):
  431. """enclenche le mode peinture de case a partir de la couleur selectionnee"""
  432. couleur = self.chercherCouleur()
  433. if couleur.isValid():
  434. self.activerMode(Modes.MajCases, couleur)
  435. else:
  436. self.activerMode(Modes.Standard)
  437. def modePeintureCase_perso(self):
  438. origine = self.sender().objectName()
  439. index = int(origine.replace("cp_couleur",""))-1
  440. couleur = QColor()
  441. r, g, b = m_couleursRapides[index]
  442. couleur.setRgb(r, g, b)
  443. if couleur.isValid():
  444. self.activerMode(Modes.MajCases, couleur)
  445. else:
  446. self.activerMode(Modes.Standard)
  447. def modeCopieTerrain(self):
  448. """enclenche le mode copie de case"""
  449. self.activerMode(Modes.Pipette)
  450. def modeCaseEffet(self):
  451. """enclenche le mode de mise a jour de l'ffet actif des cases"""
  452. origine = self.sender().objectName()
  453. if origine == "effFeu":
  454. effet = "brule"
  455. elif origine == "effEau":
  456. effet = "eau"
  457. elif origine == "effGlace":
  458. effet = "glace"
  459. elif origine == "effPoison":
  460. effet = "poison"
  461. elif origine == "effEffacer":
  462. effet = "aucun"
  463. self.activerMode(ModesCaseMaj, effet)
  464. def modeCreationPion(self):
  465. """enclenche le mode de creation de pions simples"""
  466. self.majMode("pionCreation")
  467. def majModePionSupprimer(self):
  468. """enclenche le mode suppression de pions sur clic gauche (creatures ou decors)"""
  469. self.majMode("pionSupprimer")
  470. def modeCreationDecor(self, ligne, col):
  471. """enclenche le mode de creation de decors depuis la liste des decors"""
  472. index = self.fenetre.ui.cp_listeDecors.item(ligne, 0)
  473. decor = charger("lib\\biblio\\decor", str(index.text().toUtf8()))
  474. self.majMode("pionDecorCreation", decor)
  475. self.fenetre.ui.cbt_vue.setFocus()
  476. def modeCreationCombattant(self, ligne, col):
  477. """enclenche le mode de creation de pions depuis la liste des creatures"""
  478. index = self.fenetre.ui.cp_listeCreatures.item(ligne, 0)
  479. creature = charger("lib\\biblio\\combattant", str(index.text().toUtf8()))
  480. self.majMode("pionCreation", creature)
  481. self.fenetre.ui.cbt_vue.setFocus()
  482. def modeMajTerrainCase(self, ligne, col):
  483. """enclenche le mode permettant la mise a jour du terrain des cases"""
  484. index = self.fenetre.ui.cp_listeTerrains.item(ligne, 0)
  485. terrain = charger("lib\\biblio\\terrain", str(index.text().toUtf8()))
  486. if terrain:
  487. self.activerMode(Modes.MajCases, terrain)
  488. else:
  489. print "terrain invalide"
  490. def majEpaisseurPinceau(self, epaisseur):
  491. """met a jour l'epaisseur du pinceau (en cases)"""
  492. self.fenetre.ui.cp_valeurEpaisseurPinceau.setText(QString.fromUtf8(str(epaisseur)))
  493. self.pinceau.majEpaisseur(int(epaisseur))
  494. def modeMajAltitudeCase(self):
  495. self.majMode("caseMajAltitude")
  496. def majModeForme(self):
  497. """met a jour la forme utilisee pour la peinture"""
  498. formes = {"cp_formeSimple": "simple", \
  499. "cp_formeLigne": "ligne", \
  500. "cp_formeLigneOrientee": "frontiere", \
  501. "cp_formeEllipseVide": "ellipseV", \
  502. "cp_formeEllipsePlein": "ellipseP", \
  503. "cp_formeRectVide": "rectV", \
  504. "cp_formeRectPlein": "rectP"}
  505. self.pinceau.majForme(formes[str(self.sender().objectName())])
  506. def majModeCombatDeplacement(self):
  507. """active le mode de combat 'deplacement' (mode standard)"""
  508. self.majModeCombat("combatDeplacement")
  509. def majModeCombatAttaqueCaC(self):
  510. """active le mode de combat 'corps-a-corps'"""
  511. self.majModeCombat("combatAttaqueCaC")
  512. def majModeCombatAttaqueDist(self):
  513. """active le mode de combat 'attaque a distance'"""
  514. self.majModeCombat("combatAttaqueDist")
  515. def majModeCombatZone(self):
  516. if not len(self.modeParam["typeAttaqueZone"]) > 0: self.modeParam["typeAttaqueZone"] = "ligne"
  517. self.majModeCombat("combatAttaqueZone")
  518. def majModeCombatZoneForme(self):
  519. pass
  520. ## if self.modeCombat == "combatAttaqueZone":
  521. ## origine = self.sender().objectName()
  522. ## self.modeParam["typeAttaqueZone"] = str(origine).split("_")[1]
  523. ## self.majModeCombat("combatAttaqueZone")
  524. def majModeDefinirEntree(self):
  525. entree = EntreeSortie(self, "E")
  526. self.activerMode(Modes.EntreesSorties, entree)
  527. def majModeDefinirSortie(self):
  528. sortie = EntreeSortie(self, "S")
  529. self.activerMode(Modes.EntreesSorties, sortie)
  530. def majModeZonePlacement(self):
  531. self.activerMode(Modes.ZonePlacement)
  532. def majMode(self, mode = "standard", param = None):
  533. """modifie ou reinitialise le type d'interaction avec le plateau"""
  534. reinit = True #doit-on reinitialiser a la fin de l'operation
  535. ##on desactive le mode precedent
  536. if self.pionSelectionne() != None:
  537. self.pionSelectionne().afficheOmbreSelection(False)
  538. if self.modeActif_old == "pionSelectionne":
  539. self.majModeCombat("")
  540. self.modeParam["numPionSelectionne"] = 0
  541. elif self.pionDecorSelectionne() != None:
  542. self.pionDecorSelectionne().afficheOmbreSelection(False)
  543. self.modeParam["numPionSelectionne"] = 0
  544. if self.modeActif_old == "pionSelectionne" or self.modeActif_old == "pionCreation" or \
  545. self.modeActif_old == "pionDecorSelectionne" or self.modeActif_old == "pionDecorCreation":
  546. self.proj.desactiver()
  547. if self.modeActif_old[0:7] == "caseMaj" or self.modeActif_old == "cachePlacer" or self.modeActif_old == "majZonePlacement":
  548. self.pinceau.reinit()
  549. if self.modeActif_old == "placementEntreeSortie":
  550. if self.modeParam["entreeSortie"] != None:
  551. self.modeParam["entreeSortie"].prepareGeometryChange()
  552. self.removeItem(self.modeParam["entreeSortie"])
  553. self.modeParam["entreeSortie"] = None
  554. ### definition du nouveau mode
  555. if mode != "standard":
  556. self.modeActif_old = mode
  557. reinit = False
  558. if mode == "caseMajTerrain":
  559. #curseur pinceau, on ajoute des terrains au cases
  560. if param != None:
  561. self.curseurPinceau()
  562. self.fenetre.ui.cbt_vue.setDragMode(0)
  563. self.modeParam["terrain"] = param
  564. elif mode == "caseCopie":
  565. #curseur seringue, on 'preleve' le terrain sur la case cliquee, avant de passer en mode majTerrain
  566. self.curseurSeringue()
  567. self.fenetre.ui.cbt_vue.setDragMode(0)
  568. elif mode == "caseMajEffet":
  569. #on met a jour l'effet actif sur les cases
  570. if param != None:
  571. self.curseurPinceau()
  572. self.fenetre.ui.cbt_vue.setDragMode(0)
  573. self.modeParam["effet"] = param
  574. elif mode == "caseMajAltitude":
  575. self.curseurPinceau()
  576. self.fenetre.ui.cbt_vue.setDragMode(0)
  577. elif mode == "cachePlacer":
  578. self.curseurPinceau()
  579. self.fenetre.ui.cbt_vue.setDragMode(0)
  580. self.pinceau.majForme("rectP")
  581. self.pinceau.verrouillerForme(True)
  582. elif mode == "majZonePlacement":
  583. self.curseurPinceau()
  584. self.fenetre.ui.cbt_vue.setDragMode(0)
  585. self.pinceau.majForme("rectP")
  586. self.pinceau.verrouillerForme(True)
  587. elif mode == "placementEntreeSortie":
  588. self.fenetre.ui.cbt_vue.setDragMode(0)
  589. elif mode == "pionDecorCreation":
  590. #curseur 'plus', on cree de nouveaux decors
  591. self.modeParam["decor"] = None
  592. self.fenetre.ui.cbt_vue.setDragMode(0)
  593. if param != None:
  594. if param.__class__.__name__ == "Decor":
  595. self.modeParam["decor"] = param
  596. self.proj.creer(param)
  597. elif mode == "pionDecorSelectionne":
  598. #un pion decor est selectionne
  599. if param != None:
  600. self.modeParam["numPionSelectionne"] = param
  601. self.pionDecorSelectionne().afficheOmbreSelection(True)
  602. self.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
  603. self.proj.creer(self.pionDecorSelectionne())
  604. elif mode == "pionCreation":
  605. #curseur 'plus', on cree de nouveaux pions
  606. self.modeParam["creature"] = None
  607. self.fenetre.ui.cbt_vue.setDragMode(0)
  608. if param != None:
  609. if param.__class__.__name__ == "Combattant":
  610. self.modeParam["creature"] = param
  611. self.proj.creer(param)
  612. elif mode == "pionSupprimer":
  613. #mode suppression de pions/pions decors
  614. self.curseurGomme()
  615. self.fenetre.ui.cbt_vue.setDragMode(0)
  616. elif mode == "pionSelectionne":
  617. #un pion est selectionne, on affiche les deplacements possibles
  618. if param != None:
  619. self.modeParam["numPionSelectionne"] = param
  620. self.pionSelectionne().afficheOmbreSelection(True)
  621. self.numPionEnCours = param
  622. for i in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
  623. if str(self.fenetre.ui.inf_listeOrdreJeu.item(i, 0).text().toUtf8()) == str(param):
  624. self.fenetre.ui.inf_listeOrdreJeu.setCurrentCell(i,0)
  625. #bobby
  626. self.majAffichagePionSelectionne()
  627. self.majListeAttributs()
  628. self.afficherNotesCombattant()
  629. self.majListeAttaques()
  630. self.majModeCombat("aucun")
  631. ##on reinitialise si necessaire
  632. if reinit:
  633. #mode standard : pas d'interaction avec les cases, on deplace le plateau en le saisissant ou les pions en cliquant dessus
  634. self.modeActif_old = "standard"
  635. self.majAffichagePionSelectionne()
  636. self.majInfosPion()
  637. self.majInfosDecor()
  638. self.majListeAttributs()
  639. self.majListeAttaques()
  640. self.afficherNotesCombattant()
  641. ## self.fenetre.majVisibiliteBarreCombat("menu")
  642. QApplication.processEvents()
  643. self.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
  644. self.fenetre.ui.cbt_vue.setDragMode(1)
  645. else:
  646. self.fenetre.ui.cbt_vue.setFocus()
  647. def majModeCombat(self, mode = ""):
  648. """met a jour le mode de combat actif pour le pion selectionne"""
  649. ## on desactive le mode precedent si besoin
  650. #la projection de position
  651. if self.modeCombat == "combatDeplacement":
  652. #le champ de deplacement
  653. if self.modePrincipal == "combat":
  654. self.afficherChampDeplacement(False)
  655. self.proj.desactiver()
  656. elif self.modeCombat == "combatAttaqueCaC":
  657. #la zone d'attaque au cac
  658. self.materialiserPions(True)
  659. self.majZoneAttaqueCaC(False)
  660. self.modeParam["zoneAttaqueCaC"] = []
  661. if self.modeParam["cibleAttaqueCaC"] != None:
  662. self.modeParam["cibleAttaqueCaC"].estCibleAttaque(False)
  663. self.modeParam["cibleAttaqueCaC"] = None
  664. elif self.modeCombat == "combatAttaqueDist":
  665. self.materialiserPions(True)
  666. self.majLigneMireAttaqueDist()
  667. elif self.modeCombat == "combatAttaqueZone":
  668. #l'attaque de zone
  669. self.materialiserPions(True)
  670. QApplication.processEvents()
  671. self.reinitAttaqueZone()
  672. ## if mode != "combatAttaqueZone": self.fenetre.majVisibiliteBarreCombat("menu")
  673. self.modeParam["listeCasesAttaqueZone"] = []
  674. ## definition du nouveau mode de combat
  675. if self.pionSelectionne() != None:
  676. self.modeCombat = mode
  677. self.fenetre.ui.cbt_vue.setDragMode(0)
  678. if mode == "aucun":
  679. self.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
  680. if mode == "combatDeplacement":
  681. self.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))
  682. self.proj.creer(self.pionSelectionne())
  683. if self.modePrincipal == "combat":
  684. #si mode combat, affichage de la zone de deplacement
  685. self.afficherChampDeplacement(True)
  686. elif mode == "combatAttaqueCaC":
  687. self.curseurEpee()
  688. self.materialiserPions(False)
  689. ## self.modeParam["zoneAttaqueCaC"] = self.zone(self.pionSelectionne().position, self.pionSelectionne().allonge, True, True)
  690. self.modeParam["zoneAttaqueCaC"] = self.zone(self.pionSelectionne().position, 1, True, True)
  691. self.majZoneAttaqueCaC(True)
  692. elif mode == "combatAttaqueDist":
  693. self.curseurArc()
  694. self.materialiserPions(False)
  695. elif mode == "combatAttaqueZone":
  696. self.curseurBaguette()
  697. self.materialiserPions(False)
  698. self.majFormeAttaqueZone()
  699. ###############
  700. ########## Gestion du combat ##############
  701. def majAffichageTour(self):
  702. """met a jour l'affichage du tour en cours"""
  703. self.fenetre.ui.cbt_tour.setText(QString.fromUtf8("Tour: {}".format(self.tour)))
  704. def majAffichagePionSelectionne(self):
  705. """affiche le nom et le logo du pion actuellement selectionne"""
  706. if self.pionSelectionne() != None:
  707. self.fenetre.ui.pi_nom.setText(QString.fromUtf8(self.pionSelectionne().txtId()))
  708. if len(self.pionSelectionne().img.nomFichier) > 0:
  709. pix = QPixmap(QString.fromUtf8("img\\"+self.pionSelectionne().img.nomFichier))
  710. pix = pix.scaled(44, 44, Qt.KeepAspectRatio, Qt.SmoothTransformation)
  711. self.fenetre.ui.pi_img.setPixmap(pix)
  712. else:
  713. self.fenetre.ui.pi_img.setPixmap(QPixmap())
  714. else:
  715. self.fenetre.ui.pi_img.setPixmap(QPixmap())
  716. self.fenetre.ui.pi_nom.setText(QString.fromUtf8("Pas de pion\nselectionné"))
  717. def initListeOrdreJeu(self):
  718. """cree les colonnes et met en forme la table ordre jeu"""
  719. ## self.fenetre.ui.infoOrdreJeu.setColumnWidth(0, 20)
  720. self.fenetre.ui.inf_listeOrdreJeu.setColumnWidth(2, 30)
  721. self.fenetre.ui.inf_listeOrdreJeu.hideColumn(0)
  722. self.fenetre.ui.inf_listeOrdreJeu.hideColumn(2)
  723. self.fenetre.ui.inf_listeOrdreJeu.setIconSize(QSize(30,20))
  724. def majListeOrdreJeu(self):
  725. """met a jour la liste des pions infoOrdreJeu"""
  726. while self.fenetre.ui.inf_listeOrdreJeu.rowCount() > 0:
  727. self.fenetre.ui.inf_listeOrdreJeu.removeRow(0)
  728. index = 0
  729. for num in self.ordreJeu:
  730. self.fenetre.ui.inf_listeOrdreJeu.insertRow(int(index))
  731. self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 0, QTableWidgetItem(QString.fromUtf8(str(num))))
  732. icon = QIcon("img\\"+self.combattants[num].logo)
  733. item = QTableWidgetItem(icon,QString.fromUtf8(self.combattants[num].txtId()))
  734. self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 1, item)
  735. self.fenetre.ui.inf_listeOrdreJeu.setItem(int(index), 2, QTableWidgetItem(QString.fromUtf8(str(self.ordreJeu[num]))))
  736. index += 1
  737. self.fenetre.ui.inf_listeOrdreJeu.sizeHintForColumn(1)
  738. ## trierTable(self.fenetre.ui.infoOrdreJeu, 2, 0)
  739. def clicListOrdreJeu(self, ligne, col):
  740. """on a clique dans la liste d'ordre de jeu, le pion correspondant est selectionne et centre sur la carte"""
  741. numCombattant = int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8())
  742. self.fenetre.ui.cbt_vue.centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
  743. self.pionSaisir(numCombattant)
  744. def pionSuivant(self):
  745. """selection du pion suivant dans la liste d'ordre de jeu"""
  746. if self.numPionEnCours in self.combattants:
  747. suivant = self.ordreJeu[self.numPionEnCours] + 1
  748. else:
  749. suivant = 1
  750. if suivant > len(self.ordreJeu):
  751. self.tour += 1
  752. self.majAffichageTour()
  753. suivant = 1
  754. for num in self.ordreJeu:
  755. if self.ordreJeu[num] == suivant:
  756. numCombattant = num
  757. break
  758. for ligne in range(0, self.fenetre.ui.inf_listeOrdreJeu.rowCount()):
  759. item = self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0)
  760. item.setSelected(int(self.fenetre.ui.inf_listeOrdreJeu.item(ligne, 0).text().toUtf8()) == numCombattant)
  761. if int(item.text().toUtf8()) == numCombattant:
  762. self.fenetre.ui.inf_listeOrdreJeu.scrollToItem(item)
  763. self.fenetre.ui.cbt_vue.centerOn(self.cases[self.combattants[numCombattant].position].centreGraphique)
  764. self.pionSaisir(numCombattant)
  765. def afficheEcranGestionCombat(self):
  766. #*egc
  767. """affiche l'ecran de gestion du combat"""
  768. self.gestionCombat = EcranGestionCombat(self)
  769. self.gestionCombat.show()
  770. self.connect(self.fenetre, SIGNAL("majListesPions"), self.majListesPions)
  771. self.connect(self.gestionCombat, SIGNAL("majListesPions"), self.majListesPions)
  772. QApplication.processEvents()
  773. ## r = self.gestionCombat.exec_()
  774. def majOrdreJeu(self):
  775. """met a jour l'ordre de jeu des pions en fonction de l'attribut prevu par les regles s'il existe,
  776. ou en fonction de l'ordre de jeu parametre sinon"""
  777. attribut = regles.attributOrdreJeu()
  778. if attribut != None:
  779. dico = {}
  780. for numCombattant in self.combattants:
  781. dico[numCombattant] = int(self.combattants[numCombattant].listeAttributs[attribut])
  782. ordre = sorted(dico, key = dico.get, reverse=(regles.sensTriOrdreJeu() == 1))
  783. self.ordreJeu = {}
  784. for numCombattant in self.combattants:
  785. self.ordreJeu[numCombattant] = ordre.index(numCombattant) + 1
  786. self.majListeOrdreJeu()
  787. def pionDeplacerDansOrdreJeu(self, numCombattant, nouvellePosition):
  788. """deplace un pion dans le dictionnaire gerant l'ordre de jeu de maniere a assurer sa coherence
  789. nouvellePosition = 0 supprime le pion de la liste"""
  790. if numCombattant in self.ordreJeu:
  791. if nouvellePosition == 0:
  792. del self.ordreJeu[numCombattant]
  793. if len(self.ordreJeu) > 0:
  794. i = 0
  795. tmp = sorted(self.ordreJeu, key=self.ordreJeu.get)
  796. if numCombattant in tmp:
  797. tmp.remove(numCombattant)
  798. for num in tmp:
  799. i += 1
  800. if i == nouvellePosition:
  801. self.ordreJeu[numCombattant] = i
  802. i += 1
  803. self.ordreJeu[num] = i
  804. if i < nouvellePosition:
  805. self.ordreJeu[numCombattant] = i + 1
  806. elif nouvellePosition > 0:
  807. self.ordreJeu[numCombattant] = 1
  808. self.majOrdreJeu()
  809. def majListeAttributs(self):
  810. """met a jour la liste des attributs dans le panneau de combat"""
  811. self.fenetre.ui.pi_listeAttributs.setColumnWidth(0, 50)
  812. self.disconnect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  813. #on vide la liste
  814. while self.fenetre.ui.pi_listeAttributs.rowCount() > 0:
  815. self.fenetre.ui.pi_listeAttributs.removeRow(0)
  816. self.fenetre.ui.pi_listeAttributs.setVisible((self.pionSelectionne() != None))
  817. if self.pionSelectionne() != None:
  818. #creation des lignes de base
  819. lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans listeAttributCelluleModifiee
  820. for i in range(0, 10): #10 premieres colonnes reservees pour les infos de base
  821. self.fenetre.ui.pi_listeAttributs.insertRow(i)
  822. item = QTableWidgetItem()
  823. if i < len(lignesBase):
  824. item.setText(QString.fromUtf8(lignesBase[i]))
  825. item.setFlags(Qt.NoItemFlags)
  826. self.fenetre.ui.pi_listeAttributs.setItem(i, 0, item)
  827. self.fenetre.ui.pi_listeAttributs.setRowHidden(i, (i >= len(lignesBase)))
  828. #maj des donnees de base
  829. self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Nom"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().nom))))
  830. self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Etat"), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().etat))))
  831. self.fenetre.ui.pi_listeAttributs.setItem(lignesBase.index("Alt."), 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().z))))
  832. #attributs issus des regles utilisees
  833. ordre = regles.ordreAttributs()
  834. for elt in ordre:
  835. ligne = 10 + ordre.index(elt)
  836. self.fenetre.ui.pi_listeAttributs.insertRow(ligne)
  837. item = QTableWidgetItem(QString.fromUtf8(elt))
  838. item.setFlags(Qt.NoItemFlags)
  839. self.fenetre.ui.pi_listeAttributs.setItem(ligne, 0, item)
  840. self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[elt]))))
  841. self.connect(self.fenetre.ui.pi_listeAttributs, SIGNAL("cellChanged(int,int)"), self.listeAttributCelluleModifiee)
  842. def listeAttributCelluleModifiee(self, ligne, colonne):
  843. """une cellule de la liste des attributs a ete modifiee"""
  844. if colonne != 1:
  845. print("valeur non modifiable")
  846. else:
  847. #on verifie la validite de la donnee entree
  848. lignesBase = ["Nom","Etat","Alt."] #attention: modifier aussi dans majListeAttribut
  849. if ligne < len(lignesBase):
  850. pass
  851. elif ligne >= 10:
  852. attribut = regles.ordreAttributs()[(ligne - 10)]
  853. nouvelleVal = str(self.fenetre.ui.pi_listeAttributs.item(ligne, 1).text().toUtf8())
  854. valVerifiee = regles.listeControle()[attribut].controler(nouvelleVal)
  855. if valVerifiee != None:
  856. self.pionSelectionne().listeAttributs[attribut] = valVerifiee
  857. if attribut == regles.attributOrdreJeu():
  858. print("maj ordre (a implementer)")
  859. else:
  860. self.fenetre.ui.pi_listeAttributs.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().listeAttributs[attribut]))))
  861. def initListeAttaques(self):
  862. """met en forme et connecte la liste des attaques du pion"""
  863. self.fenetre.ui.pi_listeAttaques.setColumnWidth(0, 0)
  864. self.fenetre.ui.pi_listeAttaques.setColumnWidth(1, (0.3*self.fenetre.ui.pi_listeAttaques.width()))
  865. self.fenetre.ui.pi_listeAttaques.setColumnWidth(2, (0.7*self.fenetre.ui.pi_listeAttaques.width()))
  866. self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("itemSelectionChanged()"), self.majInfosAttaqueEC)
  867. self.connect(self.fenetre.ui.pi_listeAttaques, SIGNAL("cellClicked(int, int)"), self.listeAttaquesCelluleCliquee)
  868. self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
  869. self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(0, (0.49*self.fenetre.ui.pi_listeAttributsAttaqueEC.width()))
  870. self.fenetre.ui.pi_listeAttributsAttaqueEC.setColumnWidth(1, (0.5*self.fenetre.ui.pi_listeAttributsAttaqueEC.width()))
  871. def majListeAttaques(self):
  872. """met a jour la liste des attaques du pion dans le panneau de combat"""
  873. #on vide la liste
  874. while self.fenetre.ui.pi_listeAttaques.rowCount() > 0:
  875. self.fenetre.ui.pi_listeAttaques.removeRow(0)
  876. self.fenetre.ui.pi_listeAttaques.setVisible((self.pionSelectionne() != None))
  877. ## self.fenetre.ui.editerAttaques.setVisible((self.pionSelectionne() != None))
  878. self.fenetre.ui.pi_panneauAttaqueEC.setVisible((self.pionSelectionne() != None))
  879. i = 0
  880. if self.pionSelectionne() != None:
  881. for attaque in self.pionSelectionne().attaques:
  882. self.fenetre.ui.pi_listeAttaques.insertRow(i)
  883. self.fenetre.ui.pi_listeAttaques.setItem(i, 0, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques.index(attaque)))))
  884. icone = None
  885. if attaque.typ == "cac":
  886. icone = QIcon("img\\curseurEpee.png")
  887. if attaque.typ == "dist":
  888. icone = QIcon("img\\arc.png")
  889. if attaque.typ == "zone":
  890. icone = QIcon("img\\baguette.png")
  891. if icone != None:
  892. self.fenetre.ui.pi_listeAttaques.setItem(i, 1, QTableWidgetItem(icone, QString.fromUtf8("")))
  893. self.fenetre.ui.pi_listeAttaques.setItem(i, 2, QTableWidgetItem(QString.fromUtf8(attaque.nom)))
  894. self.majInfosAttaqueEC()
  895. def listeAttaquesCelluleCliquee(self, ligne, colonne):
  896. """on a clique sur une cellule de la liste des attaques"""
  897. numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
  898. if numAttaque >= 0:
  899. self.utiliserAttaque(numAttaque)
  900. def utiliserAttaque(self, numAttaque):
  901. """le pion selectionne utilise son attaque n"""
  902. if self.pionSelectionne() != None:
  903. if numAttaque < len(self.pionSelectionne().attaques):
  904. attaque = self.pionSelectionne().attaques[numAttaque]
  905. if attaque.typ == "cac":
  906. self.majModeCombat("combatAttaqueCaC")
  907. if attaque.typ == "dist":
  908. self.majModeCombat("combatAttaqueDist")
  909. if attaque.typ == "zone":
  910. self.modeParam["typeAttaqueZone"] = attaque.formeZone
  911. self.fenetre.ui.pi_rayonAttaqueZone.setValue(attaque.rayon)
  912. self.majModeCombat("combatAttaqueZone")
  913. def majInfosAttaqueEC(self):
  914. #*aec
  915. """met a jour les infos de l'attaque en cours (selectionnee)"""
  916. selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
  917. self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
  918. if self.pionSelectionne() != None and len(selection) > 0:
  919. ligne = selection[0].row()
  920. numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
  921. self.disconnect(self.fenetre.ui.pi_panneauAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
  922. #on vide la liste
  923. while self.fenetre.ui.pi_listeAttributsAttaqueEC.rowCount() > 0:
  924. self.fenetre.ui.pi_listeAttributsAttaqueEC.removeRow(0)
  925. self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(0)
  926. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 0, QTableWidgetItem(QString.fromUtf8("numAtt")))
  927. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(0, 1, QTableWidgetItem(QString.fromUtf8(str(numAttaque))))
  928. self.fenetre.ui.pi_listeAttributsAttaqueEC.setRowHidden(0, True)
  929. #attributs issus des regles utilisees
  930. ordre = regles.ordreAttributsAttaques()
  931. for elt in ordre:
  932. ligne = 1 + ordre.index(elt)
  933. self.fenetre.ui.pi_listeAttributsAttaqueEC.insertRow(ligne)
  934. item = QTableWidgetItem(QString.fromUtf8(elt))
  935. item.setFlags(Qt.NoItemFlags)
  936. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 0, item)
  937. self.fenetre.ui.pi_listeAttributsAttaqueEC.setItem(ligne, 1, QTableWidgetItem(QString.fromUtf8(str(self.pionSelectionne().attaques[numAttaque].attributs[elt]))))
  938. self.connect(self.fenetre.ui.pi_listeAttributsAttaqueEC, SIGNAL("cellChanged(int,int)"), self.attaqueECCelluleModifiee)
  939. #maj des notes
  940. self.disconnect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
  941. self.fenetre.ui.pi_notesAttaqueEC.setText(QString.fromUtf8(self.pionSelectionne().attaques[numAttaque].notes))
  942. self.connect(self.fenetre.ui.pi_notesAttaqueEC, SIGNAL("textChanged()"), self.majNotesAttaqueEC)
  943. def attaqueECCelluleModifiee(self, ligne, colonne):
  944. """une cellule de la liste d'attributs de l'attaque en cours a ete modifiee"""
  945. pass
  946. def majNotesAttaqueEC(self):
  947. """met a jour les notes de l'attaque en cours (selectionnee)"""
  948. selection = self.fenetre.ui.pi_listeAttaques.selectedItems()
  949. self.fenetre.ui.pi_panneauAttaqueEC.setVisible(self.pionSelectionne() != None and len(selection) > 0)
  950. if self.pionSelectionne() != None and len(selection) > 0:
  951. ligne = selection[0].row()
  952. numAttaque = int(str(self.fenetre.ui.pi_listeAttaques.item(ligne, 0).text().toUtf8()))
  953. self.pionSelectionne().attaques[numAttaque].notes = str(self.fenetre.ui.pi_notesAttaqueEC.toPlainText().toUtf8())
  954. def afficheEcranEditionAttaques(self):
  955. """affiche l'ecran d'edition/creation d'attaques"""
  956. if self.pionSelectionne() != None:
  957. self.editionAttaques = QDialog()
  958. frame = EcranEditionAttaques(self.pionSelectionne())
  959. frame.setParent(self.editionAttaques)
  960. self.editionAttaques.setAttribute(Qt.WA_DeleteOnClose)
  961. r = self.editionAttaques.exec_()
  962. del self.editionAttaques
  963. self.majListeAttaques()
  964. def majNotesCombattant(self):
  965. """les notes du pion ont ete mises a jour"""
  966. if self.pionSelectionne() != None:
  967. self.pionSelectionne().notes = str(self.fenetre.ui.pi_notes.toPlainText().toUtf8())
  968. else:
  969. pass
  970. def afficherNotesCombattant(self):
  971. """affiche les notes du pion selectionne dans le QTextEdit dedie"""
  972. self.fenetre.ui.pi_notes.setVisible((self.pionSelectionne() != None))
  973. if self.pionSelectionne() != None:
  974. self.fenetre.ui.pi_notes.setText(QString.fromUtf8(self.pionSelectionne().notes))
  975. ###############
  976. ############### fonctions de calcul ################
  977. def zone(self, origine, distance, z=0, conditionFranchissable = False, conditionVisible = False):
  978. """renvoie un dictionnaire representant la liste des coordonnees des cases comprises dans la zone
  979. la zone en question est la liste des cases situees a une distance d des coordonnees d'origine
  980. z = 0 -> hauteur z de l'origine par rapport a l'altitude de la case
  981. conditionFranchissable = Vrai -> les cases infranchissables ne sont pas prises en compte
  982. conditionVisible = Vrai -> les cases bloquant la visibilite ne sont pas prises en compte
  983. [cf methode A* (A-star)]"""
  984. aVerifier = []
  985. aVerifier2 = []
  986. resultat = {}
  987. k = 0
  988. #on part de la premiere case, puis on itere a partir de chaque nouveau depart
  989. if origine in self.cases:
  990. aVerifier.append(origine)
  991. while k <= distance:
  992. for depart in aVerifier:
  993. for coord in self.cases[depart].voisins:
  994. if not coord in aVerifier and not coord in aVerifier2 and not coord in resultat:
  995. if conditionFranchissable and not conditionVisible:
  996. if self.cases[coord].estFranchissable(z):
  997. aVerifier2.append(coord)
  998. elif not conditionFranchissable and conditionVisible:
  999. if self.cases[coord].terrain.visibilite:
  1000. aVerifier2.append(coord)
  1001. elif conditionFranchissable and conditionVisible:
  1002. if self.cases[coord].estFranchissable(z) and self.cases[coord].terrain.visibilite:
  1003. aVerifier2.append(coord)
  1004. else:
  1005. aVerifier2.append(coord)
  1006. for elt in aVerifier:
  1007. resultat[elt] = k
  1008. aVerifier = aVerifier2
  1009. aVerifier2 = []
  1010. k += 1
  1011. return resultat
  1012. def coordonneesValides(self, coord):
  1013. """les coordonnees entrees en parametre sont elles celles d'une case du plateau"""
  1014. return (coord[0] >= 0 and coord[1] >= 0 and coord[0] < self.nbCasesX and coord[1] < self.nbCasesY)
  1015. def polygoneAgglo(self, listeCases):
  1016. """renvoie un polygone contruit par agglomeration des polygones des cases de la liste
  1017. les cases doivent etre adjacentes (cases hexagonales ou carrees)"""
  1018. pointsPolygone = []
  1019. segments = []
  1020. case = Case(self)
  1021. #on verifie que toutes les cases sont adjacentes les unes aux autres
  1022. valide = True
  1023. if len(listeCases) > 1:
  1024. for coord in listeCases:
  1025. if not len(set(listeCases).intersection(self.lstCoordAdjacentes(coord[0], coord[1]))) > 0: valide = False
  1026. if not len(listeCases) > 0:
  1027. valide = False
  1028. if valide:
  1029. #on parcourt les faces des polygones des cases, et on ne garde que ceux qui n'ont pas de case 'en face'
  1030. for coord in listeCases:
  1031. polygone = case.polygone(coord[0], coord[1])
  1032. voisins = self.lstCoordAdjacentes(coord[0], coord[1])
  1033. for i in range(0, len(voisins)):
  1034. if not voisins[i] in listeCases:
  1035. j = i+1
  1036. if j > len(voisins) - 1:
  1037. j = 0
  1038. segments.append(QLineF(polygone[i], polygone[j]))
  1039. #on 'accroche' les segments les uns aux autres, dans l'ordre
  1040. segments2 = [segments[0]]
  1041. for segment2 in segments2:
  1042. for segment in segments:
  1043. if not QLineF(segment.p1(), segment.p2()) in segments2 and not QLineF(segment.p2(), segment.p1()) in segments2:
  1044. if sqrt((segment.p1().x()-segment2.p2().x())**2+(segment.p1().y()-segment2.p2().y())**2) < 1:
  1045. segments2.append(QLineF(segment.p1(), segment.p2()))
  1046. elif sqrt((segment.p2().x()-segment2.p2().x())**2+(segment.p2().y()-segment2.p2().y())**2) < 1:
  1047. segments2.append(QLineF(segment.p2(), segment.p1()))
  1048. pointsPolygone = []
  1049. premierPoint = segments2[0].p1()
  1050. pointsPolygone.append(premierPoint)
  1051. for segment in segments2:
  1052. pointSuivant = segment.p2()
  1053. if pointSuivant != premierPoint:
  1054. pointsPolygone.append(pointSuivant)
  1055. #creation du polygone
  1056. polygone = QPolygonF()
  1057. for point in pointsPolygone:
  1058. polygone.append(point)
  1059. else:
  1060. polygone = None
  1061. return polygone
  1062. def lstCoordAdjacentes(self, x, y):
  1063. """renvoie la liste des coordonnees adjacentes, sans condition d'existence sur le plateau
  1064. attention: l'ordre est important"""
  1065. if self.formeCases == "H":
  1066. voisins = [(x, y-1), (x+1, y-0.5), (x+1, y+0.5), (x, y+1), (x-1, y+0.5), (x-1, y-0.5)]
  1067. else:
  1068. voisins = [(x, y-1), (x+1, y), (x, y+1), (x-1, y)]
  1069. return voisins
  1070. def coordCentreListeCases(self, listeCases):
  1071. """renvoie les coordonnees centrales d'une liste de cases"""
  1072. retour = None
  1073. if len(listeCases) > 0:
  1074. listeTriee = sorted(listeCases)
  1075. posMilieu = int(len(listeCases)/2)
  1076. retour = listeTriee[posMilieu]
  1077. return retour
  1078. def coordonneesAuPoint(self, point):
  1079. """renvoie les coordonnees de la case situee au QPointF entre en parametre"""
  1080. coord = None
  1081. if point != None:
  1082. lstObjets = self.fenetre.ui.cbt_vue.scene().items(point)
  1083. for objet in lstObjets:
  1084. if objet:
  1085. if objet.__class__.__name__ == "Case":
  1086. coord = (objet.x, objet.y)
  1087. break
  1088. return coord
  1089. def casesSousForme(self, forme, plein = True, epaisseur = 0):
  1090. """renvoie la liste des cases en collision avec un QGraphicsItem en parametre
  1091. plein = False: pas le contenu de la forme
  1092. epaisseur = renvoie aussi les cases voisines jusqu'a la distance demandee"""
  1093. tmp = []
  1094. listeCases = []
  1095. point1 = None
  1096. point2 = None
  1097. #point 1 et 2
  1098. if forme.__class__.__name__ == "QGraphicsLineItem":
  1099. point1 = forme.line().p1()
  1100. point2 = forme.line().p2()
  1101. elif forme.__class__.__name__ == "QGraphicsRectItem" or forme.__class__.__name__ == "QGraphicsEllipseItem":
  1102. point1 = forme.rect().topLeft()
  1103. point2 = forme.rect().bottomRight()
  1104. else:
  1105. point1 = forme.boundingRect().topLeft()
  1106. point2 = forme.boundingRect().bottomRight()
  1107. #preselection des cases (meilleures perf)
  1108. if point1 != None and point2 != None and point1 != point2:
  1109. preSelection = self.preSelectionCollision(point1, point2)
  1110. else:
  1111. preSelection = []
  1112. for coord in self.cases:
  1113. preSelection.append(coord)
  1114. #on liste les cases en collision avec la forme
  1115. for coord in preSelection:
  1116. if self.cases[coord].collidesWithItem(forme, Qt.IntersectsItemShape):
  1117. if plein:
  1118. tmp.append(coord)
  1119. else:
  1120. contenu = True
  1121. for i in range(0,len(self.cases[coord].polygon())):
  1122. if not forme.contains(self.cases[coord].polygon().at(i)):
  1123. contenu = False
  1124. break
  1125. if contenu == False:
  1126. tmp.append(coord)
  1127. #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
  1128. if not plein and epaisseur > 0:
  1129. for coord in tmp:
  1130. zone = self.zone(coord, epaisseur)
  1131. for coord2 in zone:
  1132. if not coord2 in listeCases:
  1133. listeCases.append(coord2)
  1134. else:
  1135. listeCases = tmp
  1136. #si la liste est vide, on ajoute l'origine de la forme
  1137. if len(listeCases) == 0:
  1138. listeCases = [self.coordonneesAuPoint(point1)]
  1139. return listeCases
  1140. def preSelectionCollision(self, point1, point2):
  1141. """renvoie une liste des cases qui peuvent etre concernees par une collision avec
  1142. un graphicsItem (pour des raisons de performance)"""
  1143. preSelection = []
  1144. coord1 = self.coordonneesAuPoint(point1)
  1145. coord2 = self.coordonneesAuPoint(point2)
  1146. if coord1 != None and coord2 != None:
  1147. minX = min(coord1[0], coord2[0]) - 1
  1148. maxX = max(coord1[0], coord2[0]) + 1
  1149. minY = min(coord1[1], coord2[1]) - 1
  1150. maxY = max(coord1[1], coord2[1]) + 1
  1151. for coord in self.cases:
  1152. if coord[0] >= minX and coord[0] <= maxX and coord[1] >= minY and coord[1] <= maxY :
  1153. preSelection.append(coord)
  1154. else:
  1155. preSelection = self.cases
  1156. return preSelection
  1157. def majLigneMireAttaqueDist(self, coordCible = None):
  1158. """met a jour la ligne de mire representant l'attaque a distance"""
  1159. if self.modeParam["cibleAttaqueDist"] != None and self.modeParam["cibleAttaqueDist"] != coordCible:
  1160. self.cases[self.modeParam["cibleAttaqueDist"]].majEstCibleCurseur(False)
  1161. if self.modeParam["pionCibleAttaqueDist"] != None:
  1162. self.modeParam["pionCibleAttaqueDist"].estCibleAttaque(False)
  1163. if coordCible != None and self.pionSelectionne() != None and self.modeCombat == "combatAttaqueDist":
  1164. if coordCible == None:
  1165. coordCible = pion.position
  1166. if coordCible != self.modeParam["cibleAttaqueDist"]:
  1167. if self.modeParam["ligneAttaqueDist"] == None:
  1168. self.modeParam["ligneAttaqueDist"] = QGraphicsLineItem()
  1169. self.modeParam["ligneAttaqueDist"].setZValue(100)
  1170. pinceau = QPen()
  1171. pinceau.setWidth(6)
  1172. self.modeParam["ligneAttaqueDist"].setPen(pinceau)
  1173. self.modeParam["ligneAttaqueDist"].prepareGeometryChange()
  1174. self.addItem(self.modeParam["ligneAttaqueDist"])
  1175. z = 0
  1176. pionSurCase = self.cases[coordCible].pionOccupant()
  1177. if pionSurCase != None:
  1178. z = pionSurCase.z
  1179. cibleValide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, coordCible, z)
  1180. if pionSurCase != None:
  1181. pionSurCase.estCibleAttaque(True, cibleValide)
  1182. self.modeParam["pionCibleAttaqueDist"] = pionSurCase
  1183. else:
  1184. self.cases[coordCible].majEstCibleCurseur(True, cibleValide)
  1185. self.modeParam["cibleAttaqueDist"] = coordCible
  1186. point1 = self.cases[self.pionSelectionne().position].centreGraphique
  1187. point2 = self.cases[coordCible].centreGraphique
  1188. ligne = QLineF(point1, point2)
  1189. self.modeParam["ligneAttaqueDist"].setLine(ligne)
  1190. else:
  1191. if self.modeParam["ligneAttaqueDist"] != None:
  1192. self.modeParam["ligneAttaqueDist"].prepareGeometryChange()
  1193. self.removeItem(self.modeParam["ligneAttaqueDist"])
  1194. self.modeParam["ligneAttaqueDist"] = None
  1195. self.modeParam["cibleAttaqueDist"] = None
  1196. def estCibleAttaqueDistValide(self, coordOrigine, coordCible, zPion = 0):
  1197. """la case cible est elle valide pour une attaque a distance depuis la position et hauteur
  1198. du pion selectionne? on compare pour ce faire les altitudes des cases sur la ligne de mire"""
  1199. casesLigneMire = []
  1200. #on preselectionne les cases concernees
  1201. preSelection = self.preSelectionCollision(self.cases[coordOrigine].centreGraphique, self.cases[coordCible].centreGraphique)
  1202. if coordOrigine in preSelection:
  1203. preSelection.remove(coordOrigine)
  1204. if coordCible in preSelection:
  1205. preSelection.remove(coordCible)
  1206. for coord in preSelection:
  1207. ligne = QLineF(self.cases[coordOrigine].centreGraphique, self.cases[coordCible].centreGraphique)
  1208. ligneGraphique = QGraphicsLineItem(ligne)
  1209. ligneGraphique.prepareGeometryChange()
  1210. self.addItem(ligneGraphique)
  1211. if self.cases[coord].collidesWithItem(ligneGraphique, Qt.IntersectsItemShape):
  1212. casesLigneMire.append(coord)
  1213. self.removeItem(ligneGraphique)
  1214. del ligneGraphique
  1215. #on trie les cases par distance au point d'origine (de la plus proche a la plus eloignee)
  1216. casesLigneMireDistance = {} #distance: coord
  1217. for coord in casesLigneMire:
  1218. distance = sqrt((coordOrigine[0] - coord[0])**2 + (coordOrigine[1] - coord[1])**2)
  1219. casesLigneMireDistance[coord] = distance
  1220. #on compare enfin les altitudes de chaque case en fonction de la distance
  1221. zOrigine = self.cases[coordOrigine].altitude + self.pionSelectionne().z + self.pionSelectionne().hauteur
  1222. zCible = self.cases[coordCible].altitude + zPion
  1223. distanceTot = sqrt((coordCible[0] - coordOrigine[0])**2 + (coordCible[1] - coordOrigine[1])**2)
  1224. valide = True
  1225. for coord in casesLigneMireDistance:
  1226. if self.cases[coord].terrain.visibilite == False:
  1227. valide = False
  1228. break
  1229. else:
  1230. if zOrigine >= zCible:
  1231. z = (zOrigine - zCible) * (casesLigneMireDistance[coord] / distanceTot)
  1232. else:
  1233. z = (zCible - zOrigine) * ((distanceTot - casesLigneMireDistance[coord]) / distanceTot)
  1234. if self.cases[coord].estOccupee(int(z)):
  1235. if self.modeParam["pionCibleAttaqueDist"] != None:
  1236. if self.cases[coord].estOccupeePar(int(z)) != self.modeParam["pionCibleAttaqueDist"]:
  1237. valide = False
  1238. else:
  1239. valide = False
  1240. break
  1241. return valide
  1242. def validerAttaqueDist(self):
  1243. """on essaie de valider une attaque a distance vers un pion ou une case"""
  1244. if self.modeParam["pionCibleAttaqueDist"] != None:
  1245. msg = "{} attaque a distance le pion {}".format(self.pionSelectionne().txtId(),
  1246. self.modeParam["pionCibleAttaqueDist"].txtId())
  1247. valide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, self.modeParam["cibleAttaqueDist"], self.modeParam["pionCibleAttaqueDist"].z)
  1248. else:
  1249. msg = "{} attaque a distance la case {}".format(self.pionSelectionne().txtId(),
  1250. self.modeParam["cibleAttaqueDist"])
  1251. valide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, self.modeParam["cibleAttaqueDist"])
  1252. if not valide:
  1253. msg += " [INVALIDE]"
  1254. print(msg)
  1255. self.majModeCombat("aucun")
  1256. def rectEllipseCirculaire(self, centre, rayon):
  1257. """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
  1258. attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
  1259. verticalement le nombre de cases demandees"""
  1260. rect = QRectF()
  1261. if rayon > 0:
  1262. p1 = QPointF((centre.x() - (rayon*self.hCase)), (centre.y() - (rayon*self.hCase)))
  1263. p2 = QPointF((centre.x() + (rayon*self.hCase)), (centre.y() + (rayon*self.hCase)))
  1264. rect.setTopLeft(p1)
  1265. rect.setBottomRight(p2)
  1266. else:
  1267. rect = None
  1268. return rect
  1269. def polygoneCone(self, point1, point2):
  1270. """renvoie le polygone du cone defini par les deux points (origine, distance)"""
  1271. ligne1 = QLineF(point1, point2)
  1272. longueur = ligne1.length()
  1273. ligne1.setAngle(ligne1.angle() + 22.5)
  1274. ligne1.setLength(1.1547*longueur)
  1275. ligne2 = QLineF(point1, point2)
  1276. ligne2.setAngle(ligne2.angle() - 22.5)
  1277. ligne2.setLength(1.1547*longueur)
  1278. polygone = QPolygonF()
  1279. polygone.append(point1)
  1280. polygone.append(ligne1.p2())
  1281. polygone.append(ligne2.p2())
  1282. return polygone
  1283. def majFormeAttaqueZone(self):
  1284. """cree la forme de l'attaque de zone"""
  1285. for coord in self.modeParam["listeCasesAttaqueZone"]:
  1286. self.cases[coord].majEstCibleAttaque(False)
  1287. for numCombattant in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]):
  1288. self.combattants[numCombattant].estCibleAttaque(False)
  1289. if self.modeCombat == "combatAttaqueZone" and self.pionSelectionne() != None:
  1290. if self.modeParam["typeAttaqueZone"] == "ligne":
  1291. if self.modeParam["formeAttaqueZone"] == None:
  1292. self.modeParam["origineAttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique
  1293. self.modeParam["point2AttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique
  1294. self.modeParam["formeAttaqueZone"] = QGraphicsLineItem()
  1295. self.modeParam["formeAttaqueZone"].setPen(QPen(QColor("black")))
  1296. self.modeParam["formeAttaqueZone"].prepareGeometryChange()
  1297. self.addItem(self.modeParam["formeAttaqueZone"])
  1298. if self.modeParam["origineAttaqueZone"] != self.modeParam["point2AttaqueZone"]:
  1299. ligne = QLineF(self.modeParam["origineAttaqueZone"], self.modeParam["point2AttaqueZone"])
  1300. self.modeParam["formeAttaqueZone"].setLine(ligne)
  1301. self.modeParam["listeCasesAttaqueZone"] = []
  1302. lst = self.casesSousForme(self.modeParam["formeAttaqueZone"],False)
  1303. for coord in lst:
  1304. self.modeParam["listeCasesAttaqueZone"].append(coord)
  1305. #on retire la case du pion selectionne si besoin:
  1306. if self.pionSelectionne().position in self.modeParam["listeCasesAttaqueZone"]:
  1307. self.modeParam["listeCasesAttaqueZone"].remove(self.pionSelectionne().position)
  1308. elif self.modeParam["typeAttaqueZone"] == "disque":
  1309. if self.modeParam["ligneMireAttaqueZone"] == None:
  1310. self.modeParam["origineAttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique
  1311. self.modeParam["point2AttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique
  1312. self.modeParam["ligneMireAttaqueZone"] = QGraphicsLineItem()
  1313. self.modeParam["ligneMireAttaqueZone"].setPen(QPen(QColor("black")))
  1314. self.modeParam["ligneMireAttaqueZone"].prepareGeometryChange()
  1315. self.addItem(self.modeParam["ligneMireAttaqueZone"])
  1316. if self.modeParam["origineAttaqueZone"] != self.modeParam["point2AttaqueZone"]:
  1317. ligne = QLineF(self.modeParam["origineAttaqueZone"], self.modeParam["point2AttaqueZone"])
  1318. self.modeParam["ligneMireAttaqueZone"].setLine(ligne)
  1319. coordCible = self.coordonneesAuPoint(self.modeParam["point2AttaqueZone"])
  1320. cibleValide = self.estCibleAttaqueDistValide(self.pionSelectionne().position, coordCible)
  1321. if cibleValide:
  1322. rayon = self.fenetre.ui.pi_rayonAttaqueZone.value()
  1323. if self.modeParam["formeAttaqueZone"] == None:
  1324. self.modeParam["formeAttaqueZone"] = QGraphicsEllipseItem()
  1325. self.modeParam["formeAttaqueZone"].setPen(QPen(QColor("black")))
  1326. self.modeParam["formeAttaqueZone"].prepareGeometryChange()
  1327. self.addItem(self.modeParam["formeAttaqueZone"])
  1328. rect = self.rectEllipseCirculaire(self.modeParam["point2AttaqueZone"], rayon)
  1329. self.modeParam["listeCasesAttaqueZone"] = []
  1330. if rect != None and rect.bottomRight() != rect.topLeft():
  1331. self.modeParam["formeAttaqueZone"].setRect(rect)
  1332. lst = self.zone(coordCible, rayon, 0) #zone bcp plus rapide que casesSousforme
  1333. self.modeParam["listeCasesAttaqueZone"] = lst
  1334. else:
  1335. self.cases[coordCible].majEstCibleCurseur(True, False)
  1336. self.modeParam["listeCasesAttaqueZone"] = []
  1337. if self.modeParam["formeAttaqueZone"] != None:
  1338. self.modeParam["formeAttaqueZone"].setVisible(cibleValide == True and rect != None)
  1339. elif self.modeParam["typeAttaqueZone"] == "cone":
  1340. if self.modeParam["formeAttaqueZone"] == None:
  1341. self.modeParam["origineAttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique
  1342. self.modeParam["point2AttaqueZone"] = self.cases[self.pionSelectionne().position].centreGraphique
  1343. self.modeParam["formeAttaqueZone"] = QGraphicsPolygonItem()
  1344. self.modeParam["formeAttaqueZone"].setPen(QPen(QColor("black")))
  1345. self.modeParam["formeAttaqueZone"].prepareGeometryChange()
  1346. self.addItem(self.modeParam["formeAttaqueZone"])
  1347. if self.modeParam["origineAttaqueZone"] != self.modeParam["point2AttaqueZone"]:
  1348. cone = self.polygoneCone(self.modeParam["origineAttaqueZone"], self.modeParam["point2AttaqueZone"])
  1349. self.modeParam["formeAttaqueZone"].setPolygon(cone)
  1350. lst = self.casesSousForme(self.modeParam["formeAttaqueZone"], True, True)
  1351. self.modeParam["listeCasesAttaqueZone"] = []
  1352. for coord in lst:
  1353. if coord != self.pionSelectionne().position:
  1354. self.modeParam["listeCasesAttaqueZone"].append(coord)
  1355. for coord in self.modeParam["listeCasesAttaqueZone"]:
  1356. self.cases[coord].majEstCibleAttaque(True)
  1357. for numCombattant in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]):
  1358. self.combattants[numCombattant].estCibleAttaque(True)
  1359. def validerAttaqueZone(self):
  1360. """l'attaque de zone est validee"""
  1361. if self.modeActif_old == "pionSelectionne" and self.modeCombat == "combatAttaqueZone":
  1362. for numCombattant in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]):
  1363. print("{} a lance une attaque de zone sur {}".format(self.pionSelectionne().nom, self.pionSelectionne().numero , \
  1364. self.combattants[numCombattant].nom, self.combattants[numCombattant].numero))
  1365. self.majModeCombat("aucun")
  1366. def reinitAttaqueZone(self):
  1367. if self.modeParam["formeAttaqueZone"] != None:
  1368. self.modeParam["formeAttaqueZone"].prepareGeometryChange()
  1369. self.removeItem(self.modeParam["formeAttaqueZone"])
  1370. self.modeParam["formeAttaqueZone"] = None
  1371. if self.modeParam["ligneMireAttaqueZone"] != None:
  1372. self.modeParam["ligneMireAttaqueZone"].prepareGeometryChange()
  1373. self.removeItem(self.modeParam["ligneMireAttaqueZone"])
  1374. self.modeParam["ligneMireAttaqueZone"] = None
  1375. if self.modeParam["point2AttaqueZone"] != None:
  1376. self.cases[self.coordonneesAuPoint(self.modeParam["point2AttaqueZone"])].majEstCibleCurseur(False)
  1377. for coord in self.modeParam["listeCasesAttaqueZone"]:
  1378. self.cases[coord].majEstCibleAttaque(False)
  1379. for numCombattant in self.pionsSurListeCase(self.modeParam["listeCasesAttaqueZone"]):
  1380. self.combattants[numCombattant].estCibleAttaque(False)
  1381. def pionSurCase(self, coord):
  1382. """renvoie le pion present sur la case, none sinon"""
  1383. retour = None
  1384. for num in self.combattants:
  1385. if self.combattants[num].position == coord:
  1386. retour = num
  1387. return retour
  1388. def pionsSurListeCase(self, listeCases):
  1389. """renvoie la liste des pions presents sur la liste de cases"""
  1390. retour = []
  1391. for coord in listeCases:
  1392. pion = self.cases[coord].pionOccupant()
  1393. if pion != None and not pion.numero in retour:
  1394. retour.append(pion.numero)
  1395. return retour
  1396. def majZonePlacement(self, listeCases):
  1397. """met a jour la forme et l'affichage de la zone de placement initale des joueurs"""
  1398. if len(listeCases) > 0:
  1399. if self.polygoneZonePlacement == None:
  1400. self.polygoneZonePlacement = QGraphicsPolygonItem(scene=self)
  1401. self.polygoneZonePlacement.setZValue(0)
  1402. qCouleurFond = QColor("white")
  1403. qCouleurFond.setAlpha(50)
  1404. self.polygoneZonePlacement.setBrush(qCouleurFond)
  1405. pinceau = QPen(QColor("orange"))
  1406. pinceau.setWidth(20)
  1407. self.polygoneZonePlacement.setPen(pinceau)
  1408. self.polygoneZonePlacement.setAcceptedMouseButtons(Qt.NoButton)
  1409. self.polygoneZonePlacement.setAcceptHoverEvents(False)
  1410. self.addItem(self.polygoneZonePlacement)
  1411. listeCases2 = []
  1412. for coord in listeCases:
  1413. if self.cases[coord].estFranchissable():
  1414. listeCases2.append(coord)
  1415. self.polygoneZonePlacement.setPolygon(self.polygoneAgglo(listeCases2))
  1416. self.listeCasesZonePlacement = listeCases
  1417. def materialiserPions(self,actif):
  1418. """avtive/desactive la reception par les pions (autres que le pion selectionne) des hover events"""
  1419. for numCombattant in self.combattants:
  1420. if numCombattant != self.modeParam["numPionSelectionne"]:
  1421. self.combattants[numCombattant].setAcceptsHoverEvents(actif)
  1422. self.combattants[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
  1423. for numCombattant in self.decors:
  1424. self.decors[numCombattant].setAcceptsHoverEvents(actif)
  1425. self.decors[numCombattant].polygoneGraphique.setAcceptsHoverEvents(actif)
  1426. #######################
  1427. ######## interaction avec les cases, decors et pions #############
  1428. def pionSelectionne(self):
  1429. """renvoie le pion actuellement selectionne"""
  1430. if self.modeParam["numPionSelectionne"] in self.combattants:
  1431. retour = self.combattants[self.modeParam["numPionSelectionne"]]
  1432. else:
  1433. retour = None
  1434. return retour
  1435. def pionDecorSelectionne(self):
  1436. """renvoie le pion actuellement selectionne"""
  1437. if self.modeParam["numPionSelectionne"] in self.decors:
  1438. retour = self.decors[self.modeParam["numPionSelectionne"]]
  1439. else:
  1440. retour = None
  1441. return retour
  1442. def caseCliquee(self, x, y):
  1443. """on a clique sur la case (clic gauche)"""
  1444. coord = (x, y)
  1445. self.modeActif.clic_case(coord)
  1446. accepte = False
  1447. if coord in self.cases:
  1448. case = self.cases[coord]
  1449. if self.modeActif_old == "pionDecorSelectionne":
  1450. if coord != self.pionDecorSelectionne().position:
  1451. self.pionDeposer(coord)
  1452. accepte = True
  1453. elif self.modeActif_old == "pionSelectionne":
  1454. if self.modeCombat == "combatDeplacement":
  1455. if self.pionSelectionne() != None:
  1456. if coord != self.pionSelectionne().position:
  1457. self.pionDeposer(coord)
  1458. accepte = True
  1459. elif self.modeCombat == "combatAttaqueCaC":
  1460. if self.modeParam["cibleAttaqueCaC"] in self.modeParam["zoneAttaqueCaC"]:
  1461. print("{} attaque {} au corps a corps".format(self.pionSelectionne().nom, self.modeParam["cibleAttaqueCaC"]))
  1462. self.majMode("pionSelectionne", None)
  1463. accepte = True
  1464. else:
  1465. print("cette case est invalide pour une corps a corps")
  1466. accepte = True
  1467. elif self.modeCombat == "combatAttaqueDist":
  1468. self.validerAttaqueDist()
  1469. accepte = True
  1470. elif self.modeCombat == "combatAttaqueZone":
  1471. self.validerAttaqueZone()
  1472. accepte = True
  1473. elif self.modeActif_old == "pionCreation":
  1474. self.pionCreer(coord)
  1475. accepte = True
  1476. elif self.modeActif_old == "pionDecorCreation":
  1477. self.pionDecorCreer(coord)
  1478. accepte = True
  1479. return accepte
  1480. def caseSurvolClicEnfonce(self, coord):
  1481. """une case est survolee par le curseur (le clic gauche est enfonce)"""
  1482. self.modeActif.survolClic_case(coord)
  1483. def caseSurvol(self, x, y):
  1484. """une case est survole par le curseur, on affiche ses informations dans la zone prevue"""
  1485. self.modeActif.survol_case((x,y))
  1486. case = self.cases[(x, y)]
  1487. self.majInfosCase(case)
  1488. if (self.modeActif_old == "pionSelectionne" and self.modeCombat == "combatDeplacement") or self.modeActif_old == "pionCreation"\
  1489. or self.modeActif_old == "pionDecorSelectionne" or self.modeActif_old == "pionDecorCreation":
  1490. self.proj.majCoord((x, y))
  1491. elif self.modeActif_old == "pionSelectionne" and self.modeCombat == "combatAttaqueDist" and self.modeParam["cibleAttaqueDist"] != (case.x, case.y):
  1492. self.majLigneMireAttaqueDist((case.x,case.y))
  1493. elif self.modeActif_old == "pionSelectionne" and self.pionSelectionne() != None and self.modeCombat == "combatAttaqueZone":
  1494. if case.centreGraphique != self.modeParam["point2AttaqueZone"]:
  1495. self.cases[self.coordonneesAuPoint(self.modeParam["point2AttaqueZone"])].majEstCibleCurseur(False)
  1496. self.modeParam["point2AttaqueZone"] = case.centreGraphique
  1497. self.majFormeAttaqueZone()
  1498. def afficherListeCases(self, listeCases, actif):
  1499. """met ou non en evidence les cases selectionnees"""
  1500. for coord in listeCases:
  1501. self.cases[coord].majEstCibleCurseur(actif)
  1502. def majInfosCase(self, case=None):
  1503. """met a jour les informations d'un pion dans la zone prevue"""
  1504. if case != None:
  1505. if len(case.terrain.nom) > 0:
  1506. self.fenetre.ui.inf_caseTerrain.setText(QString.fromUtf8(case.terrain.nom))
  1507. else:
  1508. self.fenetre.ui.inf_caseTerrain.setText(QString.fromUtf8("Case"))
  1509. self.fenetre.ui.inf_caseCoord.setText(QString.fromUtf8("X: {} Y: {}".format(case.x, case.y)))
  1510. self.fenetre.ui.inf_caseAltitude.setText(QString.fromUtf8("Alt.: {}".format(case.altitude)))
  1511. if case.effetActif != "":
  1512. pix = QPixmap(QString.fromUtf8("img\\"+case.imgEffet[case.effetActif]))
  1513. pix = pix.scaled(21, 21, Qt.KeepAspectRatio, Qt.SmoothTransformation)
  1514. self.fenetre.ui.inf_caseEffet.setPixmap(pix)
  1515. else:
  1516. self.fenetre.ui.inf_caseEffet.clear()
  1517. self.fenetre.ui.inf_boiteCase.setVisible(True)
  1518. else:
  1519. self.fenetre.ui.inf_boiteCase.setVisible(False)
  1520. def pionClique(self, numCombattant):
  1521. """on a clique sur ce pion"""
  1522. accepte = False
  1523. if self.pionSelectionne() != None and self.modeCombat == "combatAttaqueDist":
  1524. self.validerAttaqueDist()
  1525. accepte = True
  1526. elif self.modeActif_old == "standard" and self.pionSelectionne() == None:
  1527. self.pionSaisir(numCombattant)
  1528. accepte = True
  1529. return accepte
  1530. def pionSurvol(self, numCombattant):
  1531. """le pion est survole par le curseur, on affiche ses informations dans la zone prevue"""
  1532. if numCombattant in self.combattants:
  1533. pion = self.combattants[numCombattant]
  1534. else:
  1535. pion = None
  1536. self.majInfosPion(pion)
  1537. if self.pionSelectionne() != None and self.modeCombat == "combatAttaqueCaC":
  1538. self.majProjectionAttaqueCaC(pion)
  1539. pass
  1540. if numCombattant in self.combattants:
  1541. ## case = self.cases[self.combattants[numCombattant].position]
  1542. self.caseSurvol(self.combattants[numCombattant].position[0], self.combattants[numCombattant].position[1])
  1543. def pionDoubleClic(self, numCombattant):
  1544. """on a double-clique sur le pion"""
  1545. accepte = False
  1546. if self.pionSelectionne() == self.combattants[numCombattant] and self.modeCombat == "aucun":
  1547. ## self.pionSaisir(numCombattant)
  1548. self.majModeCombat("combatDeplacement")
  1549. accepte = True
  1550. return accepte
  1551. def pionCreer(self, coordCase):
  1552. """creer un jeton aux coordonnees indiquees"""
  1553. valide = True
  1554. self.proj.majCoord(coordCase)
  1555. if self.proj.projectionValide():
  1556. numero = 1
  1557. if len(self.combattants) > 0:
  1558. numero = max(self.combattants) + 1
  1559. combattant = self.modeParam["creature"]
  1560. numComplementaire = self.numeroterNom(combattant.nom)
  1561. combattant.numero = numero
  1562. combattant.position = self.proj.coord()
  1563. combattant.numComplementaire = numComplementaire
  1564. combattant.nbRotations = self.proj.nbRotations()
  1565. combattant.ajouterAuPlateau(self)
  1566. self.combattants[numero] = combattant
  1567. self.pionDeplacerDansOrdreJeu(numero, len(self.ordreJeu) + 2)
  1568. def numeroterNom(self, nom):
  1569. """renvoie le nom du pion avec un numero complementaire si necessaire """
  1570. i = 1
  1571. for numCombattant in self.combattants:
  1572. if self.combattants[numCombattant].nom == nom:
  1573. i += 1
  1574. if i == 1:
  1575. retour = ""
  1576. else:
  1577. retour = str(i)
  1578. return retour
  1579. def pionSaisir(self, numCombattant):
  1580. """on saisit un pion"""
  1581. if numCombattant != self.modeParam["numPionSelectionne"]:
  1582. self.majMode("pionSelectionne", numCombattant)
  1583. def pionDeposer(self, coordCase):
  1584. """on depose le pion sur la case voulue"""
  1585. if self.pionSelectionne() != None:
  1586. pion = self.pionSelectionne()
  1587. else:
  1588. pion = self.pionDecorSelectionne()
  1589. if pion != None:
  1590. if self.proj.deplacementValide():
  1591. if self.modePrincipal == "combat":
  1592. self.majInfosPion()
  1593. pion.majPosition(self.proj.coord(), self.proj.nbRotations())
  1594. self.majModeCombat("aucun")
  1595. else:
  1596. print("Deplacement impossible!")
  1597. def afficherChampDeplacement(self, actif):
  1598. """cree et affiche ou efface et detruit le champ de deplacement du pion selectionne"""
  1599. if self.pionSelectionne() != None:
  1600. if actif:
  1601. self.pionSelectionne().champDeplacement = self.zone(self.pionSelectionne().position, \
  1602. self.pionSelectionne().deplacementRestant, \
  1603. True)
  1604. for coord in self.pionSelectionne().champDeplacement:
  1605. self.cases[coord].majEstDansChampDeplacement(actif)
  1606. if not actif:
  1607. self.pionSelectionne().champDeplacement = {}
  1608. def majInfosPion(self, pionSurvole=None):
  1609. """met a jour les informations d'un pion dans la zone prevue"""
  1610. if pionSurvole != None:
  1611. pion = pionSurvole
  1612. else:
  1613. if self.pionSelectionne() != None:
  1614. pion = self.pionSelectionne()
  1615. else:
  1616. pion = None
  1617. if pion != None:
  1618. self.fenetre.ui.inf_pionNom.setText(QString.fromUtf8(pion.nom))
  1619. if len(pion.img.nomFichier) > 0:
  1620. pix = QPixmap(QString.fromUtf8("img\\"+pion.img.nomFichier))
  1621. pix = pix.scaled(61, 51, Qt.KeepAspectRatio, Qt.SmoothTransformation)
  1622. self.fenetre.ui.inf_pionImage.setPixmap(pix)
  1623. self.fenetre.ui.inf_boitePion.setVisible(True)
  1624. self.fenetre.ui.inf_pionEffet.setVisible(False)
  1625. else:
  1626. self.fenetre.ui.inf_boitePion.setVisible(False)
  1627. def majZPion(self, valeur):
  1628. """met a jour l'altitude du pion selectionne"""
  1629. if self.pionSelectionne() != None:
  1630. self.pionSelectionne().majZ(valeur)
  1631. def pionDecorSurvol(self, numPionDecor):
  1632. """le pion-decor est survole par le curseur, on affiche ses informations dans la zone prevue"""
  1633. if numPionDecor in self.decors:
  1634. self.majInfosDecor(self.decors[numPionDecor])
  1635. else:
  1636. self.majInfosDecor(None)
  1637. def pionDecorSaisir(self, numPionDecor):
  1638. """on saisit un pion decor (mode creation seulement)"""
  1639. if numPionDecor != self.modeParam["numPionSelectionne"]:
  1640. self.majMode("pionDecorSelectionne", numPionDecor)
  1641. def majInfosDecor(self, pionDecor=None):
  1642. """met a jour les informations d'un pion dans la zone prevue"""
  1643. if pionDecor != None:
  1644. self.fenetre.ui.inf_decorNom.setText(QString.fromUtf8(pionDecor.decor.nom))
  1645. if len(pionDecor.decor.img["nom"]) > 0:
  1646. pix = QPixmap(QString.fromUtf8("img\\"+pionDecor.decor.img["nom"]))
  1647. pix = pix.scaled(61, 51, Qt.KeepAspectRatio, Qt.SmoothTransformation)
  1648. self.fenetre.ui.infoDecorEnCours_image.setPixmap(pix)
  1649. self.fenetre.ui.inf_boiteDecor.setVisible(True)
  1650. else:
  1651. self.fenetre.ui.inf_boiteDecor.setVisible(False)
  1652. def majProjectionAttaqueCaC(self, pionCible):
  1653. """affiche ou non la cible de l'attaque au corps a corps, selon sa validite ou non"""
  1654. if self.modeActif_old == "pionSelectionne" and self.modeCombat == "combatAttaqueCaC":
  1655. if pionCible != self.pionSelectionne():
  1656. if pionCible != None:
  1657. conditionPossible = (pionCible.position in self.modeParam["zoneAttaqueCaC"])
  1658. pionCible.estCibleAttaque(True, conditionPossible)
  1659. else:
  1660. if self.modeParam["cibleAttaqueCaC"] != None:
  1661. self.modeParam["cibleAttaqueCaC"].estCibleAttaque(False)
  1662. self.modeParam["cibleAttaqueCaC"] = pionCible
  1663. def majZoneAttaqueCaC(self, actif = True):
  1664. """affiche ou non les cases a portee du pion selectionne pour une attaque au corps-a-corps"""
  1665. for coord in self.modeParam["zoneAttaqueCaC"]:
  1666. self.cases[coord].majEstDansChampDeplacement(actif)
  1667. def pionDecorCreer(self, coordCase):
  1668. """creer un jeton aux coordonnees indiquees"""
  1669. if self.proj.deplacementValide:
  1670. numero = 10001
  1671. if len(self.decors) > 0:
  1672. numero = max(self.decors) + 10001
  1673. decor = self.modeParam["decor"]
  1674. decor.numero = numero
  1675. decor.position = self.proj.coord()
  1676. decor.nbRotations = self.proj.nbRotations()
  1677. decor.ajouterAuPlateau(self)
  1678. self.decors[numero] = decor
  1679. def pionSupprimer(self, num):
  1680. """supprime le pion entre en parametre"""
  1681. #settrace(trace_calls)
  1682. if num in self.combattants:
  1683. for coord in self.combattants[num].forme.listeCases(self.combattants[num].position, self.combattants[num].nbRotations):
  1684. self.cases[coord].majOccupation(self.combattants[num])
  1685. self.pionSurvol(None)
  1686. self.pionDeplacerDansOrdreJeu(num, 0)
  1687. pionSuppr = self.combattants.pop(num)
  1688. pionSuppr.retirerDuPlateau()
  1689. else:
  1690. print("erreur: ce pion n'est pas dans la liste des pions")
  1691. def pionDecorSupprimer(self, num):
  1692. """supprime le pion entre en parametre"""
  1693. if num in self.decors:
  1694. for coord in self.decors[num].forme.listeCases(self.decors[num].position, self.decors[num].nbRotations):
  1695. self.cases[coord].majOccupation(self.decors[num])
  1696. self.pionDecorSurvol(None)
  1697. pionDecorASuppr = self.decors.pop(num)
  1698. pionDecorASuppr.supprimer()
  1699. else:
  1700. print("ce pion n'est pas dans la liste des decors")
  1701. ###############
  1702. ######### caches ###############
  1703. def voirCacheEnCours(self):
  1704. """centre la vue sur et met en evidence le cache actif"""
  1705. if len(self.caches[self.cacheEnCours]["listeCases"]) > 0:
  1706. #centre la vue sur le premier point du polygone d'une case du milieu de la liste
  1707. indiceMilieu = int((len(self.caches[self.cacheEnCours]["listeCases"])/2))
  1708. self.fenetre.ui.cbt_vue.centerOn(self.cases[self.caches[self.cacheEnCours]["listeCases"][indiceMilieu]].polygon()[0])
  1709. #mettre en surbrillance
  1710. #for coord in self.caches[self.cacheEnCours]["listeCases"]:
  1711. # self.
  1712. def placerCacheEnCours(self):
  1713. """active le mode de mise a jour de la liste des cases cachees par ce cache"""
  1714. self.majMode("cachePlacer")
  1715. self.fenetre.ui.cacheActif.setChecked(True)
  1716. self.majEtatCacheEnCours()
  1717. def majEtatCacheEnCours(self):
  1718. """met a jour l'etat (actif ou non) du cache selon l'etat de la case correspondante"""
  1719. self.caches[self.cacheEnCours]["actif"] = self.fenetre.ui.cacheActif.isChecked()
  1720. self.majAffichageCache(self.cacheEnCours, self.caches[self.cacheEnCours]["actif"])
  1721. def majAffichageCache(self, numCache, afficher = True):
  1722. """met a jour l'affichage des cases selon les parametres enregistres pour le cache"""
  1723. if self.polygonesCaches[numCache] == None:
  1724. self.polygonesCaches[numCache] = Cache(self, numCache)
  1725. self.polygonesCaches[numCache].afficher(afficher, self.pinceau.selection())
  1726. ###############"
  1727. ######### gestion des evenements souris et clavier ###############
  1728. def wheelEvent(self, event):
  1729. """zoom/dezoom avec la molette de la souris"""
  1730. #on zoom/dezoom et on recentre sur la position du curseur
  1731. #super (Plateau, self).wheelEvent(event)
  1732. zoom = 1.00
  1733. if event.delta() > 0:
  1734. if self.nbZoomActuel <= 10:
  1735. self.nbZoomActuel += 1
  1736. zoom = 1.25
  1737. elif event.delta() < 0:
  1738. if self.nbZoomActuel >= -10:
  1739. zoom = 0.8
  1740. self.nbZoomActuel -= 1
  1741. if zoom != 0.00:
  1742. self.fenetre.ui.cbt_vue.scale(zoom, zoom)
  1743. self.fenetre.ui.cbt_vue.centerOn(event.scenePos())
  1744. event.accept() #pour considerer l'evenement comme resolu, sans ca les barres de defilement reagissent aussi
  1745. def mouseMoveEvent(self, event):
  1746. super(Plateau, self).mouseMoveEvent(event)
  1747. if event.buttons() == Qt.LeftButton and self.fenetre.ui.cbt_vue.dragMode() != QGraphicsView.ScrollHandDrag:
  1748. coord = self.coordonneesAuPoint(event.scenePos())
  1749. if coord != None:
  1750. self.caseSurvolClicEnfonce(coord)
  1751. else:
  1752. self.modeActif.mouvementSouris(event)
  1753. event.ignore()
  1754. def mousePressEvent(self, event):
  1755. super(Plateau, self).mousePressEvent(event)
  1756. if event.button() == 1:
  1757. self.modeActif.clicGauche(event)
  1758. if event.button() == 1 and self.fenetre.ui.cbt_vue.dragMode() != QGraphicsView.ScrollHandDrag:
  1759. if self.modeActif_old == "pionSupprimer":
  1760. for item in self.items(event.scenePos()):
  1761. if item.__class__.__name__ == "PionDecor":
  1762. self.pionDecorSupprimer(item.numero)
  1763. break
  1764. elif item.parentItem().__class__.__name__ == "Pion":
  1765. self.pionSupprimer(item.parentItem().numero)
  1766. break
  1767. else:
  1768. ## if not event.isAccepted():
  1769. ## self.caseCliquee(self.coordonneesAuPoint(event.scenePos()))
  1770. event.ignore()
  1771. elif event.button() == 2:
  1772. if self.pionSelectionne() != None and self.modeCombat != "" and self.modeCombat != "aucun":
  1773. self.majModeCombat("aucun")
  1774. else:
  1775. self.majMode("standard")
  1776. self.activerMode(Modes.Standard)
  1777. event.accept()
  1778. #event.ignore()
  1779. def mouseReleaseEvent(self, event):
  1780. super(Plateau, self).mouseReleaseEvent(event)
  1781. self.modeActif.finClicGauche(event)
  1782. def keyPressEvent(self, event):
  1783. """gestion des evenements clavier"""
  1784. toucheClavier = event.key()
  1785. self.modeActif.toucheClavier(event)
  1786. if self.modeActif_old == "pionCreation" or self.modeActif_old == "pionSelectionne" or self.modeActif_old == "pionDecorSelectionne" or self.modeActif_old == "pionDecorCreation":
  1787. #pivots de la projection du deplacement
  1788. if toucheClavier == Qt.Key_Right:
  1789. self.proj.majRotation(1)
  1790. event.accept()
  1791. elif toucheClavier == Qt.Key_Left:
  1792. self.proj.majRotation(-1)
  1793. event.accept()
  1794. if toucheClavier == Qt.Key_Delete:
  1795. if self.pionSelectionne() != None:
  1796. num = self.pionSelectionne().numero
  1797. if self.modeActif_old == "pionSelectionne":
  1798. self.pionSupprimer(num)
  1799. elif self.modeActif_old == "pionDecorSelectionne":
  1800. self.pionDecorSupprimer(num)
  1801. self.majMode("standard")
  1802. ################