Plateau.py 69 KB

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