Plateau.py 64 KB

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