Plateau.py 125 KB

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